Changeset 37

Show
Ignore:
Timestamp:
02/21/08 15:14:27 (11 months ago)
Author:
aarti_pl
Message:

- Tokenizer -> Scanner
- new module Storage
- reworked scanning functions
- more precise description of symbols (not everything is string)
- escaper module has ability to escape named characters (as an option)
- possibility to unescape \x, \u, \U. \oct etc.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/doost/core/Traits.d

    r32 r37  
    3737    else 
    3838        static assert(false, "'" ~ T.stringof ~ "' is not an array."); 
    39 } 
    40  
    41 /******************************************************************************* 
    42     Evaluates to type of array element 
    43  ******************************************************************************/ 
    44 //TODO: checki na spełnianie wymagań co do array 
    45 template elementType(T) { 
    46     static if( is( T U : U[] ) ) { 
    47         pragma(msg, "elementType: " ~ T.stringof ~ " -> " ~ U.stringof); 
    48         alias U elementType; 
    49     } else 
    50     static if( is( typeof(T.get(1u)) U == U[]) ) { 
    51         pragma(msg, "elementType: " ~ T.stringof ~ " -> " ~ U.stringof); 
    52         alias U elementType; 
    53     } else 
    54     static assert(false, "'" ~ T.stringof ~ "' can not be threated as array."); 
    5539} 
    5640 
  • trunk/doost/text/Escaper.d

    r31 r37  
     1/******************************************************************************* 
     2 
     3    License:    Boost Software License, v. 1.0 
     4                Academic Free License, v. 3.0 
     5                BSD License 
     6 
     7    Authors:    Marcin Kuszczak, www.zapytajmnie.com (author's christian site) 
     8 
     9    Version:    0.9.0 
     10    Date:       18 Jan 2008 
     11 
     12    History:    0.9.0   -   initial public beta version 
     13 
     14 ******************************************************************************/ 
     15 
    116module doost.text.Escaper; 
    217 
     18import std.stdio; 
     19 
     20import doost.util.DUnit; 
    321import doost.core.Traits; 
    4 import std.stdio; 
    5 import doost.util.DUnit; 
    6  
    7 //------------------------------------------------------------------------------ 
    8  
    9 //TODO: add other escape sequences from: http://www.digitalmars.com/d/lex.html 
    10  
    11  
     22import doost.text.Scanner; 
     23 
     24import doost.storage.Storage; 
     25 
     26//------------------------------------------------------------------------------ 
     27 
     28unittest { 
     29    testSuite.timing.width(100).repeat(1).begin("Escaper module"); 
     30
     31 
     32//------------------------------------------------------------------------------ 
     33 
     34/******************************************************************************* 
     35 ******************************************************************************/ 
    1236class UnescapeException : Exception { 
    1337    this(string str) { 
     
    1640} 
    1741 
     42//------------------------------------------------------------------------------ 
     43 
    1844/******************************************************************************* 
     45    Params: 
     46            full = replaces also characters using named characters (slower) 
    1947 ******************************************************************************/ 
    20 T escape(T)(T str) { 
     48T escape(T)(T input, bool full = false) { 
    2149    static assert(isString!(T), "Only unicode strings allowed"); 
    2250 
     51    uint pos; 
     52    Matcher m; 
     53    T result; 
     54 
     55    while(!input.eos(pos)) { 
     56        m = scan(input, SequenceSet!(T).escchar, pos); 
     57 
     58        if (cast(bool)m) { 
     59            result ~= input.get(pos); 
     60            input.get(m.position - pos); 
     61 
     62            result ~= '\\' ~ SequenceSet!(T).escseq.matching(m); 
     63            pos = 0; 
     64            continue; 
     65        } 
     66 
     67        if (full) { 
     68            m = scan(input, SequenceSet!(T).namedchar, pos); 
     69 
     70            if (cast(bool)m) { 
     71                result ~= input.get(pos); 
     72                input.get(m.position - pos); 
     73 
     74                result ~= r"\&" ~ SequenceSet!(T).namedseq.matching(m); 
     75                pos = 0; 
     76            continue; 
     77            } 
     78        } 
     79 
     80        ++pos; 
     81    } 
     82 
     83    result ~= input.get(pos); 
     84 
     85    return result; 
     86} 
     87 
     88//------------------------------------------------------------------------------ 
     89 
     90T escapeOld(T)(T input, bool full = false) { 
     91    //poniÅŒsze jest 5x szybsze niÅŒ nowa implementacja 
    2392    T result; 
    24     foreach(c; str) { 
     93    foreach(c; input) { 
    2594        switch (c) { 
    2695            case '\\'  : result ~= "\\\\"; break; 
     
    43112//------------------------------------------------------------------------------ 
    44113 
     114unittest { testCase.repeat(1).execute("basic escape characters", { 
     115    assert(escape("\""[]) == "\\\""); 
     116    assert(escape("\?"[]) == "\\?"); 
     117    assert(escape("\\"[]) == "\\\\"); 
     118    assert(escape("\a"[]) == "\\a"); 
     119    assert(escape("\b"[]) == "\\b"); 
     120    assert(escape("\f"[]) == "\\f"); 
     121    assert(escape("\n"[]) == "\\n"); 
     122    assert(escape("\r"[]) == "\\r"); 
     123    assert(escape("\t"[]) == "\\t"); 
     124    assert(escape("\v"[]) == "\\v"); 
     125});} 
     126 
     127//------------------------------------------------------------------------------ 
     128 
     129unittest { testCase.repeat(1).execute("basic old implementation escape characters", { 
     130    assert(escapeOld("\""[]) == "\\\""); 
     131    assert(escapeOld("\?"[]) == "\\?"); 
     132    assert(escapeOld("\\"[]) == "\\\\"); 
     133    assert(escapeOld("\a"[]) == "\\a"); 
     134    assert(escapeOld("\b"[]) == "\\b"); 
     135    assert(escapeOld("\f"[]) == "\\f"); 
     136    assert(escapeOld("\n"[]) == "\\n"); 
     137    assert(escapeOld("\r"[]) == "\\r"); 
     138    assert(escapeOld("\t"[]) == "\\t"); 
     139    assert(escapeOld("\v"[]) == "\\v"); 
     140});} 
     141 
     142//------------------------------------------------------------------------------ 
     143 
     144unittest { testCase.execute("escape with named characters", { 
     145    //full escape with named characters 
     146    assert(escape("\♥"[], true) == r"\♥"); 
     147    assert(escape("\∅"[], true) == r"\∅"); 
     148    assert(escape("\∑"[], true) == r"\∑"); 
     149});} 
     150 
     151//------------------------------------------------------------------------------ 
     152 
     153private uint toDec(dchar c) { 
     154    uint code = c; 
     155    if (code >= 0x61) code -= 0x57; 
     156    if (code >= 0x41) code -= 0x37; 
     157    if (code >= 0x30) code -= 0x30; 
     158    return code; 
     159} 
     160 
     161private uint[] maxsize = [0u, 255, 65535, 4228250625]; 
     162 
    45163/******************************************************************************* 
    46164 ******************************************************************************/ 
    47 T unescape(T)(T str) { 
    48     static assert(isString!(T), "Only unicode strings allowed"); 
    49  
    50     T result; 
     165//TODO: speed optimalization 
     166T unescape(T)(T input) { 
     167//  static assert(isString!(T), "Only unicode strings allowed"); 
     168 
     169    uint pos; 
     170    Matcher m; 
     171    T result; 
     172    T seq; 
     173 
     174    while(!input.eos(pos)) { 
     175        m = scanEscapeSequence(input, pos); 
     176        if (cast(bool)m) { 
     177            result ~= input.get(pos); 
     178            seq = input.get(m.position - pos); 
     179 
     180            switch (seq[1]) { 
     181                //NOTE: is below interpretation of escape characters same as in DMD? 
     182                case 'x':   //2 hex digits 
     183                            result ~= cast(StorageElementType!(T))(toDec(seq[2])*16 + toDec(seq[3])); 
     184                            break; 
     185                case '0', '1', '2', '3', '4', '5', '6', '7' : //1 to 3 octal digits 
     186                            uint code; 
     187 
     188                            if (seq.length == 4) 
     189                                code = toDec(seq[1])*64 + toDec(seq[2])*8 +toDec(seq[3]); 
     190                            else 
     191                            if (seq.length == 3) 
     192                                code = toDec(seq[1])*8 +toDec(seq[2]); 
     193                            else 
     194                            if (seq.length == 2) 
     195                                code = toDec(seq[1]); 
     196 
     197                            if (code > maxsize[StorageElementType!(T).sizeof]) throw new UnescapeException("Octal representation out of character range!"); 
     198                            result ~= cast(StorageElementType!(T))code; 
     199                            break; 
     200                case 'u':   //4 hex digits 
     201                            result ~= cast(StorageElementType!(T))(toDec(seq[2])*16 + toDec(seq[3])); 
     202                            result ~= cast(StorageElementType!(T))(toDec(seq[4])*16 + toDec(seq[5])); 
     203                            break; 
     204                case 'U':   //8 hex digits 
     205                            result ~= cast(StorageElementType!(T))(toDec(seq[2])*16 + toDec(seq[3])); 
     206                            result ~= cast(StorageElementType!(T))(toDec(seq[4])*16 + toDec(seq[5])); 
     207                            result ~= cast(StorageElementType!(T))(toDec(seq[6])*16 + toDec(seq[7])); 
     208                            result ~= cast(StorageElementType!(T))(toDec(seq[8])*16 + toDec(seq[9])); 
     209                            break; 
     210                case '&':   //named character 
     211                            result ~= SequenceSet!(StorageType!(T)).namedchar.matching(m); 
     212                            break; 
     213                default:    //regular esc char 
     214                            result ~= SequenceSet!(StorageType!(T)).escchar.matching(m); 
     215                            break; 
     216            } 
     217 
     218            pos = 0; 
     219            continue; 
     220        } 
     221 
     222        if (m.status == Matcher.syntax_error || (m.status == Matcher.missing_input && m.position > pos)) 
     223            throw new UnescapeException("Unknown escape sequence!"); //TODO: lepsze komunikaty o błędach (ogólnie) 
     224        ++pos; 
     225    } 
     226 
     227    result ~= input.get(pos); 
     228 
     229    return result; 
     230
     231 
     232//------------------------------------------------------------------------------ 
     233 
     234T unescapeOld(T)(T input) { 
     235    //PoniÅŒsze jest 6,22 razy szybsze niÅŒ nowa implementacja 
     236    T result; 
    51237    bool isEscape=false; 
    52238 
    53     foreach(c; str) { 
     239    foreach(c; input) { 
    54240        if (isEscape==true) { 
    55241            switch (c) { 
     
    64250                case 't'  : result ~= '\t'; break; 
    65251                case 'v'  : result ~= '\v'; break; 
    66                 default: throw new UnescapeException("Illegal escape character"); 
     252                case '\\'  : result ~= '\\'; break; 
     253                default: throw new UnescapeException("Illegal escape character: \\" ~ c); 
    67254            } 
    68255            isEscape=false; 
     
    79266    return result; 
    80267} 
     268 
     269//------------------------------------------------------------------------------ 
     270 
     271unittest { testCase.repeat(1).execute("unescape basic characters", { 
     272    assert(unescape("\\\\"[]) == "\\"); 
     273    assert(unescape("\\\""[]) == "\""); 
     274    assert(unescape("\\?"[]) == "\?"); 
     275    assert(unescape("\\a"[]) == "\a"); 
     276    assert(unescape("\\b"[]) == "\b"); 
     277    assert(unescape("\\f"[]) == "\f"); 
     278    assert(unescape("\\n"[]) == "\n"); 
     279    assert(unescape("\\r"[]) == "\r"); 
     280    assert(unescape("\\t"[]) == "\t"); 
     281    assert(unescape("\\v"[]) == "\v"); 
     282 
     283    assert(unescape(r"\\\\\\\\ abc \\t\\n\\t \\t"[]) == r"\\\\ abc \t\n\t \t"); 
     284});} 
     285 
     286//------------------------------------------------------------------------------ 
     287 
     288unittest { testCase.repeat(1).execute("unescape stream wrapper", { 
     289    DummyStorage!(string) storage; 
     290 
     291    //storage.input = "\\\\"; assert(unescape(storage).output == "\\"); 
     292    assert(unescape("\\\""[]) == "\""); 
     293    assert(unescape("\\?"[]) == "\?"); 
     294    assert(unescape("\\a"[]) == "\a"); 
     295    assert(unescape("\\b"[]) == "\b"); 
     296    assert(unescape("\\f"[]) == "\f"); 
     297    assert(unescape("\\n"[]) == "\n"); 
     298    assert(unescape("\\r"[]) == "\r"); 
     299    assert(unescape("\\t"[]) == "\t"); 
     300    assert(unescape("\\v"[]) == "\v"); 
     301 
     302    assert(unescape(r"\\\\\\\\ abc \\t\\n\\t \\t"[]) == r"\\\\ abc \t\n\t \t"); 
     303});} 
     304 
     305//------------------------------------------------------------------------------ 
     306 
     307unittest { testCase.repeat(1).execute("unescape basic characters old implementation", { 
     308    assert(unescapeOld("\\\\"[]) == "\\"); 
     309    assert(unescapeOld("\\\""[]) == "\""); 
     310    assert(unescapeOld("\\?"[]) == "\?"); 
     311    assert(unescapeOld("\\a"[]) == "\a"); 
     312    assert(unescapeOld("\\b"[]) == "\b"); 
     313    assert(unescapeOld("\\f"[]) == "\f"); 
     314    assert(unescapeOld("\\n"[]) == "\n"); 
     315    assert(unescapeOld("\\r"[]) == "\r"); 
     316    assert(unescapeOld("\\t"[]) == "\t"); 
     317    assert(unescapeOld("\\v"[]) == "\v"); 
     318 
     319    assert(unescapeOld(r"\\\\\\\\ abc \\t\\n\\t \\t"[]) == r"\\\\ abc \t\n\t \t"); 
     320});} 
     321 
     322//------------------------------------------------------------------------------ 
     323 
     324unittest { testCase.execute("unescape extended characters", { 
     325    // 2 characters hexadecimal test (\x) 
     326    assert(unescape(r"\x41"[]) == "A"[]); 
     327    assert(unescape(r"\x41\x42\x43"[]) == "ABC"[]); 
     328 
     329    // 1-3 characters octal test (\ooo) 
     330    assert(unescape(r"\101"[]) == "A"[]); 
     331    assert(unescape(r"\101\102\103"[]) == "ABC"[]); 
     332    //Unknown escape sequence 
     333    assert(checkException!(UnescapeException)({unescape(r"\999"[]);})); 
     334    //Out of char range 
     335    assert(checkException!(UnescapeException)({unescape(r"\777"[]);})); 
     336    assert(unescape(r"\377"[]) == "\xff"); 
     337 
     338    //4 hex digits 
     339    assert(unescape(r"\u4142"[]) == "AB"[]); 
     340    assert(unescape(r"\uC582"[]) == "ł"[]); 
     341 
     342    //8 hex digits 
     343    assert(unescape(r"\U41424344"[]) == "ABCD"[]); 
     344 
     345    //named chars 
     346    assert(unescape(r"\""[]) == "\""); 
     347    assert(unescape(r"\©"[]) == "\©"); 
     348    assert(unescape(r"\Λ"[]) == "\Λ"); 
     349    assert(unescape(r"\♥"[]) == "\♥"); 
     350});} 
     351 
     352//------------------------------------------------------------------------------ 
     353 
     354unittest { testCase.execute("escape/unescape characters", { 
     355    string input; 
     356 
     357    input = r"\\\\ abc \t\n\t \t"; assert(unescape(escape(input)) == input); 
     358    input = r"\\d\te\\f"; assert(unescape(escape(input))==input); 
     359    input = r"\\g\r\t\nhi"; assert(unescape(escape(input))==input); 
     360    input = r"\\jk;lkds[]\tl"; assert(unescape(escape(input))==input); 
     361    input = r"\fmno"; assert(unescape(escape(input))==input); 
     362    input = r"\r\npqr"; assert(unescape(escape(input))==input); 
     363    input = r"\\stu"; assert(unescape(escape(input))==input); 
     364    input = r"\\vwq"; assert(unescape(escape(input))==input); 
     365    input = r"\\xyz"; assert(unescape(escape(input))==input); 
     366});} 
     367 
     368 
     369//------------------------------------------------------------------------------ 
     370 
     371unittest { 
     372    testSuite.finish; 
     373} 
  • trunk/doost/util/DUnit.d

    r32 r37  
    4242public: 
    4343    this(uint rwidth, Align aligning, string form="%s", uint border = 1) { 
     44        m_rwidth = rwidth; 
    4445        m_cwidth = rwidth; 
    4546        m_aligning = aligning; 
     
    8384private: 
    8485    uint m_cwidth; 
     86    uint m_rwidth; 
    8587    Align m_aligning; 
    8688    uint m_border; 
     
    187189            if (auto elem = cast(CellElem)e) { 
    188190                ccount++; 
    189                 if (elem.m_cwidth == -1) { 
     191                if (elem.m_rwidth == -1) { 
    190192                    if (dyncol !is null) throw new Exception("Only one column can have dynamic width"); 
    191193                    dyncol = elem; 
    192                 } else defwidth+=elem.m_cwidth; 
     194                } else defwidth+=elem.m_rwidth; 
    193195            } 
    194196        } 
     
    237239 
    238240//------------------------------------------------------------------------------ 
     241 
     242ulong rdtsc() { 
     243    asm 
     244    { 
     245        naked; 
     246        rdtsc; 
     247        ret; 
     248    } 
     249} 
    239250 
    240251struct TraceInfo { 
     
    280291        m_testname = testname; 
    281292        m_passed = false; 
    282         m_elapsedtime = real.nan
     293        m_elapsedtime = 0
    283294 
    284295        int no; 
     
    290301            m_number = m_owner.m_tccounter; 
    291302            try { 
    292                 d_time starttime = getUTCtime()
     303                long starttime = rdtsc
    293304                for(uint i = 0; i<m_repeat; i++) { 
    294305                    if (m_setup !is null) m_setup(); 
     
    296307                    if (m_teardown !is null) m_teardown(); 
    297308                } 
    298                 m_elapsedtime = (cast(real)(getUTCtime() - starttime))/1000
     309                m_elapsedtime = rdtsc - starttime
    299310                result = "OK"; 
    300311                m_passed = true; 
     
    306317                m_owner.m_tcfailed~=this; 
    307318                no = 0; 
     319                m_elapsedtime = 0; 
    308320            } 
    309321        } else result = "DISABLED"; 
     
    317329 
    318330        //BUG: przy sprawdzaniu nan is oraz !is powinno działać 
    319         if (!isNaN(m_elapsedtime)) m_owner.m_elapsedtime+=m_elapsedtime; 
     331        m_owner.m_elapsedtime+=m_elapsedtime; 
    320332    } 
    321333 
     
    378390    bool m_dotraces; 
    379391 
    380     real m_elapsedtime; 
     392    long m_elapsedtime; 
    381393    uint m_number; 
    382394    TestSuite m_owner; 
     
    449461 
    450462    void begin(string suitename) { 
     463 
    451464        m_suitename = suitename; 
     465        m_firstingroup=true; 
     466        m_elapsedtime=0; 
     467        m_curgroup = null; 
     468        m_testgroups = null; 
     469        m_curcase = null; 
     470        m_testcases = null; 
     471        m_tcfailed = null; 
    452472        m_tccounter = 0; 
    453473        m_tcfcounter = 0; 
    454         m_tcfailed = null; 
    455         m_elapsedtime=0; 
    456474 
    457475        renderer.render(hl); 
     
    490508        renderer.render(hl); 
    491509        renderer.render(simple); 
    492         renderer.render(etime,  "Statistics :", "Total time :", m_elapsedtime); 
     510        renderer.render(etime,  "Statistics :", "Total ticks :", m_elapsedtime); 
    493511        renderer.render(stat,  " -    all  :", m_tccounter); 
    494512        renderer.render(stat,  " - passed  :", tcpcounter, cast(double)(tcpcounter*100)/m_tccounter); 
     
    499517        renderer.render(empty); 
    500518 
     519        m_setup = null; 
     520        m_teardown = null; 
     521        m_dotiming = false; 
     522        m_dotraces = false; 
     523        m_reqtraces = false; 
     524        m_repeat = 1; 
    501525    } 
    502526 
     
    545569        title   = [Sep, Cell(-1, Align.Center), Sep]; 
    546570        tc      = [Sep, Cell(5, Align.Right, "%-s", 0), Cell(-1, Align.Left), Cell(7, Align.Right), Sep]; 
    547         tc_tim  = [Sep, Cell(5, Align.Right, "%-s", 0), Cell(-1, Align.Left), Cell(7, Align.Right), Sep, Cell(8, Align.Right), Sep, Cell(8, Align.Right, "%6.2f"), Sep]; 
     571        tc_tim  = [Sep, Cell(5, Align.Right, "%-s", 0), Cell(-1, Align.Left), Cell(7, Align.Right), Sep, Cell(7, Align.Right), Sep, Cell(10, Align.Right, "%d"), Sep]; 
    548572        simple  = [Sep, Cell(-1, Align.Left), Sep]; 
    549         etime   = [Sep, Cell(15, Align.Right), Cell(-1, Align.Right), Cell(10, Align.Left, "%6.4f s"), Sep]; 
     573        etime   = [Sep, Cell(15, Align.Right), Cell(-1, Align.Right), Cell(15, Align.Right, "%d"), Sep]; 
    550574        stat    = [Sep, Cell(15, Align.Right), Cell(6, Align.Left), Cell(-1, Align.Left, "(%6.2f %%)"), Sep]; 
    551575        fail    = [Sep, Cell(5, Align.Right, "%d."), Cell(-1, Align.Left), Sep]; 
     
    609633    TestGroup m_curgroup; 
    610634    TestGroup[] m_testgroups; 
    611     real m_elapsedtime=0; 
     635    long m_elapsedtime=0; 
    612636 
    613637    uint m_tccounter, m_tcfcounter; 
  • trunk/doost/util/serializer/Serializer.d

    r32 r37  
    1818import doost.api.Common; 
    1919import doost.core.Traits; 
     20import doost.storage.Storage; 
    2021import doost.util.serializer.Registry; 
    2122 
     
    8889 
    8990    enum Mode {LOAD, DUMP} 
    90     alias elementType!(STORAGE)[] STORAGETYPE; 
     91    alias StorageElementType!(STORAGE)    ELEMENTTYPE; 
     92    alias StorageType!(STORAGE)           STORAGETYPE; 
    9193 
    9294    mixin CONCRETEARCHIVE!(Archive); 
     
    104106    this() { 
    105107        m_archive = new Archive; 
    106         init(m_archive); 
     108        static if (is(typeof(init(Archive)) == bool)) { 
     109            init(m_archive); 
     110        } 
    107111    } 
    108112 
     
    143147 
    144148        archive.mode = Mode.DUMP; 
    145         archive.storage = STORAGE.init; 
    146149 
    147150        start(archive); 
     
    169172    VALUE load(VALUE)(STORAGE storage, Archive archive = null) { 
    170173        //TODO: static asserts in serializer --> check if all template functions exists in Archive 
    171  
    172174        if (archive is null) archive = m_archive.dup_info; 
    173175            else archive = archive.dup_info; 
     
    285287            "'. Types like void*, union, enum are not serializable without additional information"); 
    286288        } 
    287         //TODO: Unions - they are possible serializable, but probably only through 
     289        //TODO: Unions - they are possibly serializable, but probably only through 
    288290        //loadUdt/dumpUdt 
    289291    } 
     
    371373                } 
    372374            } else { 
    373                 //FIXME: 
    374375                static assert(false, "UDT '" ~ VALUE.stringof ~ "' is not serializable."); 
    375376            } 
  • trunk/doost/util/serializer/archive/JsonArchive.d

    r34 r37  
    3939    import doost.util.serializer.Registry; 
    4040    import doost.text.Escaper; 
    41     import doost.text.Tokenizer; 
    42  
    43     /******************************************************************************* 
    44      ******************************************************************************/ 
    45     static string generator(string name, string[] arr) { 
    46         assert(arr.length % 2 == 0, "For each pattern default must be given."); 
    47         string result = "static struct " ~ name ~ " {\n"; 
    48  
    49         string reset = "    static public void reset() {\n"; 
    50  
    51         string dupl = "    public typeof(*this) dup() {\n"; 
    52         dupl~=        "       typeof(*this) result;\n"; 
    53  
    54         for(int i=0; i<arr.length; i+=2 ) { 
    55             result~="    static public string " ~ arr[i] ~ " = `" ~ arr[i+1] ~ "`;\n"; 
    56             reset~= "       " ~ arr[i] ~ " = `" ~ arr[i+1] ~ "`;\n"; 
    57             dupl~=    "       result." ~ arr[i] ~ " = " ~ arr[i] ~ ".dup;\n"; 
    58         } 
    59  
    60         result~="\n"; 
    61         reset~="    }\n\n"; 
    62         dupl~="       return result; \n"; 
    63         dupl~=        "   }\n\n"; 
    64  
    65         result~= reset ~ dupl ~ "}\n"; 
    66         return result; 
    67     } 
     41    import doost.text.Scanner; 
    6842 
    6943    //------------------------------------------------------------------------------ 
    7044 
    71     //TODO: czy na pewno wystawiać na zewnÄ 
    72 trz typy proste? po co je zmieniać?? 
    73     mixin(generator("Pattern(T : long)", ["pattern", r"[\+|-]?\d\d*"])); 
    74     mixin(generator("Pattern(T : int)", ["pattern", r"[\+|-]?\d\d*"])); 
    75     mixin(generator("Pattern(T : short)", ["pattern", r"[\+|-]?\d\d*"])); 
    76     mixin(generator("Pattern(T : byte)", ["pattern", r"[\+|-]?\d\d*"])); 
    77     mixin(generator("Pattern(T : ulong)", ["pattern", r"\d\d*"])); 
    78     mixin(generator("Pattern(T : uint)", ["pattern", r"\d\d*"])); 
    79     mixin(generator("Pattern(T : ushort)", ["pattern", r"\d\d*"])); 
    80     mixin(generator("Pattern(T : ubyte)", ["pattern", r"\d\d*"])); 
    81  
    82     mixin(generator("Pattern(T : real)", ["pattern", r"nan|[\+|-]?\d\d*(\.\d\d*)?"])); 
    83     mixin(generator("Pattern(T : double)", ["pattern", r"nan|[\+|-]?\d\d*(\.\d\d*)?"])); 
    84     mixin(generator("Pattern(T : float)", ["pattern", r"nan|[\+|-]?\d\d*(\.\d\d*)?"])); 
    85  
    86     mixin(generator("Pattern(T : char)", ["pattern", r"."])); 
    87     mixin(generator("Pattern(T : wchar)", ["pattern", r"."])); 
    88     mixin(generator("Pattern(T : dchar)", ["pattern", r"."])); 
    89     mixin(generator("Pattern(T : bool)", ["positive", "true", "negative", "false"])); 
    90  
    91     //For other types: 
    92     mixin(generator("Pattern(T)", ["pattern", ""])); 
    93  
    94 //    mixin(generator("Skip", [ 
    95 //                            "skip", " \t\r\n", 
    96 //                            "space", " ", 
    97 //                            "newline", "\n", 
    98 //                            "indent", "    " 
    99 //                            ])); 
    100  
    101     static struct Skip { 
    102  
    103         static public string space = " "; 
    104         static public string newline = "\n"; 
    105         static public string indent = "    "; 
    106  
    107         static public string skip() { 
    108             return m_skip; 
    109         } 
    110  
    111         static public void skip(string s) { 
    112             m_skip = s; 
    113         } 
    114  
    115         static public CharClass!(char) skip_cc() { 
    116             if (m_skip_cc.empty) return m_skip_cc.whitespace; 
    117             return m_skip_cc; 
    118         } 
    119  
    120         static private CharClass!(char) m_skip_cc; 
    121         static public string m_skip = " \t\r\n"; 
    122     } 
    123  
    124  
    125     mixin(generator("Array", ["begin", "[", "separator", ",", "end", "]"])); 
    126     mixin(generator("String", ["delim1", "\"", "delim2", "'"])); 
    127     mixin(generator("Udt", [ 
    128                             "ver", "versionUdt", 
    129                             "begin", "{", 
    130                             "kvseparator", ":", 
    131                             "separator", ",", 
    132                             "end", "}" 
    133                             ])); 
    134  
    135     mixin(generator("Reference", ["p_null", "null", "p_ref", "$", "p_pointer", r"*", "s_null", "null", "s_ref", "$", "s_pointer", "*"])); 
     45    private static struct Skip { 
     46        static STORAGETYPE space = " "; 
     47        static STORAGETYPE newline = "\n"; 
     48        static STORAGETYPE indent = "    "; 
     49        static auto skip = CharClass!(ELEMENTTYPE).whitespace; 
     50    } 
     51 
     52    private static struct Bool { 
     53        static STORAGETYPE positive = "true"; 
     54        static STORAGETYPE negative = "false"; 
     55    } 
     56 
     57    private static struct String { 
     58        static auto delimiter = SequenceSet!(STORAGETYPE).strdelim; 
     59        static auto escdesc = &scanEscapeSequence!(STORAGE); 
     60        static auto allchars = CharClass!(ELEMENTTYPE).alphanum; 
     61        static auto midchars = CharClass!(ELEMENTTYPE).digit; 
     62        static ELEMENTTYPE sdelimiter = '"'; 
     63        static ELEMENTTYPE cdelimiter = '\''; 
     64    } 
     65 
     66    private static struct Region { 
     67        static auto begin = SequenceSet!(STORAGETYPE).openingbrackets; 
     68        static auto end = SequenceSet!(STORAGETYPE).closingbrackets; 
     69    } 
     70 
     71    private static struct Reference { 
     72        static STORAGETYPE defnull = "null"; 
     73        static ELEMENTTYPE defref = '$'; 
     74        static ELEMENTTYPE pointer = '*'; 
     75    } 
     76 
     77    private static struct Array { 
     78        static ELEMENTTYPE begin = '['; 
     79        static ELEMENTTYPE separator = ','; 
     80        static ELEMENTTYPE end = ']'; 
     81    } 
     82 
     83    private static struct Udt { 
     84        static STORAGETYPE ver = "versionUdt"; 
     85        static ELEMENTTYPE begin = '{'; 
     86        static ELEMENTTYPE kvseparator = ':'; 
     87        static ELEMENTTYPE separator = ','; 
     88        static ELEMENTTYPE end = '}'; 
     89    } 
    13690 
    13791    //-------------------------------------------------------------------------- 
     
    14296        uint indent = 0; 
    14397 
    144         //zawartość[nazwa pola
    145         STORAGETYPE[STORAGETYPE] memberStructFields;          //fields of specific class with values; 
     98        //fields of specific class with values: content[name of fields
     99        STORAGETYPE[STORAGETYPE] memberStructFields; 
    146100 
    147101        Archive dup_infoext() { 
     
    159113    static class TypeDescription(T) : Registration { 
    160114        mixin TypeDescriptionBase!(T) DEFAULT; 
    161         public Pattern!(T) def; 
    162115 
    163116        public typeof(this) dup_info() { 
    164117            typeof(this) result = DEFAULT.dup_info; 
    165             result.def = def.dup; 
    166118            return result; 
    167119        } 
     
    203155     **************************************************************************/ 
    204156    bool loadString(VALUE)(ref VALUE value, ARCHIVE archive) { 
    205         skip(archive.storage, Skip.skip_cc); 
    206  
    207         //FIXME: 
    208         CharClass!(char) delim; 
    209         delim.add(String.delim1[0]); 
    210         delim.add(String.delim2[0]); 
    211  
    212         auto pos = startsWithString(archive.storage, delim); 
    213         if (!pos) throw new ParsingException("Expected string/char in input, but it wasn't found."); 
    214  
    215         value = munch(archive.storage, pos); 
    216  
    217         if (value.length>1 && (value[0] == String.delim1[0] || value[0] == String.delim2[0] )) { 
    218             value = value[1..$-1]; 
    219             value = unescape(value); 
    220         } 
     157        skip(archive.storage, Skip.skip, uint.max); 
     158 
     159        auto m = scanString!(STORAGE)(archive.storage, String.delimiter, String.escdesc, String.allchars, String.midchars); 
     160        if (!cast(bool)m) 
     161            throw new ParsingException("Expected string or char in input, but it wasn't found."); 
     162 
     163        value = munch(archive.storage, m); 
     164 
     165        auto delim = munch(value, String.delimiter); 
     166        auto len = delim.length; 
     167 
     168        if (len>0) value = value[0..$-len]; 
     169 
     170        value = unescape(value); 
    221171 
    222172        return true; 
     
    226176     **************************************************************************/ 
    227177    bool dumpString(VALUE)(ref VALUE value, ARCHIVE archive) { 
    228         archive.storage.put( to!(STORAGETYPE)(String.delim1)
     178        archive.storage.put( String.sdelimiter
    229179                            to!(STORAGETYPE)(escape(value)) ~ 
    230                             to!(STORAGETYPE)(String.delim1)); 
    231         return true; 
    232     } 
    233  
    234     /*************************************************************************** 
    235      **************************************************************************/ 
    236     MatchPosition startsWithBool(ref STORAGE input) { 
    237         MatchPosition mp; 
    238  
    239         mp = starts(input, Pattern!(bool).positive); if (mp) return mp; 
    240         mp = starts(input, Pattern!(bool).negative); if (mp) return mp; 
    241  
    242         return mismatch
     180                            String.sdelimiter); 
     181        return true; 
     182    } 
     183 
     184    /*************************************************************************** 
     185     **************************************************************************/ 
     186    Matcher scanWithBool(ref STORAGE input) { 
     187        Matcher mp; 
     188 
     189        mp = scan(input, Bool.positive); if (cast(bool)mp) return mp; 
     190        mp = scan(input, Bool.negative); if (cast(bool)mp) return mp; 
     191 
     192        return Matcher(0, Matcher.mismatch)
    243193    } 
    244194 
     
    250200     **************************************************************************/ 
    251201    bool loadBool(VALUE)(ref VALUE value, ARCHIVE archive) { 
    252         skip(archive.storage, Skip.skip_cc); 
     202        skip(archive.storage, Skip.skip, uint.max); 
    253203        STORAGETYPE literal; 
    254204 
    255         if (auto mp = archive.storage.startsWithBool()) { 
     205        auto mp = archive.storage.scanWithBool(); 
     206        if (cast(bool)mp) { 
    256207            literal = munch(archive.storage, mp); 
    257208        } else throw new ParsingException("Unknown bool literal."); 
     
    269220     **************************************************************************/ 
    270221    bool dumpBool(VALUE)(ref VALUE value, ARCHIVE archive) { 
    271         archive.storage.put((value == true) ? Pattern!(bool).positive 
    272                             : Pattern!(bool).negative); 
     222        archive.storage.put((value == true) ? Bool.positive 
     223                            : Bool.negative); 
    273224        return true; 
    274225    } 
     
    277228     **************************************************************************/ 
    278229    bool loadNumber(VALUE)(ref VALUE value, ARCHIVE archive) { 
    279         skip(archive.storage, Skip.skip_cc); 
    280         auto pos = startsWithNumber(archive.storage); 
    281         if (!pos) throw new ParsingException("Expected number in source, but it wasn't found."); 
     230        skip(archive.storage, Skip.skip, uint.max); 
     231        auto pos = scanNumber(archive.storage); 
     232        if (!cast(bool)pos) throw new ParsingException("Expected number in source, but it wasn't found."); 
    282233 
    283234        value = to!(VALUE)(munch(archive.storage, pos)); 
     
    307258     **************************************************************************/ 
    308259    bool dumpChar(VALUE)(ref VALUE value, ARCHIVE archive) { 
    309         archive.storage.put(String.delim2 ~ value ~ String.delim2); 
    310         return true; 
    311     } 
    312  
    313     /*************************************************************************** 
    314      **************************************************************************/ 
    315     bool loadElement(VALUE)(ref VALUE value, string esep, ARCHIVE archive) { 
     260        archive.storage.put("" ~ String.cdelimiter ~ value ~ String.cdelimiter); 
     261        return true; 
     262    } 
     263 
     264    /*************************************************************************** 
     265     **************************************************************************/ 
     266    bool loadElement(VALUE, SEP)(ref VALUE value, SEP esep, ARCHIVE archive) { 
    316267        if (archive.mismatch) throw new ParsingException("Missing elements separator."); 
    317268        bool matched = traverse(value, archive); 
    318269        if (!matched) return false; 
    319270 
    320         skip(archive.storage, Skip.skip_cc); 
    321         archive.mismatch = !skip(archive.storage, new RegExp(esep)); 
    322         return true; 
    323     } 
    324  
    325     /*************************************************************************** 
    326      **************************************************************************/ 
    327     bool dumpElement(VALUE)(ref VALUE value, string sep, ARCHIVE archive) { 
     271        skip(archive.storage, Skip.skip, uint.max); 
     272        archive.mismatch = !skip(archive.storage, esep); 
     273        return true; 
     274    } 
     275 
     276    /*************************************************************************** 
     277     **************************************************************************/ 
     278    bool dumpElement(VALUE, SEP)(ref VALUE value, SEP sep, ARCHIVE archive) { 
    328279        archive.storage.put(archive.rest); 
    329280        bool res = traverse(value, archive); 
     
    335286     **************************************************************************/ 
    336287    bool loadArray(VALUE)(ref VALUE value, ARCHIVE archive) { 
    337         skip(archive.storage, Skip.skip_cc); 
     288        skip(archive.storage, Skip.skip, uint.max); 
    338289 
    339290        if (!skip(archive.storage, Array.begin)) 
     
    344295        archive.mismatch = false; 
    345296        do { 
    346             skip(archive.storage, Skip.skip_cc); 
     297            skip(archive.storage, Skip.skip, uint.max); 
    347298            if (skip(archive.storage, Array.end)) break; 
    348299            loadElement(elem, Array.separator, archive); 
     
    369320    /*************************************************************************** 
    370321     **************************************************************************/ 
    371     bool loadAssociativeElement(KEY, VALUE)(ref KEY key, ref VALUE value, string kvsep, string esep, ARCHIVE archive) { 
     322    bool loadAssociativeElement(KEY, VALUE, KVSEP, SEP)(ref KEY key, ref VALUE value, KVSEP kvsep, SEP esep, ARCHIVE archive) { 
    372323        if (archive.mismatch) throw new ParsingException("Missing associative elements separator."); 
    373324        bool matched = traverse(key, archive); 
    374325        if(!matched) return false; 
    375326 
    376         skip(archive.storage, Skip.skip_cc); 
     327        skip(archive.storage, Skip.skip, uint.max); 
    377328        if (!skip(archive.storage, kvsep)) 
    378329            throw new ParsingException("Missing associative array literal key-value separator."); 
     
    380331        traverse(value, archive); 
    381332 
    382         skip(archive.storage, Skip.skip_cc); 
    383         if (!skip(archive.storage, esep)) 
    384             archive.mismatch = true; 
     333        skip(archive.storage, Skip.skip, uint.max); 
     334        if (!skip(archive.storage, esep)) archive.mismatch = true; 
    385335 
    386336        return matched; 
     
    389339    /*************************************************************************** 
    390340     **************************************************************************/ 
    391     bool dumpAssociativeElement(KEY, VALUE)(ref KEY key, ref VALUE value, string kvsep, string esep, ARCHIVE archive) { 
     341    bool dumpAssociativeElement(KEY, VALUE, KVSEP, SEP)(ref KEY key, ref VALUE value, KVSEP kvsep, SEP esep, ARCHIVE archive) { 
    392342        archive.storage.put(archive.rest); 
    393343        traverse(key, archive); 
     
    404354        alias typeof(VALUE.init.keys[0]) KeyType; 
    405355 
    406         skip(archive.storage, Skip.skip_cc); 
     356        skip(archive.storage, Skip.skip, uint.max); 
    407357        if (!skip(archive.storage, Udt.begin)) 
    408358            throw new ParsingException("Missing associative array literal begining delimiter."); 
     
    414364        archive.mismatch = false; 
    415365        do { 
    416             skip(archive.storage, Skip.skip_cc); 
     366            skip(archive.storage, Skip.skip, uint.max); 
    417367            if (skip(archive.storage, Udt.end)) break; 
    418             loadAssociativeElement(key, val, Udt.kvsepar