You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucy.apache.org by ma...@apache.org on 2011/02/03 00:02:11 UTC

[lucy-commits] svn commit: r1066678 - in /incubator/lucy/trunk/clownfish: lib/Clownfish.xs lib/Clownfish/Symbol.pm src/CFCSymbol.c t/051-symbol.t

Author: marvin
Date: Wed Feb  2 23:02:11 2011
New Revision: 1066678

URL: http://svn.apache.org/viewvc?rev=1066678&view=rev
Log:
Move some functionality (primarily validation) in the Clownfish::Symbol
constructor from Perl to C.

Modified:
    incubator/lucy/trunk/clownfish/lib/Clownfish.xs
    incubator/lucy/trunk/clownfish/lib/Clownfish/Symbol.pm
    incubator/lucy/trunk/clownfish/src/CFCSymbol.c
    incubator/lucy/trunk/clownfish/t/051-symbol.t

Modified: incubator/lucy/trunk/clownfish/lib/Clownfish.xs
URL: http://svn.apache.org/viewvc/incubator/lucy/trunk/clownfish/lib/Clownfish.xs?rev=1066678&r1=1066677&r2=1066678&view=diff
==============================================================================
--- incubator/lucy/trunk/clownfish/lib/Clownfish.xs (original)
+++ incubator/lucy/trunk/clownfish/lib/Clownfish.xs Wed Feb  2 23:02:11 2011
@@ -162,18 +162,20 @@ PPCODE:
 MODULE = Clownfish    PACKAGE = Clownfish::Symbol
 
 SV*
-_new(klass, parcel, exposure, class_name_sv, class_cnick_sv, micro_sym)
+_new(klass, parcel, exposure, class_name_sv, class_cnick_sv, micro_sym_sv)
     const char *klass;
     SV *parcel;
     const char *exposure;
     SV *class_name_sv;
     SV *class_cnick_sv;
-    const char *micro_sym;
+    SV *micro_sym_sv;
 CODE:
     const char *class_name = SvOK(class_name_sv) 
                            ? SvPV_nolen(class_name_sv) : NULL;
     const char *class_cnick = SvOK(class_cnick_sv) 
                             ? SvPV_nolen(class_cnick_sv) : NULL;
+    const char *micro_sym = SvOK(micro_sym_sv) 
+                            ? SvPV_nolen(micro_sym_sv) : NULL;
     CFCSymbol *self = CFCSymbol_new(parcel, exposure, class_name, class_cnick,
         micro_sym);
     RETVAL = newSV(0);

Modified: incubator/lucy/trunk/clownfish/lib/Clownfish/Symbol.pm
URL: http://svn.apache.org/viewvc/incubator/lucy/trunk/clownfish/lib/Clownfish/Symbol.pm?rev=1066678&r1=1066677&r2=1066678&view=diff
==============================================================================
--- incubator/lucy/trunk/clownfish/lib/Clownfish/Symbol.pm (original)
+++ incubator/lucy/trunk/clownfish/lib/Clownfish/Symbol.pm Wed Feb  2 23:02:11 2011
@@ -55,31 +55,6 @@ sub new {
         $parcel = Clownfish::Parcel->singleton( name => $parcel );
     }
 
-    # Validate micro_sym.
-    confess "micro_sym is required" unless $micro_sym;
-    confess("Invalid micro_sym: '$micro_sym'")
-        unless $micro_sym =~ /^[A-Za-z_][A-Za-z0-9_]*$/;
-
-    # Validate exposure.
-    confess("Invalid value for 'exposure': $exposure")
-        unless $exposure =~ /^(?:public|parcel|private|local)$/;
-
-    # Validate class name, validate or derive class_cnick.
-    if ( defined $class_name ) {
-        confess("Invalid class name: $class_name")
-            unless $class_name =~ $class_name_regex;
-        if ( !defined $class_cnick ) {
-            $class_name =~ /(\w+)$/;
-            $class_cnick = $1;
-        }
-        confess("Invalid class_cnick: $class_cnick")
-            unless $class_cnick =~ /^[A-Z]+[A-Za-z0-9]*$/;
-    }
-    elsif ( defined $class_cnick ) {
-        # Sanity check class_cnick without class_name.
-        confess("Can't supply class_cnick without class_name");
-    }
-
     # Create the object.
     my $class_class = ref($either) || $either;
     return $class_class->_new( $parcel, $exposure, $class_name, $class_cnick,

Modified: incubator/lucy/trunk/clownfish/src/CFCSymbol.c
URL: http://svn.apache.org/viewvc/incubator/lucy/trunk/clownfish/src/CFCSymbol.c?rev=1066678&r1=1066677&r2=1066678&view=diff
==============================================================================
--- incubator/lucy/trunk/clownfish/src/CFCSymbol.c (original)
+++ incubator/lucy/trunk/clownfish/src/CFCSymbol.c Wed Feb  2 23:02:11 2011
@@ -15,10 +15,17 @@
  */
 
 #include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
 #include "EXTERN.h"
 #include "perl.h"
 #include "XSUB.h"
 
+#ifndef true
+  #define true 1
+  #define false 0
+#endif
+
 #define CFC_NEED_SYMBOL_STRUCT_DEF
 #include "CFCSymbol.h"
 
@@ -36,16 +43,130 @@ CFCSymbol_new(void *parcel, const char *
         micro_sym);
 }
 
+static int
+S_validate_exposure(const char *exposure)
+{
+    if (!exposure) { return false; }
+    if (   strcmp(exposure, "public")
+        && strcmp(exposure, "parcel")
+        && strcmp(exposure, "private")
+        && strcmp(exposure, "local")
+    ) {
+        return false;
+    }
+    return true;
+}
+
+static int
+S_validate_class_name(const char *class_name)
+{
+    const char *ptr;
+
+    // Must be UpperCamelCase, separated by "::".
+    for (ptr = class_name; *ptr != 0; ) {
+        if (!isupper(*ptr)) { return false; }
+
+        // Each component must contain lowercase letters.
+        const char *substring;
+        for (substring = ptr; ; substring++) {
+            if      (*substring == 0)     { return false; }
+            else if (*substring == ':')   { return false; }
+            else if (islower(*substring)) { break; }
+        }
+
+        while(*ptr != 0) {
+            if      (*ptr == 0) { break; }
+            else if (*ptr == ':') {
+                ptr++;
+                if (*ptr != ':') { return false; }
+                ptr++;
+                if (*ptr == 0) { return false; }
+                break;
+            }
+            else if (!isalnum(*ptr)) { return false; }
+            ptr++;
+        }
+    }
+
+    return true;
+}
+
+static int
+S_validate_class_cnick(const char *class_cnick)
+{
+    // Allow all caps.
+    const char *ptr;
+    for (ptr = class_cnick; ; ptr++) {
+        if (*ptr == 0) {
+            if (strlen(class_cnick)) { return true; }
+            else { break; }
+        }
+        else if (!isupper(*ptr)) { break; }
+    }
+
+    // Same as one component of a class name.
+    if (!S_validate_class_name(class_cnick)) { return false; }
+    if (strchr(class_cnick, ':') != NULL) { return false; }
+    return true;
+}
+
+static int
+S_validate_identifier(const char *identifier)
+{
+    const char *ptr = identifier;
+    if (!isalpha(*ptr) && *ptr != '_') { return false; }
+    for ( ; *ptr != 0; ptr++) {
+        if (!isalnum(*ptr) && *ptr != '_') { return false; }
+    }
+    return true;
+}
+
 CFCSymbol*
 CFCSymbol_init(CFCSymbol *self, void *parcel, const char *exposure, 
                const char *class_name, const char *class_cnick, 
                const char *micro_sym)
 {
-    self->parcel      = newSVsv((SV*)parcel);
-    self->exposure    = savepv(exposure);
-    self->class_name  = savepv(class_name);
-    self->class_cnick = savepv(class_cnick);
-    self->micro_sym   = savepv(micro_sym);
+    self->parcel = newSVsv((SV*)parcel);
+
+    // Validate exposure.
+    if (!S_validate_exposure(exposure)) {
+        croak("Invalid exposure: '%s'", exposure ? exposure : "[NULL]");
+    }
+    self->exposure = savepv(exposure);
+
+    // Validate class name (if supplied);
+    if (class_name && !S_validate_class_name(class_name)) {
+        croak("Invalid class_name: '%s'", class_name);
+    }
+    self->class_name = savepv(class_name);
+
+    // Derive class_cnick if necessary, then validate.
+    if (class_name) {
+        if (class_cnick) {
+            self->class_cnick = savepv(class_cnick);
+        }
+        else {
+            const char *last_colon = strrchr(class_name, ':');
+            const char *cnick = last_colon ? last_colon + 1 : class_name;
+            self->class_cnick = savepv(cnick);
+        }
+    }
+    else if (class_cnick) {
+        // Sanity check class_cnick without class_name.
+        croak("Can't supply class_cnick without class_name");
+    }
+    else {
+        self->class_cnick = NULL;
+    }
+    if (self->class_cnick && !S_validate_class_cnick(self->class_cnick)) {
+        croak("Invalid class_cnick: '%s'", self->class_cnick);
+    }
+
+    if (!micro_sym || !S_validate_identifier(micro_sym)) {
+        croak("Invalid micro_sym: '%s'",  micro_sym ? micro_sym : "[NULL]");
+    }
+    self->micro_sym = savepv(micro_sym);
+
     return self;
 }
 

Modified: incubator/lucy/trunk/clownfish/t/051-symbol.t
URL: http://svn.apache.org/viewvc/incubator/lucy/trunk/clownfish/t/051-symbol.t?rev=1066678&r1=1066677&r2=1066678&view=diff
==============================================================================
--- incubator/lucy/trunk/clownfish/t/051-symbol.t (original)
+++ incubator/lucy/trunk/clownfish/t/051-symbol.t Wed Feb  2 23:02:11 2011
@@ -28,10 +28,10 @@ use Test::More tests => 44;
 
 for (qw( foo FOO 1Foo Foo_Bar FOOBAR 1FOOBAR )) {
     eval { my $thing = ClownfishyThing->new( class_name => $_ ) };
-    like( $@, qr/class name/, "Reject invalid class name $_" );
+    like( $@, qr/class_name/, "Reject invalid class name $_" );
     my $bogus_middle = "Foo::" . $_ . "::Bar";
     eval { my $thing = ClownfishyThing->new( class_name => $bogus_middle ) };
-    like( $@, qr/class name/, "Reject invalid class name $bogus_middle" );
+    like( $@, qr/class_name/, "Reject invalid class name $bogus_middle" );
 }
 
 my @exposures = qw( public private parcel local );