blob: 8b819997ec75cd1fa8228c4ab62e8c089207f356 [file] [log] [blame]
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
use strict;
use warnings;
use Test::More tests => 87;
BEGIN { use_ok('Clownfish::CFC::Parser') }
my $parser = Clownfish::CFC::Parser->new;
isa_ok( $parser, "Clownfish::CFC::Parser" );
isa_ok(
$parser->parse("parcel Fish;"),
"Clownfish::CFC::Model::Parcel",
"parcel_definition"
);
# Set and leave parcel.
my $registered = Clownfish::CFC::Model::Parcel->new(
name => 'Crustacean',
nickname => 'Crust',
);
$registered->register;
my $parcel = $parser->parse('parcel Crustacean;')
or die "failed to process parcel_definition";
is( $$parcel, $$registered, "Fetch registered parcel" );
is( ${ $parser->get_parcel },
$$parcel, "parcel_definition sets internal \$parcel var" );
for (qw( foo _foo foo_yoo FOO Foo fOO f00 foo_foo_foo )) {
my $var = $parser->parse("int32_t $_;");
is( $var->micro_sym, $_, "identifier/declarator: $_" );
}
for (qw( void float uint32_t int64_t uint8_t bool )) {
my $var = $parser->parse("int32_t $_;");
ok( !defined($var), "reserved word not parsed as identifier: $_" );
}
isa_ok( $parser->parse("bool"),
"Clownfish::CFC::Model::Type", "C99 integer specifier bool" );
for (qw( ByteBuf Obj ANDMatcher )) {
my $class = $parser->parse("class $_ {}");
my $type = $parser->parse("$_*");
$type->resolve;
is( $type->get_specifier, "crust_$_", "object_type_specifier $_" );
}
ok( $parser->parse("const char")->const, "type_qualifier const" );
ok( $parser->parse("$_ inert int32_t foo;")->$_, "exposure_specifier $_" )
for qw( public );
ok( $parser->parse("int32_t foo;")->private,
"exposure_specifier '' implicitly private" );
isa_ok( $parser->parse($_), "Clownfish::CFC::Model::Type", "type $_" )
for ( 'const char *', 'Obj*', 'i32_t', 'char[]', 'long[1]', 'i64_t[30]' );
is( $parser->parse("(int32_t foo = $_)")->get_initial_values->[0],
$_, "hex_constant: $_" )
for (qw( 0x1 0x0a 0xFFFFFFFF -0xFC ));
is( $parser->parse("(int32_t foo = $_)")->get_initial_values->[0],
$_, "integer_constant: $_" )
for (qw( 1 -9999 0 10000 ));
is( $parser->parse("(double foo = $_)")->get_initial_values->[0],
$_, "float_constant: $_" )
for (qw( 1.0 -9999.999 0.1 0.0 ));
is( $parser->parse("(String *foo = $_)")->get_initial_values->[0],
$_, "string_literal: $_" )
for ( q|"blah"|, q|"blah blah"|, q|"\\"blah\\" \\"blah\\""| );
my @composites = ( 'int[]', "i32_t **", "Foo **", "Foo ***", "const void *" );
for my $composite (@composites) {
my $parsed = $parser->parse($composite);
ok( $parsed && $parsed->is_composite, "composite_type: $composite" );
}
my @object_types = ( 'Obj *', "incremented Foo*", "decremented String *" );
for my $object_type (@object_types) {
my $parsed = $parser->parse($object_type);
ok( $parsed && $parsed->is_object, "object_type: $object_type" );
}
my %param_lists = (
'(int foo)' => 1,
'(Obj *foo, Foo **foo_ptr)' => 2,
'()' => 0,
);
while ( my ( $param_list, $num_params ) = each %param_lists ) {
my $parsed = $parser->parse($param_list);
isa_ok(
$parsed,
"Clownfish::CFC::Model::ParamList",
"param_list: $param_list"
);
}
ok( $parser->parse("(int foo, ...)")->variadic, "variadic param list" );
my $param_list = $parser->parse(q|(int foo = 0xFF, char *bar ="blah")|);
is_deeply(
$param_list->get_initial_values,
[ '0xFF', '"blah"' ],
"initial values"
);
$parser->set_class_name('Stuff::Obj');
$parser->set_class_nickname('Obj');
ok( $parser->parse($_), "declaration statement: $_" )
for (
'public Foo* Spew_Foo(Obj *self, uint32_t *how_many);',
'public inert Hash *hash;',
);
for (qw( Foo FooJr FooIII Foo4th )) {
my $class = $parser->parse("class $_ {}");
my $type = $parser->parse("$_*");
$type->resolve;
is( $type->get_specifier, "crust_$_", "object_type_specifier: $_" )
}
Clownfish::CFC::Model::Class->_clear_registry();
SKIP: {
skip( "Can't recover from bad specifier under flex/lemon parser", 6 );
ok( !$parser->parse("$_*"), "illegal object_type_specifier: $_" )
for (qw( foo fooBar Foo_Bar FOOBAR 1Foo 1FOO ));
}
is( $parser->parse("class $_ { }")->get_class_name, $_, "class_name: $_" )
for (qw( Foo Foo::FooJr Foo::FooJr::FooIII Foo::FooJr::FooIII::Foo4th ));
SKIP: {
skip( "Can't recover from bad class name under flex/lemon parser", 6 );
ok( !$parser->parse("class $_ { }"), "illegal class_name: $_" )
for (qw( foo fooBar Foo_Bar FOOBAR 1Foo 1FOO ));
}
is( $parser->parse(qq|class Foodie$_ nickname $_ { }|)->get_nickname,
$_, "nickname: $_" )
for (qw( Food FF ));
SKIP: {
skip( "Can't recover from bad nickname under flex/lemon parser", 3 );
is( !$parser->parse(qq|class Foodie$_ nickname $_ { }|),
"Illegal nickname: $_" )
for (qw( foo fOO 1Foo ));
}