In case Flash no longer exists; a copy of this site is included in the Flashpoint archive's "ultimate" collection.

Dead Code Preservation :: Archived AS3 works from wonderfl.net

SequenceParser - Query Validator

Get Adobe Flash player
by jozefchutka 14 Oct 2011
    Embed
/**
 * Copyright jozefchutka ( http://wonderfl.net/user/jozefchutka )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/b3gd
 */

package 
{
    import flash.ui.Keyboard;
    import flash.events.KeyboardEvent;
    import flash.text.TextFieldType;
    import flash.text.TextField;
    import flash.display.Sprite;
    import flash.text.TextFormat;
    
    [SWF(width="465", height="465", frameRate="30", backgroundColor="#ffffff")]
    public class WonderflApp extends Sprite
    {
        private var textField:TextField = new TextField;
        private var textInput:TextField = new TextField;
        
        public function WonderflApp():void
        {
            textInput.width = stage.stageWidth - 1;
            textInput.height = 23;
            textInput.type = TextFieldType.INPUT;
            textInput.text = "a b    c anD b or     (c ed Or ((a) AND de*f) and andor)";
            textInput.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDown);
            textInput.border = true;
            addChild(textInput)

            textField.y = 25;
            textField.width = stage.stageWidth;
            textField.height = stage.stageHeight - 25;
            textField.wordWrap = true;
            textField.multiline = true;
            textField.defaultTextFormat = new TextFormat(null, 13);
            addChild(textField);
            
            parse();
        }
        
        private function onKeyDown(event:KeyboardEvent):void
        {
            if(event.keyCode == Keyboard.ENTER)
                parse();
        }

        
        private function parse():void
        {
            var input:String = textInput.text;
            var output:String;
            try
            {
                output = SimpleQueryParser.parse(input, expressionCallback);
            }
            catch(error:Error)
            {
                output = error.message;
            }
            textField.htmlText = output + 
                "\n\nupdate text input and hit enter.";
        }
        
        private function expressionCallback(value:String):String
        {
            return "<b><u>" + value + "</u></b>";
        }
    }
}

class SimpleQueryParser
{
    private var expression:String = "";
    private var expressionCallback:Function;
    private var pendingExpression:String = "";
    private var openedBrackets:uint = 0;
    private var isBracketStart:Boolean;
    private var isBracketEnd:Boolean;
    
    public static function parse(input:String, callback:Function=null):String
    {
        var parser:SimpleQueryParser = new SimpleQueryParser;
        parser.expressionCallback = callback;
        
        var sequences:Vector.<ISequence> = new Vector.<ISequence>;
        sequences.push(new StartStringEndStringSequence("(", ")", sequences, false, parser.bracketStart, parser.bracketEnd));
        sequences.push(new MatchRegexpSequence(/^and\b/i, false, parser.andCallback));
        sequences.push(new MatchRegexpSequence(/^or\b/i, false, parser.orCallback));
        sequences.push(new MatchRegexpSequence(/^[^\s\(\)]+/i, false, parser.anythingCallback));
        sequences.push(new MatchStringSequence(")", false, parser.unexpectedBracketEndCallback));
        sequences.push(new MatchAnythingSequence(false, parser.anythingCallback));
        
        SequenceParser.parse(input, sequences);
        parser.evaluatePendingExpression();
        if(parser.openedBrackets)
            throw new Error("Invalid expression. Missing " + parser.openedBrackets + " closing bracket(s).");
        return parser.expression;
    }
    
    private function evaluatePendingExpression():void
    {
        pendingExpression = pendingExpression.replace(/[\s]+/g, " ");
        pendingExpression = pendingExpression.replace(/^[\s]+/, "");
        pendingExpression = pendingExpression.replace(/[\s]+$/, "");
        if(pendingExpression && expressionCallback != null)
            append(expressionCallback(pendingExpression));
        else if(pendingExpression)
            append(pendingExpression);
        pendingExpression = "";
    }
    
    private function append(value:String):void
    {
        if(!expression 
            || expression.charAt(expression.length - 1) == "("
            || expression.charAt(expression.length - 1) == ")"
            || value == ")")
            expression += value;
        else
            expression += " " + value;
    }
    
    private function anythingCallback(value:String):void
    {
        if(!pendingExpression)
            value = value.replace(/^[\s]+/, "");
        pendingExpression += value;
        if(value)
            isBracketStart = isBracketEnd = false;
    }
    
    private function bracketStart(value:String):void
    {
        if(pendingExpression && !isBracketStart)
            throw new Error("Unexpected bracket start. Missing operator before opening bracket.");
        openedBrackets++;
        evaluatePendingExpression();
        append(value);
        isBracketStart = true;
        isBracketEnd = false;
    }
    
    private function bracketEnd(value:String):void
    {
        if(!pendingExpression && !isBracketEnd)
            throw new Error("Unexpected bracket end. Missing expression before closing bracket.");
        openedBrackets--;
        evaluatePendingExpression();
        append(value);
        isBracketStart = false;
        isBracketEnd = true;
    }
    
    private function andCallback(value:String):void
    {
        if(!pendingExpression && !isBracketEnd)
            throw new Error("Unexpected operator. Missing expression before operator.");
        evaluatePendingExpression();
        append(isBracketEnd ? " AND" : "AND");
        isBracketStart = isBracketEnd = false;
    }
    
    private function orCallback(value:String):void
    {
        if(!pendingExpression && !isBracketEnd)
            throw new Error("Unexpected operator. Missing expression before operator.");
        evaluatePendingExpression();
        append(isBracketEnd ? " OR" : "OR");
        isBracketStart = isBracketEnd = false;
    }
    
    private function unexpectedBracketEndCallback(value:String):void
    {
        throw new Error("Unexpected closing bracket. No bracket was opened.");
    }
}

class SequenceParser
{
    public static function parse(input:String, sequences:Vector.<ISequence>):String
    {
        if(input == null || !input.length 
            || !sequences || !sequences.length)
            return input;
        
        var source:String = input;
        var i:uint = 0;
        while(true)
        {
            var sequence:ISequence = sequences[i++];
            var match:String = sequence.test(source);
            if(match != null)
            {
                source = source.substr(match.length);
                source = parse(source, sequence.sequences);
                if(sequence.stopSequence)
                    break;
                i = 0;
            }
            else if(i == sequences.length)
                break;
        }
        
        if(source == input)
            throw new Error("Unmatching sequences");
        return source;
    }
}


interface ISequence
{
    function test(input:String):String
    function get sequences():Vector.<ISequence>
    function get stopSequence():Boolean
}

class StartStringEndStringSequence implements ISequence
{
    private var startSequence:MatchStringSequence;
    private var endSequence:MatchStringSequence;
    private var _sequences:Vector.<ISequence>;
    private var _stopSequence:Boolean;
    
    public function StartStringEndStringSequence(start:String, end:String,
        sequences:Vector.<ISequence> = null, stopSequence:Boolean = false,
        startCallback:Function = null, endCallback:Function = null)
    {
        startSequence = new MatchStringSequence(start, false, startCallback);
        endSequence = new MatchStringSequence(end, true, endCallback);
        _sequences = sequences;
        _stopSequence = stopSequence;
    }
    
    public function get sequences():Vector.<ISequence>
    {
        var result:Vector.<ISequence> = _sequences 
            ? _sequences.concat() : new Vector.<ISequence>;
        result.splice(0, 0, endSequence);
        return result;
    }
    
    public function test(input:String):String
    {
        return startSequence.test(input);
    }
    
    public function get stopSequence():Boolean
    {
        return _stopSequence;
    }
}

class MatchStringSequence implements ISequence
{
    private var match:String;
    private var _stopSequence:Boolean;
    private var matchCallback:Function;
    
    public function MatchStringSequence(match:String, 
        stopSequence:Boolean = false, matchCallback:Function = null)
    {
        this.match = match;
        _stopSequence = stopSequence;
        this.matchCallback = matchCallback;
    }
    
    public function test(input:String):String
    {
        if(input.substr(0, match.length) == match)
        {
            if(matchCallback != null)
                matchCallback(match);
            return match;
        }
        return null;
    }
    
    public function get sequences():Vector.<ISequence>
    {
        return null;
    }
    
    public function get stopSequence():Boolean
    {
        return _stopSequence;
    }
}

class MatchRegexpSequence implements ISequence
{
    private var match:RegExp;
    private var _stopSequence:Boolean;
    private var matchCallback:Function;
    
    public function MatchRegexpSequence(match:RegExp, 
        stopSequence:Boolean = false, matchCallback:Function = null)
    {
        this.match = match;
        _stopSequence = stopSequence;
        this.matchCallback = matchCallback;
    }
    
    public function test(input:String):String
    {
        var matches:Array = input.match(this.match);
        if(matches)
        {
            var match:String = matches[0];
            if(matchCallback != null)
                matchCallback(match);
            return match;
        }
        return null;
    }
    
    public function get sequences():Vector.<ISequence>
    {
        return null;
    }
    
    public function get stopSequence():Boolean
    {
        return _stopSequence;
    }
}

class MatchAnythingSequence implements ISequence
{
    private var _stopSequence:Boolean;
    private var matchCallback:Function;
    
    public function MatchAnythingSequence(stopSequence:Boolean = false, 
        matchCallback:Function = null)
    {
        _stopSequence = stopSequence;
        this.matchCallback = matchCallback;
    }
    
    public function test(input:String):String
    {
        if(input == null || !input.length)
            return null;
        
        var match:String = input.substr(0, 1);
        if(matchCallback != null)
            matchCallback(match);
        return match;
    }
    
    public function get sequences():Vector.<ISequence>
    {
        return null;
    }
    
    public function get stopSequence():Boolean
    {
        return _stopSequence;
    }
}