module dpegtest; import std.stdio; // PEG iterator for strings public class PegIter { public typedef int Pos; Pos pos; char[] string; public Pos getPos() { return pos; } public void setPos(Pos pos) { this.pos = pos; } public this(char[] string) { this.string = string; pos = 0; } public int current() { if(pos < string.length) { return string[pos]; } return -1; } public void next() { if(pos == string.length) { return; } ++pos; } char[] getString(Pos start, Pos stop) { return string[start..stop]; } } public struct Char(char ch) { static bool match(PegIter input) { debug writef(""); int cur = input.current(); if(cur == ch) { input.next(); return true; } return false; } } public struct Range(char lower, char upper) { static bool match(PegIter input) { debug writef(""); int cur = input.current(); if( (cur >= lower) && (cur <= upper) ) { input.next(); return true; } return false; } } public struct In(rules...) { static bool match(PegIter input) { debug writef(""); foreach(rule;rules) { if (rule.match(input)) { return true; } } return false; } } public struct For(alias Rule, int lower, int upper) { static bool match(PegIter input) { debug writef(""); PegIter.Pos start = input.getPos(); int i; for(i=0; i<=lower ;i++) { if( !Rule.match(input) ) { break; } } return (i >= lower) ? (true) : (input.setPos(start), false); } } public struct And(rules...) { static bool match(PegIter input) { debug writef(""); PegIter.Pos start = input.getPos(); foreach(rule;rules) { if (!rule.match(input)) { input.setPos(start); return false; } } return true; } } public struct Or(alias left, alias right) { static bool match(PegIter input) { debug writef(""); return (left.match(input) || right.match(input)); } } public struct Not(alias sub) { static bool match(PegIter input) { debug writef(""); PegIter.Pos start = input.getPos(); bool result = !sub.match(input); input.setPos(start); return result; } } public struct OptRepeat(alias sub) { static bool match(PegIter input) { debug writef(""); while(sub.match(input)) { } return true; } }; public struct PlusRepeat(alias sub) { static bool match(PegIter input) { debug writef(""); if(!sub.match(input)) { return false; } while(sub.match(input)) { } return true; } }; public struct Action(alias sub, alias dg) { static bool match(PegIter input) { debug writef(""); PegIter.Pos start = input.getPos(); if(sub.match(input)) { PegIter.Pos stop = input.getPos(); dg(input.getString(start, stop)); return true; } return false; } } /* Alpha:([A-Za-z]); */ alias In!( Range!('a', 'z'), Range!('A', 'Z') ) Alpha; /* AlphaNum:([A-Za-z0-9]); */ alias In!( Range!('a', 'z'), Range!('A', 'Z'), Range!('0', '9') ) AlphaNum; /* IdentifierStart:([a-zA-Z_]); */ alias In!( Range!('a', 'z'), Range!('A', 'Z'), Char!('_') ) IdentifierStart; /* IdentifierChar:([a-zA-Z0-9_]); */ alias In!( Range!('a', 'z'), Range!('A', 'Z'), Range!('0', '9'), Char!('_') ) IdentifierChar; /* Identifier:(IdentifierStart IdentifierChar*); */ alias And!( IdentifierStart, OptRepeat!( IdentifierChar ) ) Identifier; /* EmailChar:AlphaNum | [._%-]; */ alias Or!( AlphaNum, In!( Char!('.'), Char!('_'), Char!('%'), Char!('-') ) ) EmailChar; /* EmailSuffix:(Alpha{2,4} !EmailChar ); */ alias Action!( And!( For!(Alpha, 2, 4), Not!(EmailChar) ), delegate void(char[] suffix) { writefln(""); } ) EmailSuffix; /* Email:(EmailChar+ '@' ([a-zA-Z0-9_%-] | '.' !EmailSuffix)+ '.' EmailSuffix; */ alias Action!( And!( PlusRepeat!(EmailChar), Char!('@'), PlusRepeat!( And!( Or!( In!( Range!('a', 'z'), Range!('A', 'Z'), Range!('0', '9'), Char!('_'), Char!('%'), Char!('-') ), Char!('.') ), Not!(EmailSuffix) ) ), Char!('.'), EmailSuffix ), delegate void(char[] email) { writefln(""); } ) Email; bool matchesEmail() { auto PegIter input = new PegIter("test@test.com"); return Email.match(input); } void main() { if (matchesEmail()) { writefln("it matches"); } writefln("end"); }