예제 #1
0
        /// <summary>
        /// Parse node contents add return a fresh node.
        /// </summary>
        /// <param name="parent">Node that this is a subnode to. Can be null</param>
        /// <param name="prototypes">A list with node types</param>
        /// <param name="line">Line to parse</param>
        /// <param name="offset">Where to start the parsing. Will be set to where the next node should start parsing</param>
        /// <returns>A node corresponding to the bla bla; null if parsing failed.</returns>
        /// <exception cref="CodeGeneratorException"></exception>
        public override Node Parse(NodeList prototypes, Node parent, LineInfo line, ref int offset)
        {
            if (offset > line.Data.Length - 1)
				throw new CodeGeneratorException(line.LineNumber, line.Data, "Tried to parse after end of line");

            if (line.Data[offset] != '%')
				throw new CodeGeneratorException(line.LineNumber, line.Data, "Not a tag node");

            int pos = -1;
            for (int i = offset + 1; i < line.Data.Length; ++i)
            {
                if (!char.IsLetterOrDigit(line.Data[i]))
                {
                    pos = i;
                    break;
                }
            }
            if (pos == -1)
                pos = line.Data.Length;

            TagNode node = (TagNode) prototypes.CreateNode("%", parent);
            node.Name = line.Data.Substring(offset + 1, pos - offset - 1);
			if (node._name == "br" || node._name == "input" || node._name == "style" || node._name == "img")
            {
                line.SelfClosed = true;
            	node.LineInfo = line;
                node.LineInfo.SelfClosed = true;
            }

            offset = pos;
            return node;
        }
예제 #2
0
        /// <summary>
        /// Parse node contents add return a fresh node.
        /// </summary>
        /// <param name="prototypes">List containing all node types</param>
        /// <param name="parent">Node that this is a subnode to. Can be null</param>
        /// <param name="line">Line to parse</param>
        /// <param name="offset">Where to start the parsing. Should be set to where the next node should start parsing.</param>
        /// <returns>A node corresponding to the bla bla; null if parsing failed.</returns>
        /// <exception cref="CodeGeneratorException"></exception>
        public override Node Parse(NodeList prototypes, Node parent, LineInfo line, ref int offset)
        {
            offset = line.Data.Length;
            return new DocTypeTag(
                @"<!DOCTYPE html PUBLIC ""-//W3C//DTD XHTML 1.0 Strict//EN"" ""http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"">".Replace("\"", "\"\""),
                parent);

        }
예제 #3
0
파일: TextNode.cs 프로젝트: kf6kjg/halcyon
        /// <summary>
        /// Parse node contents add return a fresh node.
        /// </summary>
        /// <param name="prototypes">List containing all node types</param>
        /// <param name="parent">Node that this is a subnode to. Can be null</param>
        /// <param name="line">Line to parse</param>
        /// <param name="offset">Where to start the parsing. Should be set to where the next node should start parsing.</param>
        /// <returns>A node corresponding to the bla bla; null if parsing failed.</returns>
        /// <exception cref="CodeGeneratorException"></exception>
        public override Node Parse(NodeList prototypes, Node parent, LineInfo line, ref int offset)
        {
            // text on tag rows are identified by a single space.
            if (parent != null && line.Data[offset] == ' ')
                ++offset;

            TextNode node = new TextNode(parent, line.Data.Substring(offset));
            if (parent == null)
                node.LineInfo = line;
            offset = line.Data.Length;
            return node;
        }
예제 #4
0
        /// <summary>
        /// Creates a DIV node and add's the specified node to it.
        /// </summary>
        /// <param name="prototypes">Contains all prototypes for each control char. used to instanciate new nodes.</param>
        /// <param name="parent">parent node</param>
        /// <param name="line">current line information</param>
        /// <param name="me">node to add to the DIV node</param>
        /// <returns>current node</returns>
        public Node AddMe(NodeList prototypes, Node parent, LineInfo line, Node me)
        {
            if (parent == null)
            {
                TagNode tag = (TagNode)prototypes.CreateNode("%", parent);
                tag.Name = "div";
                tag.LineInfo = line;
                tag.AddModifier(me);
                return tag;
            }

            return me;
        }
예제 #5
0
        /// <summary>
        /// Parse node contents add return a fresh node.
        /// </summary>
        /// <param name="prototypes">List containing all node types</param>
        /// <param name="parent">Node that this is a subnode to. Can be null</param>
        /// <param name="line">Line to parse</param>
        /// <param name="offset">Where to start the parsing. Should be set to where the next node should start parsing.</param>
        /// <returns>A node corresponding to the bla bla; null if parsing failed.</returns>
        /// <exception cref="CodeGeneratorException"></exception>
        public override Node Parse(NodeList prototypes, Node parent, LineInfo line, ref int offset)
        {
            if (offset > line.Data.Length)
				throw new CodeGeneratorException(line.LineNumber, line.Data, "Too little data");

            int pos = line.Data.Length;
            ++offset;
            string code = line.Data.Substring(offset, pos - offset);
            offset = pos;

            SilentCodeNode node = (SilentCodeNode) prototypes.CreateNode("-", parent);
            node._code = code;
            if (parent != null)
                node.LineInfo = line;
            return node;
        }
예제 #6
0
파일: IdNode.cs 프로젝트: kf6kjg/halcyon
        /// <summary>
        /// Parse node contents add return a fresh node.
        /// </summary>
        /// <param name="prototypes">List containing all node types</param>
        /// <param name="parent">Node that this is a subnode to. Can be null</param>
        /// <param name="line">Line to parse</param>
        /// <param name="offset">Where to start the parsing. Should be set to where the next node should start parsing.</param>
        /// <returns>A node corresponding to the bla bla; null if parsing failed.</returns>
        /// <exception cref="CodeGeneratorException"></exception>
        public override Node Parse(NodeList prototypes, Node parent, LineInfo line, ref int offset)
        {
            if (line.Data[offset] != '#')
                throw new CodeGeneratorException(line.LineNumber, line.Data, "Node is not an id node.");

            int endPos = GetEndPos(offset, line.Data);
            if (endPos == -1)
                endPos = line.Data.Length;

            ++offset;
            string id = line.Data.Substring(offset, endPos - offset);
            offset = endPos;

            IdNode node = (IdNode)prototypes.CreateNode("#", parent);
            node._id = id;
            return AddMe(prototypes, parent, line, node);
        }
예제 #7
0
        /// <summary>
        /// Parse node contents add return a fresh node.
        /// </summary>
        /// <param name="prototypes">List containing all node types</param>
        /// <param name="parent">Node that this is a subnode to. Can be null</param>
        /// <param name="line">Line to parse</param>
        /// <param name="offset">Where to start the parsing. Should be set to where the next node should start parsing.</param>
        /// <returns>A node corresponding to the bla bla; null if parsing failed.</returns>
        /// <exception cref="CodeGeneratorException"></exception>
        public override Node Parse(NodeList prototypes, Node parent, LineInfo line, ref int offset)
        {
            if (offset > line.Data.Length - 1)
                throw new CodeGeneratorException(line.LineNumber, line.Data, "Too little data");

            int pos = GetEndPos(offset, line.Data);
            if (pos == -1)
                pos = line.Data.Length;

            ++offset;
            string name = line.Data.Substring(offset, pos - offset);
            offset = pos;

            ClassNode node = (ClassNode) prototypes.CreateNode(".", parent);
            node._name = name;
            return AddMe(prototypes, parent, line, node);
        }
예제 #8
0
        public void TestPartial3()
        {
                        LineInfo line = new LineInfo(1, string.Empty);
            line.Set("%a{href=\"/settings/divert/remove/\", title=Language[\"RemoveDivert\"] }", 0, 0);

            TagNode tagNode = new TagNode(null);
            NodeList nodes = new NodeList();
            AttributeNode node = new AttributeNode(tagNode);
            nodes.Add(node);
            nodes.Add(tagNode);

            int offset = 2;
            AttributeNode myNode = (AttributeNode)node.Parse(nodes, tagNode, line, ref offset);

            bool inStr = true;
            string res = myNode.ToCode(ref inStr, false);

            //Assert.Equal("\"this\"+testCase.Id+\"id\"", myNode.GetAttribute("value").Value);
            //Assert.Equal("value=\"\"\"); sb.Append(\"this\"+testCase.Id+\"id\"); sb.Append(@\"\"\"", res);
        }
예제 #9
0
        public void TestPartial2()
        {
                        LineInfo line = new LineInfo(1, string.Empty);
            line.Set("%input{ value=\"http://\"+domain+\"/voicemail/listen/\" + item.Id }", 0, 0);

            TagNode tagNode = new TagNode(null);
            NodeList nodes = new NodeList();
            AttributeNode node = new AttributeNode(tagNode);
            nodes.Add(node);
            nodes.Add(tagNode);

            int offset = 6;
            AttributeNode myNode = (AttributeNode)node.Parse(nodes, tagNode, line, ref offset);

            bool inStr = true;
            string res = myNode.ToCode(ref inStr, false);

            Assert.Equal("\"this\"+testCase.Id+\"id\"", myNode.GetAttribute("value").Value);
            Assert.Equal("value=\"\"\"); sb.Append(\"this\"+testCase.Id+\"id\"); sb.Append(@\"\"\"", res);
        }
예제 #10
0
파일: LineInfo.cs 프로젝트: kf6kjg/halcyon
        /// <summary>
        /// Will check that all rule conditions have been met.
        /// Will also remove the rules if they are done.
        /// </summary>
        /// <param name="line"></param>
        /// <returns></returns>
        private bool CheckUnfinishedRule(LineInfo line)
        {
            if (_unfinishedRule != null)
            {
                // rule is done, remove it.
                // we can exit extra lines may have rules that are done too.
                if (!_unfinishedRule.IsMultiLine(line, false))
                    _unfinishedRule = null;
                else
                    return true;
            }

            bool res = false;
            foreach (LineInfo subLine in _extraLines)
            {
                if (subLine.CheckUnfinishedRule(line))
                    res = true;
            }

            return res;
        }
예제 #11
0
        public void Test()
        {
            LineInfo line = new LineInfo(1, string.Empty);
            line.Set("%input{ type=\"checkbox\", value=testCase.Id, name=\"case\", class=lastCat.Replace(' ', '-')}", 0,
                     0);

            TagNode tagNode = new TagNode(null);
            NodeList nodes = new NodeList();
            AttributeNode node = new AttributeNode(tagNode);
            nodes.Add(node);
            nodes.Add(tagNode);

            int offset = 6;
            AttributeNode myNode  = (AttributeNode)node.Parse(nodes, tagNode, line, ref offset);
            bool t = false;
            string temp = myNode.ToCode(ref t, false);
            Assert.Equal("\"checkbox\"", myNode.GetAttribute("type").Value);
            Assert.Equal("testCase.Id", myNode.GetAttribute("value").Value);
            Assert.Equal("\"case\"", myNode.GetAttribute("name").Value);
            Assert.Equal("lastCat.Replace(' ', '-')", myNode.GetAttribute("class").Value);
        }
예제 #12
0
        /// <summary>
        /// Parse node contents add return a fresh node.
        /// </summary>
        /// <param name="prototypes">List containing all node types</param>
        /// <param name="parent">Node that this is a subnode to. Can be null</param>
        /// <param name="line">Line to parse</param>
        /// <param name="offset">Where to start the parsing. Should be set to where the next node should start parsing.</param>
        /// <returns>A node corresponding to the bla bla; null if parsing failed.</returns>
        /// <exception cref="CodeGeneratorException"></exception>
        public override Node Parse(NodeList prototypes, Node parent, LineInfo line, ref int offset)
        {
            if (offset >= line.Data.Length)
                throw new CodeGeneratorException(line.LineNumber, line.Data, "Too little data");

            int pos = line.Data.Length;

            ++offset;
            string name = line.Data.Substring(offset, pos - offset);
            offset = pos;

            string trimmedData = line.Data.Trim();
            if (trimmedData.Length > 0 && trimmedData[trimmedData.Length-1] == ';')
                throw new CodeGeneratorException(line.LineNumber, line.Data, "Displayed code should not end with semicolon.");

            DisplayCodeNode node = (DisplayCodeNode)prototypes.CreateNode("=", parent);
            node._code = name;
            if (parent == null)
                node.LineInfo = line;
            return node;
        }
예제 #13
0
        /// <summary>
        /// Parse a node
        /// todo: improve doc
        /// </summary>
        /// <param name="theLine"></param>
        /// <param name="prototypes"></param>
        /// <param name="parent"></param>
        /// <param name="textNode"></param>
        protected static void ParseNode(LineInfo theLine, NodeList prototypes, Node parent, TextNode textNode)
        {
            Node curNode = null;
            int offset = 0;

            // parse each part of a line
            while (offset <= theLine.Data.Length - 1)
            {
                Node node = prototypes.GetPrototype(GetWord(theLine.Data, offset), curNode == null) ?? textNode;
                node = node.Parse(prototypes, curNode, theLine, ref offset);

                // first node on line, set it as current
                if (curNode == null)
                {
                    curNode = node;
                    curNode.LineInfo = theLine;
                    parent.Children.AddLast(node);
                }
                else
                    curNode.AddModifier(node); // append attributes etc.
            }

            foreach (LineInfo child in theLine.Children)
                ParseNode(child, prototypes, curNode, textNode);
        }
예제 #14
0
        /// <summary>
        /// PreParse goes through the text add handles indentation
        /// and all multi line cases.
        /// </summary>
        /// <param name="reader">Reader containing the text</param>
        protected void PreParse(TextReader reader)
        {
            if (reader == null)
                throw new ArgumentNullException("reader");

            // Read first line to be able to assign it to the mother.
            if (!ReadLine())
                throw new CodeGeneratorException(1, "No data.");

            if (_currentLine.Intendation != 0)
                throw new CodeGeneratorException(1, "Invalid indentation, should be 0.");
            _currentLine.Parent = _mother;
            CheckIntendation(_currentLine);
            CheckMultiLine(_prevLine, _currentLine);

            while (ReadLine())
            {
                if (_currentLine.UnparsedData.Length == 0)
                    continue;

                CheckIntendation(_currentLine);
                CheckMultiLine(_prevLine, _currentLine);
                if (_prevLine.AppendNextLine)
                {
                    _prevLine.Append(_currentLine);
					if(_currentLine.AppendNextLine)
						_prevLine.AppendNextLine = true;
                    _currentLine = _prevLine;
                    continue;
                }

                HandlePlacement();
            }
        }
예제 #15
0
        /// <summary>
        /// Parse node contents add return a fresh node.
        /// </summary>
        /// <param name="prototypes">List containing all node types</param>
        /// <param name="parent">Node that this is a subnode to. Can be null</param>
        /// <param name="line">Line to parse</param>
        /// <param name="offset">Where to start the parsing. Should be set to where the next node should start parsing.</param>
        /// <returns>A node corresponding to the bla bla; null if parsing failed.</returns>
        /// <exception cref="CodeGeneratorException"></exception>
        public override Node Parse(NodeList prototypes, Node parent, LineInfo line, ref int offset)
        {
            if (line.Data[offset] != '{')
                throw new CodeGeneratorException(line.LineNumber, line.Data, "Attribute cant handle info at char " + offset + 1);

            int endPos = GetEndPos(offset, line.Data, '}');
            if (endPos == -1)
                throw new CodeGeneratorException(line.LineNumber, line.Data, "Failed to find end of attribute list: '" + line.UnparsedData + "'.");

            List<Attribute> col = new List<Attribute>();
            string attributes = line.Data.Substring(offset + 1, endPos - offset - 1);
            ParseAttributes(line, attributes, col);
            offset = endPos + 1;


            AttributeNode node = (AttributeNode)prototypes.CreateNode("{", parent);
            node._attributes = col;
            return AddMe(prototypes, parent, line, node);
        }
예제 #16
0
        private static void ParseAttributes(LineInfo line, string attributes, List<Attribute> col)
        {
            bool inQuote = false;
            int parenthisCount = 0;
            string name = null;
            int start = -1;
            int step = 0; //0 = start of name, 1 = end of name, 2 = equal sign, 3 = start of value, 4 = end of value, 5 = comma
            for (int i = 0; i < attributes.Length; ++i)
            {
                char ch = attributes[i];

                if (ch == '"')
                {
                    inQuote = !inQuote;
                    if (inQuote && step == 3)
                    {
                        ++step;
                        start = i;
                    }
                }

                if (inQuote)
                    continue;

                if (ch == '(')
                    ++parenthisCount;
                if (ch == ')')
                    --parenthisCount;
                if (parenthisCount > 0)
                    continue;

                // find start of name
                if (step == 0)
                {
                    if (!char.IsWhiteSpace(ch))
                    {
                        start = i;
                        ++step;
                    }
                }
                    // find end of name
                else if (step == 1)
                {
                    if (char.IsWhiteSpace(ch) || ch == '=')
                    {
                        name = attributes.Substring(start, i - start);
                        start = -1;
                        ++step;
                    }
                }

                // find equal
                if (step == 2)
                {
                    if (ch == '=')
                        ++step;
                    continue;
                }

                // start of value
                if (step == 3)
                {
                    if (!char.IsWhiteSpace(ch))
                    {
                        start = i;
                        ++step;
                    }
                }

                    // end of value
                else if (step == 4)
                {
                    if (ch == ',')
                    {
                        AddAttribute(col, name, attributes.Substring(start, i - start).Trim());
                        start = -1;
                        ++step;
                    }
                }

                // find comma
                if (step == 5)
                {
                    if (ch == ',')
                        step = 0;

                    continue;
                }
            }

            if (step > 0 && step < 4)
                throw new CodeGeneratorException(line.LineNumber, line.Data, "Invalid attributes");

            if (step == 4)
                AddAttribute(col, name, attributes.Substring(start, attributes.Length - start));
        }
예제 #17
0
파일: LineInfo.cs 프로젝트: kf6kjg/halcyon
        /// <summary>
        /// Append another line
        /// </summary>
        /// <param name="line"></param>
        public void Append(LineInfo line)
        {
            SetParsedData(_data + line.Data);
            _extraLines.AddLast(line);

            if (CheckUnfinishedRule(this))
                _appendNextLine = true;
            else
                _appendNextLine = false;
        }
예제 #18
0
        /// <summary>
        /// Parse a file and convert into to our own template object code.
        /// </summary>
        /// <param name="reader">A <see cref="TextReader"/> containing our template</param>
        /// <exception cref="CodeGeneratorException">If something is incorrect in the template.</exception>
        public void Parse(TextReader reader)
        {
            _lineNo = -1;
            _reader = reader;
            _mother = new LineInfo(-1, string.Empty);
            _prevLine = null;
            _currentLine = null;

            PreParse(reader);

            NodeList prototypes = new NodeList();
            prototypes.Add(new AttributeNode(null));
            prototypes.Add(new TagNode(null));
            prototypes.Add(new IdNode(null));
            prototypes.Add(new SilentCodeNode(null));
            prototypes.Add(new ClassNode(null));
            prototypes.Add(new DisplayCodeNode(null));
            prototypes.Add(new DocTypeTag(null, null));
			prototypes.Add(new PartialNode(null));
            TextNode textNode = new TextNode(null, "prototype");
            _parentNode = new TextNode(null, string.Empty);

            foreach (LineInfo info in _mother.Children)
                ParseNode(info, prototypes, _parentNode, textNode);
        }
예제 #19
0
 /// <summary>
 /// Print line information to the console
 /// </summary>
 /// <param name="line"></param>
 public void PrintNode(LineInfo line)
 {
     _log.Write(this, LogPrio.Debug, Spaces(line.Intendation) + line.Data);
     foreach (LineInfo info in line.Children)
         PrintNode(info);
 }
예제 #20
0
        /// <summary>
        /// Read next line from file
        /// </summary>
        /// <returns>true if line could be read; false if EOF.</returns>
        protected bool ReadLine()
        {
            string line = _reader.ReadLine();
            string trimmedLine = (line != null) ? line.Trim(new char[] {' ', '\t'}) : string.Empty;

            while (line != null && (trimmedLine == string.Empty
                                    || (trimmedLine.Length > 0 && trimmedLine[0] == '-' && trimmedLine[1] == '/')
                                   ))
            {
                ++_lineNo;
                line = _reader.ReadLine();
                trimmedLine = (line != null) ? line.Trim(new char[] {' ', '\t'}) : string.Empty;
            }
            if (line == null)
                return false;

            ++_lineNo;
            _prevLine = _currentLine;
            _currentLine = new LineInfo(_lineNo, line);
            return true;
        }
예제 #21
0
 /// <summary>
 /// Parse node contents add return a fresh node.
 /// </summary>
 /// <param name="prototypes">List containing all node types</param>
 /// <param name="parent">Node that this is a subnode to. Can be null</param>
 /// <param name="line">Line to parse</param>
 /// <param name="offset">Where to start the parsing. Should be set to where the next node should start parsing.</param>
 /// <returns>A node corresponding to the bla bla; null if parsing failed.</returns>
 /// <exception cref="CodeGeneratorException"></exception>
 public abstract Node Parse(NodeList prototypes, Node parent, LineInfo line, ref int offset);
예제 #22
0
        /// <summary>
        /// Check indentation
        /// </summary>
        /// <param name="line">fills line with intend info</param>
        protected static void CheckIntendation(LineInfo line)
        {
            int ws, intendation;
            CheckIntendation(line, out ws, out intendation);
            if (ws == -1)
                throw new CodeGeneratorException(line.LineNumber, line.Data,
                                                 "Failed to find indentation on line #" + line.LineNumber);

            line.Set(ws, intendation);
        }
예제 #23
0
        /// <summary>
        /// check if current line is a multi line
        /// </summary>
        /// <param name="prevLine">previous line</param>
        /// <param name="line">current line</param>
        protected void CheckMultiLine(LineInfo prevLine, LineInfo line)
        {
            if (prevLine != null && prevLine.UnfinishedRule != null)
            {
                if (prevLine.UnfinishedRule.IsMultiLine(line, true))
                {
                    _log.Write(this, LogPrio.Trace, line.LineNumber + ": " + prevLine.UnfinishedRule.GetType().Name +
                                      " says that the next line should be appended.");
                    line.AppendNextLine = true;
                    return;
                }
            }

            foreach (Rule rule in _rules)
            {
                if (rule.IsMultiLine(line, false))
                {
                    _log.Write(this, LogPrio.Trace, line.LineNumber + ": " + rule.GetType().Name +
                                      " says that the next line should be appended.");
                    line.AppendNextLine = true;
                    continue;
                }
            }
        }
예제 #24
0
        /// <summary>
        /// Check and validate indentation
        /// </summary>
        /// <param name="line">line to check</param>
        /// <param name="ws">number of white spaces</param>
        /// <param name="intendation">number of indentations (2 white spaces = 1 intend, 1 tab = 1 intend)</param>
        protected static void CheckIntendation(LineInfo line, out int ws, out int intendation)
        {
            intendation = 0;
            ws          = -1;

            char prevUnusedCh = line.UnparsedData[0];

            if (prevUnusedCh == '\t')
            {
                ++intendation;
                prevUnusedCh = char.MinValue;
            }
            else if (prevUnusedCh != ' ')
            {
                ws = 0;
                return;
            }

            for (int i = 1; i < line.UnparsedData.Length; ++i)
            {
                char ch = line.UnparsedData[i];

                if (ch == ' ')
                {
                    if (prevUnusedCh == '\t')
                    {
                        ++intendation;
                        prevUnusedCh = ' ';
                        continue;
                    }
                    if (prevUnusedCh == ' ')
                    {
                        prevUnusedCh = char.MinValue;
                        ++intendation;
                        continue;
                    }

                    prevUnusedCh = ' ';
                }
                else if (ch == '\t')
                {
                    if (prevUnusedCh == ' ')
                    {
                        throw new CodeGeneratorException(line.LineNumber, line.Data,
                                                         "Invalid intendation sequence: One space + one tab. Should either be one tab or two spaces.");
                    }
                    if (prevUnusedCh == char.MinValue)
                    {
                        ++intendation;
                        prevUnusedCh = char.MinValue;
                        continue;
                    }
                }
                else
                {
                    if (prevUnusedCh != char.MinValue)
                    {
                        throw new CodeGeneratorException(line.LineNumber, line.Data,
                                                         "Invalid intendation at char " + i + ", expected a space.");
                    }

                    if (i == 1 && !char.IsWhiteSpace(line.UnparsedData[0]))
                    {
                        ws = 0;
                    }
                    else
                    {
                        ws = i;
                    }
                    return;
                }
            }
        }
예제 #25
0
        /// <summary>
        /// Check and validate indentation
        /// </summary>
        /// <param name="line">line to check</param>
        /// <param name="ws">number of white spaces</param>
        /// <param name="intendation">number of indentations (2 white spaces = 1 intend, 1 tab = 1 intend)</param>
        protected static void CheckIntendation(LineInfo line, out int ws, out int intendation)
        {
            intendation = 0;
            ws = -1;

            char prevUnusedCh = line.UnparsedData[0];
            if (prevUnusedCh == '\t')
            {
                ++intendation;
                prevUnusedCh = char.MinValue;
            }
            else if (prevUnusedCh != ' ')
            {
                ws = 0;
                return;
            }

            for (int i = 1; i < line.UnparsedData.Length; ++i)
            {
                char ch = line.UnparsedData[i];

                if (ch == ' ')
                {
                    if (prevUnusedCh == '\t')
                    {
                        ++intendation;
                        prevUnusedCh = ' ';
                        continue;
                    }
                    if (prevUnusedCh == ' ')
                    {
                        prevUnusedCh = char.MinValue;
                        ++intendation;
                        continue;
                    }
                    
                    prevUnusedCh = ' ';
                }
                else if (ch == '\t')
                {
                    if (prevUnusedCh == ' ')
                        throw new CodeGeneratorException(line.LineNumber, line.Data,
                                                         "Invalid intendation sequence: One space + one tab. Should either be one tab or two spaces.");
                    if (prevUnusedCh == char.MinValue)
                    {
                        ++intendation;
                        prevUnusedCh = char.MinValue;
                        continue;
                    }
                }
                else
                {
                    if (prevUnusedCh != char.MinValue)
                        throw new CodeGeneratorException(line.LineNumber, line.Data,
                                                         "Invalid intendation at char " + i + ", expected a space.");

                    if (i == 1 && !char.IsWhiteSpace(line.UnparsedData[0]))
                        ws = 0;
                    else
                        ws = i;
                    return;
                }
            }
        }