예제 #1
0
파일: Lexer.cs 프로젝트: tcoats/Voodoo
        /// <summary>
        /// Enter with offset on the first character of the inner
        /// Leaves the token as EOF, or TagEnd
        /// </summary>
        /// <returns></returns>
        public IAction ScanInner()
        {
            var aggregate = new Aggregate();
            var start = _offset;
            while (_offset < _source.Length)
            {
                // stops for the end of file or {
                ForwardTag();

                if (_offset >= _source.Length)
                {
                    aggregate.Params.Add(
                        new Sequence(new List<IAction>()
                        {
                            new Constant(_source.Substring(start)),
                            new Render()
                        }));

                    return aggregate;
                }

                // any content we find is render content
                var contentSequence = new Sequence(new List<IAction>()
                {
                    new Constant(_source.Substring(start, _offset - start)),
                    new Render()
                });

                LexTag();

                // returning now might be okay if we're running inner only
                // it's up to the caller to make sure it ended correctly
                if (_token.type == TokenType.EOF)
                {
                    aggregate.Params.Add(contentSequence);
                    return aggregate;
                }

                if (_token.type != TokenType.TagOpen)
                {
                    ErrorAction("Expecting {");
                    return null;
                }

                LexTag();

                if (_token.type == TokenType.TagEnd)
                {
                    aggregate.Params.Add(contentSequence);
                    return aggregate;
                }

                var sequence = ScanBaseSequence();

                // newline found - must be javascript, ignore
                if (_token.type == TokenType.Newline)
                    continue;

                if (sequence == null)
                    return null;

                if (_token.type != TokenType.TagClose)
                {
                    ErrorAction("Expecting \"}\"");
                    return null;
                }

                var lastAction = sequence.Params.Last();
                if (!(lastAction is Each || lastAction is ICondition))
                    sequence.Params.Add(new Render());

                aggregate.Params.Add(contentSequence);
                aggregate.Params.Add(sequence);

                start = _offset;
            }
            return aggregate;
        }
예제 #2
0
파일: Lexer.cs 프로젝트: tcoats/Voodoo
        public IAction Scan()
        {
            if (_source == null)
                using (var sr = new StreamReader(FileSystem.GetFile(_location).Name))
                    _source = sr.ReadToEnd();

            var aggregate = new Aggregate();

            while (_offset < _source.Length)
            {
                // stops for the end of file or {
                ForwardTag();

                if (_offset >= _source.Length)
                    return aggregate;

                _offset++;

                var sequence = new Sequence();

                LexTag();

                if (_token.type == TokenType.Identifier)
                    sequence.Params.Add(new Constant(_token.value));
                else if (_token.type == TokenType.String)
                    sequence.Params.Add(new Constant(_token.value));
                else
                {
                    ErrorAction("Expecting a value (variable location, string, or number)");
                    return null;
                }

                LexTag();

                if (_token.type != TokenType.Separator)
                {
                    ErrorAction("Expecting a method name (this should be something like .Assign())");
                    return null;
                }

                LexTag();

                if (_token.type != TokenType.Identifier)
                {
                    ErrorAction("An operation must be defined (this should be something like .Assign())");
                    return null;
                }

                var functionName = _token.value;

                LexTag();

                if (_token.type != TokenType.ArgumentOpen)
                {
                    ErrorAction("Expecting \"(\"");
                    return null;
                }

                LexTag();

                if (_token.type != TokenType.ArgumentClose)
                {
                    Console.WriteLine("Expecting \")\"");
                    Console.WriteLine(PrintToken('!'));
                    return null;
                }

                LexTag();

                if (_token.type == TokenType.EOF)
                {
                    ErrorAction("Reached the end of file too soon, expecting more content");
                    return null;
                }

                if (_token.type == TokenType.Error)
                {
                    ErrorAction(_token.value);
                    return null;
                }

                //Newline found within tag (skipping tag)
                if (_token.type == TokenType.Newline)
                    continue;

                // _token.type should always equal TokenType.TagClose at this point
                if (_token.type != TokenType.TagClose)
                    throw new Exception("Unknown State\n" + PrintToken('!'));

                if (functionName == "Import")
                {
                    if (!File.Exists(_location))
                    {
                        ErrorAction("Import statement used and current location does not exist: " + _location);
                        return null;
                    }

                    if (!(sequence.Params[0] is Constant))
                    {
                        ErrorAction("Import statement requires a constant parameter");
                        return null;
                    }

                    // strip the filename off our path
                    var currentFile = new FileInfo(_location);
                    var pathToImport = ((Constant)sequence.Params[0]).Value.ToString();
                    var newPath = Path.Combine(currentFile.Directory.FullName, pathToImport);
                    // lex it
                    var lexer = new Lexer(newPath);
                    var result = lexer.Scan();
                    aggregate.Params.AddRange(result.Params);

                    continue;
                }

                var inner = ScanInner();
                if (inner == null)
                    return null;

                LexTag();

                if (_token.type != TokenType.Identifier || _token.value != functionName)
                {
                    ErrorAction("Expecting {/" + functionName + "}");
                    return null;
                }

                var func = ActionHandlers
                    .Where(p => p.Key.Type == ActionType.External
                        && p.Key.Identifier == functionName
                        && p.Key.HasParameter == false)
                    .Select(p => p.Value)
                    .FirstOrNull();

                if (func == null)
                {
                    ErrorAction("Unknown initial function");
                    return null;
                }

                var action = (IBlock)func();
                action.Content = inner;
                sequence.Params.Add(action);

                LexTag();

                if (_token.type != TokenType.TagClose)
                {
                    ErrorAction("Expecting \"}\"");
                    return null;
                }

                aggregate.Params.Add(sequence);
            }

            return aggregate;
        }