コード例 #1
0
ファイル: JadeParser.cs プロジェクト: 0xFireball/IXML
        private CodePosition CalculateCodePosition(List <JadeToken> allTokens, JadeToken currentToken)
        {
            var precedingTokens = allTokens.Take(allTokens.Count - allTokens.IndexOf(currentToken));
            var precedingCode   = string.Concat(precedingTokens.Select(t => t.TextRepresentation + new string(' ', t.IndentationLevel) + '\n'));
            var precedingLines  = precedingCode.Split(' ');

            return(new CodePosition(precedingLines.Length + 1, 0));
        }
コード例 #2
0
ファイル: JadeParser.cs プロジェクト: 0xFireball/IXML
 /// <summary>
 /// Create a node based on the input JToken
 /// </summary>
 /// <param name="inputToken"></param>
 /// <returns></returns>
 private JNode CreateNodeFromJadeToken(JadeToken inputToken)
 {
     return(new JNode
     {
         Attributes = inputToken.Attributes,
         Classes = inputToken.Classes,
         Element = inputToken.NodeName,
         Id = inputToken.Id,
         IndentationLevel = inputToken.IndentationLevel,
         Value = inputToken.Value
     });
 }
コード例 #3
0
ファイル: JadeLexer.cs プロジェクト: 0xFireball/IXML
        public List <JadeToken> ReadCode(string input)
        {
            input = input.Strip(IgnoredCharacters) + "\n"; //Strip useless characters and add a trailing \n, as it simplifies lexing

            var rawTokens       = new Queue <RawToken>();  //a queue of raw tokens to be processed
            var codeLines       = input.Split('\n');
            var indentIndicator = InferIndentIndicator(codeLines);

            //Process indentation structure
            foreach (string line in codeLines)
            {
                //Read an indented token that has an indentation amount and a value not including the indent characters
                var indentedToken = ReadIndentedToken(line, indentIndicator);

                var lToken = new RawToken
                {
                    IndentLevel = indentedToken.Item1,
                    Value       = indentedToken.Item2
                };
                rawTokens.Enqueue(lToken);
            }
            //Create real Token objects based on the indentation structure
            var  jadeTokens          = new List <JadeToken>();
            bool multilineScope      = false; //whether we are in a multiline scope.
            int  multilineScopeStart = 0;
            int  previousIndentLevel = 0;

            foreach (var rawTok in rawTokens)
            {
                var processedTokValue = rawTok.Value;
                if (processedTokValue.StartsWith("//", StringComparison.CurrentCulture) || string.IsNullOrWhiteSpace(processedTokValue))
                {
                    continue;
                }
                if (multilineScope) //We're in a special area, normal rules don't apply
                {
                    if (rawTok.IndentLevel <= multilineScopeStart)
                    {
                        //The current indent level is less than where the multiline scope started
                        //Exit the multiline scope
                        multilineScope      = false;
                        multilineScopeStart = 0;
                    }
                    else
                    {
                        //We're still in the multiline scope.
                        //Edit the previous token.
                        //Grab the last token
                        var prevTok = jadeTokens.Last();

                        //Append the current token's value to the previous token, along with a whitespace character
                        prevTok.Value += rawTok.Value + " ";
                        continue;
                    }
                }

                //Normal node token
                //Look for indicators showing end of node name
                var nodeNameRegex = new Regex(@"(^\w+(?=(\.|#|\()))|(^\w+)", RegexOptions.Multiline | RegexOptions.IgnoreCase);
                var nodeNameMatch = nodeNameRegex.Match(processedTokValue); //Only match one
                //The match should have extracted the node name. If not, there is no node name.
                var nodeName = nodeNameMatch.Success ? nodeNameMatch.Value : null;
                //Don't remove the name yet, it will be used to verify later

                var    classes         = new List <string>();
                var    nodeAttributes  = new Dictionary <string, string>();
                string nodeIdAttribute = null; //none specified

                //Read attributes first, as they may contain characters that will trigger class and Id regexes

                //Look for an attribute group - looks like this: (attr="some value")
                var attributeGroupRegex = new Regex(@"\(([^\)]+)\)");
                var attributeGroupMatch = attributeGroupRegex.Match(processedTokValue);
                if (attributeGroupMatch.Success)
                {
                    //An attribute group was found!
                    var attributeGroupText = attributeGroupMatch.Value;
                    //Remove the opening ( and the closing )
                    attributeGroupText = attributeGroupText.Substring(1, attributeGroupText.Length - 2);
                    //Parse the attribute group
                    var attributeSeparatorRegex = new Regex(",(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)");
                    var nameValuePairs          = attributeSeparatorRegex.Split(attributeGroupText);

                    foreach (var nvp in nameValuePairs)
                    {
                        var nvpRegex       = new Regex("=(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)");
                        var components     = nvpRegex.Split(nvp);
                        var attributeName  = components[0];
                        var attributeValue = components[1];
                        //clean up attribute value
                        attributeValue = attributeValue.Eat("\"");                                                                               //Eat the beginning `"` character
                        attributeValue = attributeValue.Last() == '"' ? attributeValue.Substring(0, attributeValue.Length - 1) : attributeValue; //Strip ending quote
                        //Save the attribute
                        nodeAttributes.Add(attributeName, attributeValue);
                    }
                }
                processedTokValue = attributeGroupRegex.Replace(processedTokValue, ""); //Remove matched part of value

                //Attempt to read classes
                var classRegex   = new Regex(@"\.(\w|-)+");
                var classMatches = classRegex.Matches(processedTokValue);
                //Add matched class names to classes collection
                foreach (Match classMatch in classMatches)
                {
                    classes.Add(classMatch.Value);
                }
                processedTokValue = classRegex.Replace(processedTokValue, ""); //Remove matched part of value

                //Attempt to read id
                var idRegex = new Regex(@"\#(\w|-)+");
                var idMatch = idRegex.Match(processedTokValue);
                nodeIdAttribute   = idMatch.Success ? idMatch.Value : nodeIdAttribute;
                processedTokValue = idRegex.Replace(processedTokValue, "");           //Remove matched part of value

                if (processedTokValue.EndsWith(".", StringComparison.CurrentCulture)) //This token isn't ending yet
                {
                    processedTokValue   = processedTokValue.Substring(0, processedTokValue.Length - 1);
                    multilineScope      = true;
                    multilineScopeStart = rawTok.IndentLevel; //Where the multiline scope started
                }

                string remainingValue = processedTokValue;

                //If node name is empty, and there are classes or an Id, it's a div. There also shouldn't be any value.
                if (string.IsNullOrWhiteSpace(processedTokValue))
                {
                    //If the processed token value is empty, then the name must also be empty
                    //The name was not removed, but attribute sets, ids, and classes were removed.
                    //This, if the remaining content is empty, the name is empty.
                    //In HTML, an empty name indicates that the node is a div.
                    //processedTokValue = "div"; //This is HTML-specific though, so we will mark the node name null, as none was specified
                    nodeName = null;
                }
                else
                {
                    //Normal node, get the value now
                    //All that should be left now is the name and the value.
                    //Remove the name
                    remainingValue = nodeNameRegex.Replace(remainingValue, "");
                    //Strip any unecessary whitespace
                    remainingValue = remainingValue.Trim();

                    //If the remaining value is just empty, it's null, not set
                    if (string.IsNullOrWhiteSpace(remainingValue))
                    {
                        remainingValue = null;
                    }
                }

                if (string.IsNullOrWhiteSpace(remainingValue)) //If just whitespace, make it null
                {
                    remainingValue = null;
                }

                var jTok = new JadeToken(nodeName, classes, nodeIdAttribute, nodeAttributes, rawTok.IndentLevel);

                jadeTokens.Add(jTok);
                jTok.Value = remainingValue;
                jTok.TextRepresentation = rawTok.Value; //Store the raw text representation
                previousIndentLevel     = rawTok.IndentLevel;
            }
            return(jadeTokens); //TODO: update
        }