Ejemplo n.º 1
0
 private void endLineSoft()
 {
     if (currentLine.words.Count > 0)
     {
         var line = new SmeltLine(text.From(currentLine.words[0].Fragment.Start)
                                  .To(currentLine.words.Last().Fragment.End),
                                  currentLine.words.ToImmutableList());
         currentBlock.lines.Add(line);
         currentLine = new BuildingLine(currentBlock);
     }
 }
Ejemplo n.º 2
0
        internal SmeltFile Parse()
        {
            currentBlock = new BuildingBlock(0, null);
            currentLine  = new BuildingLine(currentBlock);

            while (index < sourceText.Length)
            {
                var ch = sourceText[index];
                switch (state)
                {
                case State.InLine:
                    if (ch == '{')
                    {
                        currentBlock = new BuildingBlock(index, currentLine);
                        currentLine  = new BuildingLine(currentBlock);
                    }
                    else if (ch == '[')
                    {
                        currentLiteral = new BuildingLiteral(index);
                        state          = State.InLiteral;
                    }
                    else if (ch == '#')
                    {
                        state = State.InComment;
                    }
                    else if (ch == ';')
                    {
                        // This is a 'hard' end of line, as opposed to endLineSoft()
                        // A semicolon always causes a line to actually exist, even if it's empty
                        // { } is a block with no lines in it, but { ; } is a block with one (empty) line in it.
                        // Similarly, { hello ; ; world } is a block with three lines in it (a line containing "hello", an empty line, and
                        // a line containing "world").
                        // The boundaries of the fragments look like this:
                        // { hello ; ; world ; } { is it ; me ; ; you're looking for }
                        //   ------- - -------     ------- ---- - ------------------
                        int start = currentLine.words.Count == 0 ? index : currentLine.words[0].Fragment.Start;
                        currentBlock.lines.Add(new SmeltLine(text.From(start).To(index), currentLine.words.ToImmutableList()));
                        currentLine = new BuildingLine(currentBlock);
                    }
                    else if (ch == '}')
                    {
                        endLineSoft();

                        if (currentBlock.inLine == null)
                        {
                            throw new ApplicationException("Close block that was not open");                                  // FIXME should be a parse exception using the line position
                        }
                        currentLine = currentBlock.inLine;
                        currentLine.words.Add(new SmeltBlock(text.From(currentBlock.start).To(index), currentBlock.lines.ToImmutableList()));
                        currentBlock = currentLine.inBlock;
                    }
                    else if (ch == ']')
                    {
                        throw new ApplicationException("Illegal character");     // FIXME Should error more usefully
                    }
                    else if (char.IsWhiteSpace(ch))
                    {
                        // do nothing
                    }
                    else
                    {
                        atomStart = index;
                        state     = State.InAtom;
                    }
                    break;

                case State.InComment:
                    if (ch == '\n' || ch == '\r')
                    {
                        state = State.InLine;
                    }
                    else
                    {
                        // do nothing, continue parsing the comment
                    }
                    break;

                case State.InLiteral:
                    if (ch == '[')
                    {
                        currentLiteral.fragmentTo(text, index);
                        state = State.InLiteralEscape;
                    }
                    else if (ch == ']')
                    {
                        currentLiteral.fragmentTo(text, index);
                        currentLine.words.Add(new SmeltLiteral(text.From(currentLiteral.start).To(index), currentLiteral.fragments.ToImmutableList()));
                        state = State.InLine;
                    }
                    else
                    {
                        // do nothing
                    }
                    break;

                case State.InLiteralEscape:
                    if (ch == '#')
                    {
                        state = State.InLiteralComment;
                    }
                    else if (ch == '[' || ch == ']')
                    {
                        state = State.InLiteral;
                    }
                    else
                    {
                        throw new ApplicationException("Unexpected escaped character");     // FIXME
                    }
                    break;

                case State.InLiteralComment:
                    if (ch == '\r' || ch == '\n')
                    {
                        currentLiteral.fragmentStart = index;
                        state = State.InLiteral;
                    }
                    else
                    {
                        // do nothing
                    }
                    break;

                case State.InAtom:
                    if (ch == '[' || ch == ']')
                    {
                        throw new ApplicationException("Illegal character");     // FIXME error more usefully
                    }
                    else if (ch == '{' || ch == '}' || ch == ';' || char.IsWhiteSpace(ch))
                    {
                        index--;
                        currentLine.words.Add(new SmeltAtom(text.From(atomStart).To(index)));
                        state = State.InLine;
                    }
                    else
                    {
                        // do nothing, continue parsing the atom
                    }
                    break;
                }
                index++;
            }

            switch (state)
            {
            case State.InAtom:
                currentLine.words.Add(new SmeltAtom(text.From(atomStart).To(index - 1)));
                break;

            case State.InLiteral:
            case State.InLiteralEscape:
                throw new ApplicationException("Unterminated string literal");     // FIXME
            }

            endLineSoft();

            if (currentBlock.inLine != null)
            {
                throw new ApplicationException("Unterminated block"); // FIXME
            }

            return(new SmeltFile(text, currentBlock.lines.ToImmutableList()));
        }
Ejemplo n.º 3
0
 internal BuildingBlock(int start, BuildingLine inLine)
 {
     this.start  = start;
     this.inLine = inLine;
 }