Merge pull request #86 from abiggerhammer/php-bindings

Php bindings
This commit is contained in:
TQ Hirsch 2013-12-22 09:45:41 -08:00
commit 1d693e4f16
47 changed files with 1447 additions and 7 deletions

View file

@ -38,12 +38,31 @@ matrix:
language: perl
perl: "5.10"
env: BINDINGS=perl CC=clang
- compiler: gcc
language: php
php: "5.5"
env: BINDINGS=php
- compiler: clang
language: php
php: "5.5"
env: BINDINGS=php CC=clang
- compiler: gcc
language: php
php: "5.4"
env: BINDINGS=php
- compiler: clang
language: php
php: "5.4"
env: BINDINGS=php CC=clang
before_install:
- sudo apt-get update -qq
- if [ "$BINDINGS" != "none" ]; then sudo add-apt-repository ppa:dns/irc -y; sudo apt-get update -qq; sudo apt-get install -qq swig=2.0.8-1irc1~12.04; swig -version; fi
- if [ "$BINDINGS" != "none" ]; then sudo apt-get install -qq swig; fi
- if [ "$BINDINGS" == "perl" ]; then sudo add-apt-repository ppa:dns/irc -y; sudo apt-get update -qq; sudo apt-get install -qq swig=2.0.8-1irc1~12.04; fi
- if [ "$BINDINGS" == "python" ]; then sudo apt-get install -qq python-dev; fi
install: true
before_script:
- if [ "$BINDINGS" == "php" ]; then phpenv config-add src/bindings/php/hammer.ini; fi
script:
- scons bindings=$BINDINGS test
notifications:

View file

@ -7,7 +7,7 @@ import sys
vars = Variables(None, ARGUMENTS)
vars.Add(PathVariable('DESTDIR', "Root directory to install in (useful for packaging scripts)", None, PathVariable.PathIsDirCreate))
vars.Add(PathVariable('prefix', "Where to install in the FHS", "/usr/local", PathVariable.PathAccept))
vars.Add(ListVariable('bindings', 'Language bindings to build', 'none', ['python', 'perl']))
vars.Add(ListVariable('bindings', 'Language bindings to build', 'none', ['python', 'perl', 'php']))
env = Environment(ENV = {'PATH' : os.environ['PATH']}, variables = vars, tools=['default', 'scanreplace'], toolpath=['tools'])
@ -69,7 +69,7 @@ dbg = env.Clone(VARIANT='debug')
dbg.Append(CCFLAGS=['-g'])
opt = env.Clone(VARIANT='opt')
opt.Append(CCFLAGS="-O3")
opt.Append(CCFLAGS=["-O3"])
if GetOption("variant") == 'debug':
env = dbg
@ -95,6 +95,7 @@ env["ENV"].update(x for x in os.environ.items() if x[0].startswith("CCC_"))
#env.Append(CPPPATH=os.path.join('#', "hammer"))
testruns = []
targets = ["$libpath",
"$incpath",
"$parsersincpath",

View file

@ -3,7 +3,8 @@ Import('env')
example = env.Clone()
example.Append(LIBS="hammer", LIBPATH="../src")
example.Program('dns', ['dns.c', 'rr.c', 'dns_common.c'])
example.Program('base64', 'base64.c')
example.Program('base64_sem1', 'base64_sem1.c')
example.Program('base64_sem2', 'base64_sem2.c')
dns = example.Program('dns', ['dns.c', 'rr.c', 'dns_common.c'])
base64 = example.Program('base64', 'base64.c')
base64_sem1 = example.Program('base64_sem1', 'base64_sem1.c')
base64_sem2 = example.Program('base64_sem2', 'base64_sem2.c')
env.Alias("examples", [dns, base64, base64_sem1, base64_sem2])

View file

@ -0,0 +1,18 @@
Building
========
Requirements:
* SWIG 2.0
* A properly configured [phpenv](https://github.com/CHH/phpenv)
SCons finds your PHP include path from `php-config`, so if you don't have that working, you're going to have a bad time.
If you want to run the tests, you will also need to install PHPUnit. Do this with pyrus and save yourself some hell.
pyrus channel-discover pear.phpunit.de
pyrus channel-discover pear.symfony.com
pyrus channel-discover pear.symfony-project.com
pyrus install --optionaldeps phpunit/PHPUnit
Installing
==========
We're not building a proper package yet, but you can copy `build/$VARIANT/src/bindings/php/hammer.so` to your PHP extension directory (`scons test` will do this for you if you're using phpenv; for a system-wide php you'll probably have to use sudo) and add "extension=hammer.so" to your php.ini. There is a "hammer.ini" in src/bindings/php for your convenience; you can put it in the `conf.d` directory where PHP expects to find its configuration. `scons test` will do this for you too. You'll also need to point your include_path to the location of hammer.php, which will be `build/$VARIANT/src/bindings/php/hammer.php` until you put it somewhere else.

View file

@ -0,0 +1,31 @@
# -*- python -*-
import os, os.path
Import('env libhammer_shared testruns')
phpenv = env.Clone(IMPLICIT_COMMAND_DEPENDENCIES = 0)
php_include = os.popen("php-config --include-dir").read().rstrip()
phpenv.Append(CPPPATH = ['../../', php_include, os.path.join(php_include, 'main'), os.path.join(php_include, 'Zend'), os.path.join(php_include, 'TSRM')])
phpenv.Append(CCFLAGS = ['-fpic', '-DSWIG', '-Wno-all', '-Wno-extra', '-Wno-error'])
phpenv.Append(LIBS = ['hammer'])
phpenv.Append(LIBPATH = ['../../'])
swig = ['hammer.i']
bindings_src = phpenv.Command(['hammer.php', 'hammer_wrap.c', 'php_hammer.h'], swig, 'swig -php -DHAMMER_INTERNAL__NO_STDARG_H -Isrc/ $SOURCE')
libhammer_php = phpenv.SharedLibrary('hammer', ['hammer_wrap.c'])
Default(swig, bindings_src, libhammer_php)
phptestenv = phpenv.Clone()
phptestenv['ENV']['LD_LIBRARY_PATH'] = os.path.dirname(str(libhammer_shared[0]))
phptests = ('Tests')
phpextprefix = os.popen("php-config --extension-dir").read().rstrip()
phplib = phptestenv.Command(os.path.join(phpextprefix, "hammer.so"), libhammer_php, Copy("$TARGET", "$SOURCE"))
AlwaysBuild(phplib)
phpprefix = os.popen("php-config --prefix").read().rstrip()
phpincl = phptestenv.Command(os.path.join(os.path.join(phpprefix, "etc/conf.d"), "hammer.ini"), "hammer.ini", Copy("$TARGET", "$SOURCE"))
phptestexec = phptestenv.Command(phptests, [phplib, phpincl], "phpenv exec phpunit --include-path " + os.path.dirname(libhammer_php[0].path) +" src/bindings/php/Tests")
phptest = Alias("testphp", [phptestexec], phptestexec)
AlwaysBuild(phptest)
testruns.append(phptest)

View file

@ -0,0 +1,40 @@
<?php
include_once 'hammer.php';
function actTest($token)
{
if (is_array($token) === true) {
foreach($token as $chr) {
$ret[] = strtoupper($chr);
}
return $ret;
} else {
return strtoupper($token);
}
}
class ActionTest extends PHPUnit_Framework_TestCase
{
protected $parser;
protected function setUp()
{
$this->parser = hammer_action(hammer_sequence(hammer_choice(hammer_ch("a"), hammer_ch("A")), hammer_choice(hammer_ch("b"), hammer_ch("B"))), "actTest");
}
public function testSuccess()
{
$result1 = hammer_parse($this->parser, "ab");
$result2 = hammer_parse($this->parser, "AB");
$result3 = hammer_parse($this->parser, "aB");
$this->assertEquals(["A", "B"], $result1);
$this->assertEquals(["A", "B"], $result2);
$this->assertEquals(["A", "B"], $result3);
}
public function testFailure()
{
$result = hammer_parse($this->parser, "XX");
$this->assertEquals(NULL, $result);
}
}
?>

View file

@ -0,0 +1,35 @@
<?php
include_once 'hammer.php';
class AndTest extends PHPUnit_Framework_TestCase
{
protected $parser1;
protected $parser2;
protected $parser3;
protected function setUp()
{
$this->parser1 = hammer_sequence(hammer_and(hammer_ch("0")), hammer_ch("0"));
$this->parser2 = hammer_sequence(hammer_and(hammer_ch("0")), hammer_ch("1"));
$this->parser3 = hammer_sequence(hammer_ch("1"), hammer_and(hammer_ch("2")));
}
public function testSuccess1()
{
$result = hammer_parse($this->parser1, "0");
$this->assertEquals(array("0"), $result);
}
public function testFailure2()
{
$result = hammer_parse($this->parser2, "0");
$this->assertEquals(NULL, $result);
}
public function testSuccess3()
{
$result = hammer_parse($this->parser3, "12");
$this->assertEquals(array("1"), $result);
}
}
?>

View file

@ -0,0 +1,35 @@
<?php
include_once 'hammer.php';
class ButNotTest extends PHPUnit_Framework_TestCase
{
protected $parser1;
protected $parser2;
protected function setUp()
{
$this->parser1 = hammer_butnot(hammer_ch("a"), hammer_token("ab"));
$this->parser2 = hammer_butnot(hammer_ch_range('0', '9'), hammer_ch('6'));
}
public function testSuccess1()
{
$result1 = hammer_parse($this->parser1, "a");
$result2 = hammer_parse($this->parser1, "aa");
$this->assertEquals("a", $result1);
$this->assertEquals("a", $result1);
}
public function testFailure1()
{
$result = hammer_parse($this->parser1, "ab");
$this->assertEquals(NULL, $result);
}
public function testFailure2()
{
$result = hammer_parse($this->parser2, "6");
$this->assertEquals(NULL, $result);
}
}
?>

View file

@ -0,0 +1,24 @@
<?php
include_once 'hammer.php';
class ChRangeTest extends PHPUnit_Framework_TestCase
{
protected $parser;
protected function setUp()
{
$this->parser = hammer_ch_range("a", "c");
}
public function testSuccess()
{
$result = hammer_parse($this->parser, "b");
$this->assertEquals("b", $result);
}
public function testFailure()
{
$result = hammer_parse($this->parser, "d");
$this->assertEquals(NULL, $result);
}
}
?>

View file

@ -0,0 +1,24 @@
<?php
include_once 'hammer.php';
class ChTest extends PHPUnit_Framework_TestCase
{
protected $parser;
protected function setUp()
{
$this->parser = hammer_ch("\xa2");
}
public function testSuccess()
{
$result = hammer_parse($this->parser, "\xa2");
$this->assertEquals("\xa2", $result);
}
public function testFailure()
{
$result = hammer_parse($this->parser, "95");
$this->assertEquals(NULL, $result);
}
}
?>

View file

@ -0,0 +1,27 @@
<?php
include_once 'hammer.php';
class ChoiceTest extends PHPUnit_Framework_TestCase
{
protected $parser;
protected function setUp()
{
$this->parser = hammer_choice(hammer_ch("a"), hammer_ch("b"));
}
public function testSuccess()
{
$result1 = hammer_parse($this->parser, "a");
$result2 = hammer_parse($this->parser, "b");
$this->assertEquals("a", $result1);
$this->assertEquals("b", $result2);
}
public function testFailure()
{
$result = hammer_parse($this->parser, "c");
$this->assertEquals(NULL, $result);
}
}
?>

View file

@ -0,0 +1,25 @@
<?php
include_once 'hammer.php';
class DifferenceTest extends PHPUnit_Framework_TestCase
{
protected $parser;
protected function setUp()
{
$this->parser = hammer_difference(hammer_token("ab"), hammer_ch("a"));
}
public function testSuccess()
{
$result = hammer_parse($this->parser, "ab");
$this->assertEquals("ab", $result);
}
public function testFailure()
{
$result = hammer_parse($this->parser, "a");
$this->assertEquals(NULL, $result);
}
}
?>

View file

@ -0,0 +1,24 @@
<?php
include_once 'hammer.php';
class EndPTest extends PHPUnit_Framework_TestCase
{
protected $parser;
protected function setUp()
{
$this->parser = hammer_sequence(hammer_ch("a"), hammer_end());
}
public function testSuccess()
{
$result = hammer_parse($this->parser, "a");
$this->assertEquals(array("a"), $result);
}
public function testFailure()
{
$result = hammer_parse($this->parser, "aa");
$this->assertEquals(NULL, $result);
}
}
?>

View file

@ -0,0 +1,35 @@
<?php
include_once 'hammer.php';
class EpsilonPTest extends PHPUnit_Framework_TestCase
{
protected $parser1;
protected $parser2;
protected $parser3;
protected function setUp()
{
$this->parser1 = hammer_sequence(hammer_ch("a"), hammer_epsilon(), hammer_ch("b"));
$this->parser2 = hammer_sequence(hammer_epsilon(), hammer_ch("a"));
$this->parser3 = hammer_sequence(hammer_ch("a"), hammer_epsilon());
}
public function testSuccess1()
{
$result = hammer_parse($this->parser1, "ab");
$this->assertEquals(array("a", "b"), $result);
}
public function testSuccess2()
{
$result = hammer_parse($this->parser2, "a");
$this->assertEquals(array("a"), $result);
}
public function testSuccess3()
{
$result = hammer_parse($this->parser3, "ab");
$this->assertEquals(array("a"), $result);
}
}
?>

View file

@ -0,0 +1,25 @@
<?php
include_once 'hammer.php';
class IgnoreTest extends PHPUnit_Framework_TestCase
{
protected $parser;
protected function setUp()
{
$this->parser = hammer_sequence(hammer_ch("a"), hammer_ignore(hammer_ch("b")), hammer_ch("c"));
}
public function testSuccess()
{
$result = hammer_parse($this->parser, "abc");
$this->assertEquals(array("a", "c"), $result);
}
public function testFailure()
{
$result = hammer_parse($this->parser, "ac");
$this->assertEquals(NULL, $result);
}
}
?>

View file

@ -0,0 +1,23 @@
<?php
include_once 'hammer.php';
class InTest extends PHPUnit_Framework_TestCase
{
protected $parser;
protected function setUp()
{
$this->parser = hammer_in("abc");
}
public function testSuccess()
{
$result = hammer_parse($this->parser, "b");
$this->assertEquals("b", $result);
}
public function testFailure()
{
$result = hammer_parse($this->parser, "d");
$this->assertEquals(NULL, $result);
}
}
?>

View file

@ -0,0 +1,30 @@
<?php
include_once 'hammer.php';
class Int16Test extends PHPUnit_Framework_TestCase
{
protected $parser;
protected function setUp()
{
$this->parser = hammer_int16();
}
public function testNegative()
{
$result = hammer_parse($this->parser, "\xfe\x00");
$this->assertEquals(-0x200, $result);
}
public function testPositive() {
$result = hammer_parse($this->parser, "\x02\x00");
$this->assertEquals(0x200, $result);
}
public function testFailure()
{
$result = hammer_parse($this->parser, "\xfe");
$this->assertEquals(NULL, $result);
$result = hammer_parse($this->parser, "\x02");
$this->assertEquals(NULL, $result);
}
}
?>

View file

@ -0,0 +1,31 @@
<?php
include_once 'hammer.php';
class Int32Test extends PHPUnit_Framework_TestCase
{
protected $parser;
protected function setUp()
{
$this->parser = hammer_int32();
}
public function testNegative()
{
$result = hammer_parse($this->parser, "\xff\xfe\x00\x00");
$this->assertEquals(-0x20000, $result);
}
public function testPositive()
{
$result = hammer_parse($this->parser, "\x00\x02\x00\x00");
$this->assertEquals(0x20000, $result);
}
public function testFailure()
{
$result = hammer_parse($this->parser, "\xff\xfe\x00");
$this->assertEquals(NULL, $result);
$result = hammer_parse($this->parser, "\x00\x02\x00");
$this->assertEquals(NULL, $result);
}
}
?>

View file

@ -0,0 +1,24 @@
<?php
include_once 'hammer.php';
class Int64Test extends PHPUnit_Framework_TestCase
{
protected $parser;
protected function setUp()
{
$this->parser = hammer_int64();
}
public function testSuccess()
{
$result = hammer_parse($this->parser, "\xff\xff\xff\xfe\x00\x00\x00\x00");
$this->assertEquals(-0x200000000, $result);
}
public function testFailure()
{
$result = hammer_parse($this->parser, "\xff\xff\xff\xfe\x00\x00\x00");
$this->assertEquals(NULL, $result);
}
}
?>

View file

@ -0,0 +1,24 @@
<?php
include_once 'hammer.php';
class Int8Test extends PHPUnit_Framework_TestCase
{
protected $parser;
protected function setUp()
{
$this->parser = hammer_int8();
}
public function testSuccess()
{
$result = hammer_parse($this->parser, "\x88");
$this->assertEquals(-0x78, $result);
}
public function testFailure()
{
$result = hammer_parse($this->parser, "");
$this->assertEquals(NULL, $result);
}
}
?>

View file

@ -0,0 +1,23 @@
<?php
include_once 'hammer.php';
class IntRangeTest extends PHPUnit_Framework_TestCase
{
protected $parser;
protected function setUp()
{
$this->parser = hammer_int_range(hammer_uint8(), 3, 10);
}
public function testSuccess()
{
$result = hammer_parse($this->parser, "\x05");
$this->assertEquals(5, $result);
}
public function testFailure()
{
$result = hammer_parse($this->parser, "\xb");
$this->assertEquals(NULL, $result);
}
}
?>

View file

@ -0,0 +1,27 @@
<?php
include_once 'hammer.php';
class LeftTest extends PHPUnit_Framework_TestCase
{
protected $parser;
protected function setUp()
{
$this->parser = hammer_left(hammer_ch("a"), hammer_ch(" "));
}
public function testSuccess()
{
$result = hammer_parse($this->parser, "a ");
$this->assertEquals("a", $result);
}
public function testFailure()
{
$result1 = hammer_parse($this->parser, "a");
$result2 = hammer_parse($this->parser, " ");
$result3 = hammer_parse($this->parser, "ab");
$this->assertEquals(NULL, $result1);
$this->assertEquals(NULL, $result2);
$this->assertEquals(NULL, $result3);
}
}
?>

View file

@ -0,0 +1,36 @@
<?php
include_once 'hammer.php';
class LeftrecTest extends PHPUnit_Framework_TestCase
{
protected $parser;
protected function setUp()
{
$this->parser = hammer_indirect();
hammer_bind_indirect($this->parser, hammer_choice(hammer_sequence($this->parser, hammer_ch("a")), hammer_ch("a")));
}
public function testSuccess1()
{
$result = hammer_parse($this->parser, "a");
$this->assertEquals("a", $result);
}
/* These don't work in the underlying C so they won't work here either */
/*
public function testSuccess2()
{
$result = hammer_parse($this->parser, "aa");
var_dump($result);
$this->assertEquals(array("a", "a"), $result);
}
public function testSuccess3()
{
$result = hammer_parse($this->parser, "aaa");
var_dump($result);
$this->assertEquals(array(array("a", "a"), "a"), $result);
}
*/
}
?>

View file

@ -0,0 +1,31 @@
<?php
include_once 'hammer.php';
class Many1Test extends PHPUnit_Framework_TestCase
{
protected $parser;
protected function setUp()
{
$this->parser = hammer_many1(hammer_choice(hammer_ch("a"), hammer_ch("b")));
}
public function testSuccess()
{
$result1 = hammer_parse($this->parser, "a");
$result2 = hammer_parse($this->parser, "b");
$result3 = hammer_parse($this->parser, "aabbaba");
$this->assertEquals(array("a"), $result1);
$this->assertEquals(array("b"), $result2);
$this->assertEquals(array("a", "a", "b", "b", "a", "b", "a"), $result3);
}
public function testFailure()
{
$result1 = hammer_parse($this->parser, "");
$result2 = hammer_parse($this->parser, "daabbabadef");
$this->assertEquals(NULL, $result1);
$this->assertEquals(NULL, $result2);
}
}
?>

View file

@ -0,0 +1,25 @@
<?php
include_once 'hammer.php';
class ManyTest extends PHPUnit_Framework_TestCase
{
protected $parser;
protected function setUp()
{
$this->parser = hammer_many(hammer_choice(hammer_ch("a"), hammer_ch("b")));
}
public function testSuccess()
{
$result1 = hammer_parse($this->parser, "");
$result2 = hammer_parse($this->parser, "a");
$result3 = hammer_parse($this->parser, "b");
$result4 = hammer_parse($this->parser, "aabbaba");
$this->assertEquals(array(), $result1);
$this->assertEquals(array("a"), $result2);
$this->assertEquals(array("b"), $result3);
$this->assertEquals(array("a", "a", "b", "b", "a", "b", "a"), $result4);
}
}
?>

View file

@ -0,0 +1,35 @@
<?php
include_once 'hammer.php';
class MiddleTest extends PHPUnit_Framework_TestCase
{
protected $parser;
protected function setUp()
{
$this->parser = hammer_middle(hammer_ch(" "), hammer_ch("a"), hammer_ch(" "));
}
public function testSuccess()
{
$result = hammer_parse($this->parser, " a ");
$this->assertEquals("a", $result);
}
public function testFailure()
{
$result1 = hammer_parse($this->parser, "a");
$result2 = hammer_parse($this->parser, " ");
$result3 = hammer_parse($this->parser, " a");
$result4 = hammer_parse($this->parser, "a ");
$result5 = hammer_parse($this->parser, " b ");
$result6 = hammer_parse($this->parser, "ba ");
$result7 = hammer_parse($this->parser, " ab");
$this->assertEquals(NULL, $result1);
$this->assertEquals(NULL, $result2);
$this->assertEquals(NULL, $result3);
$this->assertEquals(NULL, $result4);
$this->assertEquals(NULL, $result5);
$this->assertEquals(NULL, $result6);
$this->assertEquals(NULL, $result7);
}
}
?>

View file

@ -0,0 +1,23 @@
<?php
include_once 'hammer.php';
class NotInTest extends PHPUnit_Framework_TestCase
{
protected $parser;
protected function setUp()
{
$this->parser = hammer_not_in("abc");
}
public function testSuccess()
{
$result = hammer_parse($this->parser, "d");
$this->assertEquals("d", $result);
}
public function testFailure()
{
$result = hammer_parse($this->parser, "b");
$this->assertEquals(NULL, $result);
}
}
?>

View file

@ -0,0 +1,35 @@
<?php
include_once 'hammer.php';
class NotTest extends PHPUnit_Framework_TestCase
{
protected $parser1;
protected $parser2;
protected function setUp()
{
$this->parser1 = hammer_sequence(hammer_ch("a"), hammer_choice(hammer_ch("+"), hammer_token("++")), hammer_ch("b"));
$this->parser2 = hammer_sequence(hammer_ch("a"), hammer_choice(hammer_sequence(hammer_ch("+"), hammer_not(hammer_ch("+"))), hammer_token("++")), hammer_ch("b"));
}
public function testSuccess1()
{
$result = hammer_parse($this->parser1, "a+b");
$this->assertEquals(array("a", "+", "b"), $result);
}
public function testFailure1()
{
$result = hammer_parse($this->parser1, "a++b");
$this->assertEquals(NULL, $result);
}
public function testSuccess2()
{
$result1 = hammer_parse($this->parser2, "a+b");
$result2 = hammer_parse($this->parser2, "a++b");
$this->assertEquals(array("a", array("+"), "b"), $result1);
$this->assertEquals(array("a", "++", "b"), $result2);
}
}
?>

View file

@ -0,0 +1,19 @@
<?php
include_once 'hammer.php';
class NothingPTest extends PHPUnit_Framework_TestCase
{
protected $parser;
protected function setUp()
{
$this->parser = hammer_nothing();
}
public function testFailure()
{
$result = hammer_parse($this->parser, "a");
$this->assertEquals(NULL, $result);
}
}
?>

View file

@ -0,0 +1,33 @@
<?php
include_once 'hammer.php';
class OptionalTest extends PHPUnit_Framework_TestCase
{
protected $parser;
protected function setUp()
{
$this->parser = hammer_sequence(hammer_ch("a"), hammer_optional(hammer_choice(hammer_ch("b"), hammer_ch("c"))), hammer_ch("d"));
}
public function testSuccess()
{
$result1 = hammer_parse($this->parser, "abd");
$result2 = hammer_parse($this->parser, "acd");
$result3 = hammer_parse($this->parser, "ad");
$this->assertEquals(array("a", "b", "d"), $result1);
$this->assertEquals(array("a", "c", "d"), $result2);
$this->assertEquals(array("a", NULL, "d"), $result3);
}
public function testFailure()
{
$result1 = hammer_parse($this->parser, "aed");
$result2 = hammer_parse($this->parser, "ab");
$result3 = hammer_parse($this->parser, "ac");
$this->assertEquals(NULL, $result1);
$this->assertEquals(NULL, $result2);
$this->assertEquals(NULL, $result3);
}
}
?>

View file

@ -0,0 +1,31 @@
<?php
include_once 'hammer.php';
function predTest($token)
{
return ($token[0] === $token[1]);
}
class PredicateTest extends PHPUnit_Framework_TestCase
{
protected $parser;
protected function setUp()
{
$this->parser = hammer_predicate(hammer_many1(hammer_choice(hammer_ch('a'), hammer_ch('b'))), "predTest");
}
public function testSuccess()
{
$result1 = hammer_parse($this->parser, "aa");
$result2 = hammer_parse($this->parser, "bb");
$this->assertEquals(["a", "a"], $result1);
$this->assertEquals(["b", "b"], $result2);
}
public function testFailure()
{
$result = hammer_parse($this->parser, "ab");
$this->assertEquals(NULL, $result);
}
}
?>

View file

@ -0,0 +1,27 @@
<?php
include_once 'hammer.php';
class RepeatNTest extends PHPUnit_Framework_TestCase
{
protected $parser;
protected function setUp()
{
$this->parser = hammer_repeat_n(hammer_choice(hammer_ch("a"), hammer_ch("b")), 2);
}
public function testSuccess()
{
$result = hammer_parse($this->parser, "abdef");
$this->assertEquals(array("a", "b"), $result);
}
public function testFailure()
{
$result1 = hammer_parse($this->parser, "adef");
$result2 = hammer_parse($this->parser, "dabdef");
$this->assertEquals(NULL, $result1);
$this->assertEquals(NULL, $result2);
}
}
?>

View file

@ -0,0 +1,27 @@
<?php
include_once 'hammer.php';
class RightTest extends PHPUnit_Framework_TestCase
{
protected $parser;
protected function setUp()
{
$this->parser = hammer_right(hammer_ch(" "), hammer_ch("a"));
}
public function testSuccess()
{
$result = hammer_parse($this->parser, " a");
$this->assertEquals("a", $result);
}
public function testFailure()
{
$result1 = hammer_parse($this->parser, "a");
$result2 = hammer_parse($this->parser, " ");
$result3 = hammer_parse($this->parser, "ba");
$this->assertEquals(NULL, $result1);
$this->assertEquals(NULL, $result2);
$this->assertEquals(NULL, $result3);
}
}
?>

View file

@ -0,0 +1,24 @@
<?php
include_once 'hammer.php';
class RightrecTest extends PHPUnit_Framework_TestCase
{
protected $parser;
protected function setUp()
{
$this->parser = hammer_indirect();
hammer_bind_indirect($this->parser, hammer_choice(hammer_sequence(hammer_ch("a"), $this->parser), hammer_epsilon()));
}
public function testSuccess()
{
$result1 = hammer_parse($this->parser, "a");
$result2 = hammer_parse($this->parser, "aa");
$result3 = hammer_parse($this->parser, "aaa");
$this->assertEquals(array("a"), $result1);
$this->assertEquals(array("a", array("a")), $result2);
$this->assertEquals(array("a", array("a", array("a"))), $result3);
}
}
?>

View file

@ -0,0 +1,31 @@
<?php
include_once 'hammer.php';
class SepBy1Test extends PHPUnit_Framework_TestCase
{
protected $parser;
protected function setUp()
{
$this->parser = hammer_sep_by1(hammer_choice(hammer_ch("1"), hammer_ch("2"), hammer_ch("3")), hammer_ch(","));
}
public function testSuccess()
{
$result1 = hammer_parse($this->parser, "1,2,3");
$result2 = hammer_parse($this->parser, "1,3,2");
$result3 = hammer_parse($this->parser, "1,3");
$result4 = hammer_parse($this->parser, "3");
$this->assertEquals(array("1", "2", "3"), $result1);
$this->assertEquals(array("1", "3", "2"), $result2);
$this->assertEquals(array("1", "3"), $result3);
$this->assertEquals(array("3"), $result4);
}
public function testFailure()
{
$result = hammer_parse($this->parser, "");
$this->assertEquals(NULL, $result);
}
}
?>

View file

@ -0,0 +1,27 @@
<?php
include_once 'hammer.php';
class SepByTest extends PHPUnit_Framework_TestCase
{
protected $parser;
protected function setUp()
{
$this->parser = hammer_sep_by(hammer_choice(hammer_ch("1"), hammer_ch("2"), hammer_ch("3")), hammer_ch(","));
}
public function testSuccess()
{
$result1 = hammer_parse($this->parser, "1,2,3");
$result2 = hammer_parse($this->parser, "1,3,2");
$result3 = hammer_parse($this->parser, "1,3");
$result4 = hammer_parse($this->parser, "3");
$result5 = hammer_parse($this->parser, "");
$this->assertEquals(array("1", "2", "3"), $result1);
$this->assertEquals(array("1", "3", "2"), $result2);
$this->assertEquals(array("1", "3"), $result3);
$this->assertEquals(array("3"), $result4);
$this->assertEquals(array(), $result5);
}
}
?>

View file

@ -0,0 +1,39 @@
<?php
include_once 'hammer.php';
class SequenceTest extends PHPUnit_Framework_TestCase
{
protected $parser1;
protected $parser2;
protected function setUp()
{
$this->parser1 = hammer_sequence(hammer_ch("a"), hammer_ch("b"));
$this->parser2 = hammer_sequence(hammer_ch("a"), hammer_whitespace(hammer_ch("b")));
}
public function testSuccess1()
{
$result = hammer_parse($this->parser1, "ab");
$this->assertEquals(array("a", "b"), $result);
}
public function testFailure1()
{
$result1 = hammer_parse($this->parser1, "a");
$result2 = hammer_parse($this->parser2, "b");
$this->assertEquals(NULL, $result1);
$this->assertEquals(NULL, $result2);
}
public function testSuccess2()
{
$result1 = hammer_parse($this->parser2, "ab");
$result2 = hammer_parse($this->parser2, "a b");
$result3 = hammer_parse($this->parser2, "a b");
$this->assertEquals(array("a", "b"), $result1);
$this->assertEquals(array("a", "b"), $result2);
$this->assertEquals(array("a", "b"), $result3);
}
}
?>

View file

@ -0,0 +1,24 @@
<?php
include_once 'hammer.php';
class TokenTest extends PHPUnit_Framework_TestCase
{
protected $parser;
protected function setUp()
{
$this->parser = hammer_token("95\xa2");
}
public function testSuccess()
{
$result = hammer_parse($this->parser, "95\xa2");
$this->assertEquals("95\xa2", $result);
}
public function testFailure()
{
$result = hammer_parse($this->parser, "95");
$this->assertEquals(NULL, $result);
}
}
?>

View file

@ -0,0 +1,24 @@
<?php
include_once 'hammer.php';
class Uint16Test extends PHPUnit_Framework_TestCase
{
protected $parser;
protected function setUp()
{
$this->parser = hammer_uint16();
}
public function testSuccess()
{
$result = hammer_parse($this->parser, "\x02\x00");
$this->assertEquals(0x200, $result);
}
public function testFailure()
{
$result = hammer_parse($this->parser, "\x02");
$this->assertEquals(NULL, $result);
}
}
?>

View file

@ -0,0 +1,24 @@
<?php
include_once 'hammer.php';
class Uint32Test extends PHPUnit_Framework_TestCase
{
protected $parser;
protected function setUp()
{
$this->parser = hammer_uint32();
}
public function testSuccess()
{
$result = hammer_parse($this->parser, "\x00\x02\x00\x00");
$this->assertEquals(0x20000, $result);
}
public function testFailure()
{
$result = hammer_parse($this->parser, "\x00\x02\x00");
$this->assertEquals(NULL, $result);
}
}
?>

View file

@ -0,0 +1,24 @@
<?php
include_once 'hammer.php';
class Uint64Test extends PHPUnit_Framework_TestCase
{
protected $parser;
protected function setUp()
{
$this->parser = hammer_uint64();
}
public function testSuccess()
{
$result = hammer_parse($this->parser, "\x00\x00\x00\x02\x00\x00\x00\x00");
$this->assertEquals(0x200000000, $result);
}
public function testFailure()
{
$result = hammer_parse($this->parser, "\x00\x00\x00\x02\x00\x00\x00");
$this->assertEquals(NULL, $result);
}
}
?>

View file

@ -0,0 +1,24 @@
<?php
include_once 'hammer.php';
class Uint8Test extends PHPUnit_Framework_TestCase
{
protected $parser;
protected function setUp()
{
$this->parser = hammer_uint8();
}
public function testSuccess()
{
$result = hammer_parse($this->parser, "\x78");
$this->assertEquals(0x78, $result);
}
public function testFailure()
{
$result = hammer_parse($this->parser, "");
$this->assertEquals(NULL, $result);
}
}
?>

View file

@ -0,0 +1,43 @@
<?php
include_once 'hammer.php';
class WhitespaceTest extends PHPUnit_Framework_TestCase
{
protected $parser1;
protected $parser2;
protected function setUp()
{
$this->parser1 = hammer_whitespace(hammer_ch("a"));
$this->parser2 = hammer_whitespace(hammer_end());
}
public function testSuccess1()
{
$result1 = hammer_parse($this->parser1, "a");
$result2 = hammer_parse($this->parser1, " a");
$result3 = hammer_parse($this->parser1, " a");
$result4 = hammer_parse($this->parser1, "\ta");
$this->assertEquals("a", $result1);
$this->assertEquals("a", $result2);
$this->assertEquals("a", $result3);
$this->assertEquals("a", $result4);
}
public function testFailure1()
{
$result = hammer_parse($this->parser1, "_a");
$this->assertEquals(NULL, $result);
}
public function testSuccess2()
{
$result1 = hammer_parse($this->parser2, "");
$result2 = hammer_parse($this->parser2, " ");
$this->assertEquals(NULL, $result1);
$this->assertEquals(NULL, $result2);
}
public function testFailure2()
{
$result = hammer_parse($this->parser2, " x");
$this->assertEquals(NULL, $result);
}
}
?>

View file

@ -0,0 +1,29 @@
<?php
include_once 'hammer.php';
class XorTest extends PHPUnit_Framework_TestCase
{
protected $parser;
protected function setUp()
{
$this->parser = hammer_xor(hammer_ch_range("0", "6"), hammer_ch_range("5", "9"));
}
public function testSuccess()
{
$result1 = hammer_parse($this->parser, "0");
$result2 = hammer_parse($this->parser, "9");
$this->assertEquals("0", $result1);
$this->assertEquals("9", $result2);
}
public function testFailure()
{
$result1 = hammer_parse($this->parser, "5");
$result2 = hammer_parse($this->parser, "a");
$this->assertEquals(NULL, $result1);
$this->assertEquals(NULL, $result2);
}
}
?>

255
src/bindings/php/hammer.i Normal file
View file

@ -0,0 +1,255 @@
%module hammer;
%include "exception.i";
%{
#include "allocator.h"
%}
%ignore HCountedArray_;
%inline %{
static int h_tt_php;
%}
%init %{
h_tt_php = h_allocate_token_type("com.upstandinghackers.hammer.php");
%}
%inline {
struct HParsedToken_;
struct HParseResult_;
void hpt_to_php(const struct HParsedToken_ *token, zval *return_value);
static struct HParsedToken_* call_action(const struct HParseResult_ *p, void* user_data);
}
%typemap(in) (const uint8_t* str, const size_t len) {
$1 = (uint8_t*)(*$input)->value.str.val;
$2 = (*$input)->value.str.len;
}
%apply (const uint8_t* str, const size_t len) { (const uint8_t* input, size_t length) }
%apply (const uint8_t* str, const size_t len) { (const uint8_t* charset, size_t length) }
%typemap(in) void*[] {
if (IS_ARRAY == Z_TYPE_PP($input)) {
HashTable *arr = Z_ARRVAL_PP($input);
HashPosition pointer;
int size = zend_hash_num_elements(arr);
int i = 0;
int res = 0;
$1 = (void**)malloc((size+1)*sizeof(HParser*));
for (i=0; i<size; i++) {
zval **data;
if (zend_hash_index_find(arr, i, (void**)&data) == FAILURE) {
$1 = NULL;
zend_throw_exception(zend_exception_get_default(TSRMLS_C), "index in parser array out of bounds", 0 TSRMLS_CC);
} else {
res = SWIG_ConvertPtr(*data, &($1[i]), SWIGTYPE_p_HParser_, 0 | 0);
if (!SWIG_IsOK(res)) {
zend_throw_exception(zend_exception_get_default(TSRMLS_C), "that wasn't an HParser", 0 TSRMLS_CC);
}
}
}
} else {
$1 = NULL;
zend_throw_exception(zend_exception_get_default(TSRMLS_C), "that wasn't an array of HParsers", 0 TSRMLS_CC);
}
}
%typemap(in) uint8_t {
if (IS_LONG == Z_TYPE_PP($input)) {
$1 = Z_LVAL_PP($input);
} else if (IS_STRING != Z_TYPE_PP($input)) {
// FIXME raise some error
} else {
$1 = *(uint8_t*)Z_STRVAL_PP($input);
}
}
%typemap(out) HBytes* {
RETVAL_STRINGL((char*)$1->token, $1->len, 1);
}
%typemap(out) struct HParseResult_* {
if ($1 == NULL) {
/* If we want parse errors to be exceptions, this is the place to do it */
//SWIG_exception(SWIG_TypeError, "typemap: should have been an HParseResult*, was NULL");
RETVAL_NULL();
} else {
hpt_to_php($1->ast, $result);
}
}
%rename("hammer_token") h_token;
%rename("hammer_int_range") h_int_range;
%rename("hammer_bits") h_bits;
%rename("hammer_int64") h_int64;
%rename("hammer_int32") h_int32;
%rename("hammer_int16") h_int16;
%rename("hammer_int8") h_int8;
%rename("hammer_uint64") h_uint64;
%rename("hammer_uint32") h_uint32;
%rename("hammer_uint16") h_uint16;
%rename("hammer_uint8") h_uint8;
%rename("hammer_whitespace") h_whitespace;
%rename("hammer_left") h_left;
%rename("hammer_right") h_right;
%rename("hammer_middle") h_middle;
%rename("hammer_end") h_end_p;
%rename("hammer_nothing") h_nothing_p;
%rename("hammer_butnot") h_butnot;
%rename("hammer_difference") h_difference;
%rename("hammer_xor") h_xor;
%rename("hammer_many") h_many;
%rename("hammer_many1") h_many1;
%rename("hammer_repeat_n") h_repeat_n;
%rename("hammer_optional") h_optional;
%rename("hammer_ignore") h_ignore;
%rename("hammer_sep_by") h_sepBy;
%rename("hammer_sep_by1") h_sepBy1;
%rename("hammer_epsilon") h_epsilon_p;
%rename("hammer_length_value") h_length_value;
%rename("hammer_and") h_and;
%rename("hammer_not") h_not;
%rename("hammer_indirect") h_indirect;
%rename("hammer_bind_indirect") h_bind_indirect;
%rename("hammer_compile") h_compile;
%rename("hammer_parse") h_parse;
%include "../swig/hammer.i";
%inline {
void hpt_to_php(const HParsedToken *token, zval *return_value) {
TSRMLS_FETCH();
if (!token) {
RETVAL_NULL();
return;
}
switch (token->token_type) {
case TT_NONE:
RETVAL_NULL();
break;
case TT_BYTES:
RETVAL_STRINGL((char*)token->token_data.bytes.token, token->token_data.bytes.len, 1);
break;
case TT_SINT:
RETVAL_LONG(token->token_data.sint);
break;
case TT_UINT:
RETVAL_LONG(token->token_data.uint);
break;
case TT_SEQUENCE:
array_init(return_value);
for (int i=0; i < token->token_data.seq->used; i++) {
zval *tmp;
ALLOC_INIT_ZVAL(tmp);
hpt_to_php(token->token_data.seq->elements[i], tmp);
add_next_index_zval(return_value, tmp);
}
break;
default:
if (token->token_type == h_tt_php) {
zval *tmp;
tmp = (zval*)token->token_data.user;
RETVAL_ZVAL(tmp, 0, 0);
} else {
int res = 0;
res = SWIG_ConvertPtr(return_value, (void*)token, SWIGTYPE_p_HParsedToken_, 0 | 0);
if (!SWIG_IsOK(res)) {
zend_throw_exception(zend_exception_get_default(TSRMLS_C), "hpt_to_php: that wasn't an HParsedToken", 0 TSRMLS_CC);
}
// TODO: support registry
}
break;
}
}
static HParsedToken* call_action(const HParseResult *p, void *user_data) {
zval **args;
zval func;
zval *ret;
TSRMLS_FETCH();
args = (zval**)h_arena_malloc(p->arena, sizeof(*args) * 1); // one-element array of pointers
MAKE_STD_ZVAL(args[0]);
ALLOC_INIT_ZVAL(ret);
ZVAL_STRING(&func, (const char*)user_data, 0);
hpt_to_php(p->ast, args[0]);
int ok = call_user_function(EG(function_table), NULL, &func, ret, 1, args TSRMLS_CC);
if (ok != SUCCESS) {
zend_throw_exception(zend_exception_get_default(TSRMLS_C), "call_action failed", 0 TSRMLS_CC);
return NULL;
}
// Whatever the zval is, stuff it into a token
HParsedToken *tok = h_make(p->arena, h_tt_php, ret);
return tok;
}
static int call_predicate(HParseResult *p, void *user_data) {
zval **args;
zval func;
zval *ret;
TSRMLS_FETCH();
args = (zval**)h_arena_malloc(p->arena, sizeof(*args) * 1); // one-element array of pointers
MAKE_STD_ZVAL(args[0]);
ALLOC_INIT_ZVAL(ret);
ZVAL_STRING(&func, (const char*)user_data, 0);
hpt_to_php(p->ast, args[0]);
int ok = call_user_function(EG(function_table), NULL, &func, ret, 1, args TSRMLS_CC);
if (ok != SUCCESS) {
zend_throw_exception(zend_exception_get_default(TSRMLS_C), "call_predicate failed", 0 TSRMLS_CC);
return 0;
}
return Z_LVAL_P(ret);
}
HParser* hammer_action(HParser *parser, const char *name) {
const char *fname = strdup(name);
return h_action(parser, call_action, (void*)fname);
}
HParser* hammer_predicate(HParser *parser, const char *name) {
const char *fname = strdup(name);
return h_attr_bool(parser, call_predicate, (void*)fname);
}
}
%pragma(php) code="
function hammer_ch($ch)
{
if (is_string($ch))
return hammer_token($ch);
else
return h_ch($ch);
}
function hammer_choice()
{
$arg_list = func_get_args();
$arg_list[] = NULL;
return h_choice__a($arg_list);
}
function hammer_sequence()
{
$arg_list = func_get_args();
$arg_list[] = NULL;
return h_sequence__a($arg_list);
}
function hammer_ch_range($low, $high)
{
return hammer_action(h_ch_range($low, $high), \"chr\");
}
function hammer_in($charset)
{
return hammer_action(h_in($charset), \"chr\");
}
function hammer_not_in($charset)
{
return hammer_action(h_not_in($charset), \"chr\");
}
"

View file

@ -0,0 +1,2 @@
enable_dl = On
extension = "hammer.so"

View file

@ -344,3 +344,5 @@ def int64(): return _h_int64()
%}
#endif