view mde/mergetag/old-code/typeSpec.d.old @ 4:9a990644948c

Many changes: upgraded to tango 0.99.4, reorganised mde/input, large changes to mde/mergetag and mde/init, separated off test/MTTest.d and more. committer: Diggory Hardy <diggory.hardy@gmail.com>
author Diggory Hardy <diggory.hardy@gmail.com>
date Sun, 06 Jan 2008 17:38:51 +0000
parents
children
line wrap: on
line source

/+ I wrote this and then realised it's not worth using, it being easier and faster to match type
strings without this. This module does enable spaces to be in appropriate places, but so what...

module typeSpec;

import mde.mergetag.exception;

import Util = tango.text.Util;

/**
 * Struct to view a type specifier string.
 */
struct TypeView
{
    /// Type of stored type specifier (NULL, BASIC, ARRAY, ASSOCIATIVE_ARRAY).
    enum SPEC_TYPE : ubyte {
        NULL, BASIC, ARRAY, ASSOCIATIVE_ARRAY
    }
    
    SPEC_TYPE spec_type;		/// Current specifier type.
    union {
        char[] type_name;		/// For BASIC types is the type name.
        TypeView* type_array_value;	/// For ARRAY and ASSOCIATIVE_ARRAY types, this is the value-type.
    }
    TypeView* type_array_key;	/// For ASSOCIATIVE_ARRAY types, this is the key-type;
    
    /** Construct and return a TypeView from a source string.
     *
     * Such a string should have one of the following forms:
     *	TYPE_NAME:	[_a-zA-Z][_a-zA-Z0-9]* (regexp)
     *	ARRAY:		TYPE_NAME[]
     *	ASSOC_ARRAY:	TYPE_NAME[TYPE_NAME]
     *
     * Throws MTBadTypeStringException on bad type specifier strings.
     */
    static TypeSpec parse (char[] src) {
        bool isNameChar (char c) {
            return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c = '_';
        }
        void throwErr () {
            logger.warn ("Bad type string");
            throw new MTBadTypeStringException ();
        }
        
        src = Util.trim(src);
        if (!src.length) throwErr;
        
        TypeView ret;
        if (src[$-1] == ']') {	// ARRAY or ASSOCIATIVE_ARRAY type
            if (src.length < 2) throwErr;
            
            if (src[$-2] == '[') {	// ARRAY type
                ret.spec_type = SPEC_TYPE.ARRAY;		// this is an array of...
                ret.type_array_value = parse (src[0..$-2]);	// whatever this is
            }
            else {			// ASSOCIATIVE_ARRAY type
                // look backwards for matching '[' bracket:
                uint i = src.length-2;
                uint recursion_depth = 0;
                while (true) {
                    char c = src[i];
                    
                    if (c == ']') ++recursion_depth;
                    if (c == '[') {
                        if (recursion_depth) --recursion_depth;
                        else break;
                    }
                    if (i == 0) throwErr;	// no matching bracket!
                    else --i;
                }
                
                ret.spec_type = SPEC_TYPE.ASSOCIATIVE_ARRAY;
                ret.type_array_value = parse (src[0..i]);
                ret.type_array_key = parse (src[i+1..$-1]);
            }
        }
        else {	// BASIC type
            char c = src[0];
            if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c = '_'))
                throwErr;
            for (uint i=1; i < src.length; ++i) {
                if (!isNameChar(src[i])) throwErr;
            }
            
            ret.spec_type = SPEC_TYPE.BASIC;
            ret.type_name = src;
        }
        return ret;
    }
}

unittest {
    TypeView tv = TypeView.parse (` type1 [] [ Type2 [] ] [] `);
    assert (tv.spec_type == SPEC_TYPE.ARRAY);
    assert (tv.type_array_value.spec_type == SPEC_TYPE.ASSOCIATIVE_ARRAY);
    assert (tv.type_array_value.type_array_value.spec_type == SPEC_TYPE.ARRAY);
    assert (tv.type_array_value.type_array_value.type_array_value.spec_type == SPEC_TYPE.BASIC);
    assert (tv.type_array_value.type_array_value.type_array_value.type_name == `type1`);
    assert (tv.type_array_value.type_array_key.spec_type == SPEC_TYPE.ARRAY);
    assert (tv.type_array_value.type_array_key.type_array_value.spec_type == SPEC_TYPE.BASIC);
    assert (tv.type_array_value.type_array_key.type_array_value.type_name == `Type2`);
}
+/