static Token Scan(Buffer b, out bool error) { int startPosition = b.Position; char ch = b.GetCharacter(); error = false; // CASE 1: Next token is a separator character if (ch == OpenParenthesis) return new Token(Token.Kind.Open, "(", startPosition); else if (ch == ClosedParenthesis) return new Token(Token.Kind.Close, ")", startPosition); if (ch == OpenBracket) return new Token(Token.Kind.LBracket, "(", startPosition); else if (ch == ClosedBracket) return new Token(Token.Kind.RBracket, ")", startPosition); else if (ch == Comma) return new Token(Token.Kind.Comma, ",", startPosition); // CASE 2: Next token is a quoted string else if (ch == QuoteChar) { StringBuilder stringToken = new StringBuilder(); bool sawEscape = false; bool endOfString = false; while (!endOfString) { ch = b.GetCharacter(); if (ch == EOF) { error = true; return null; } else if (ch == Escape && !sawEscape) { sawEscape = true; } else if (sawEscape) // to do: add && IsEscapedChar(ch) { sawEscape = false; stringToken.Append(ch); } else if (ch == QuoteChar) { endOfString = true; } else { stringToken.Append(ch); } } return new Token(Token.Kind.String, stringToken.ToString(), startPosition); } // Case 3: Integer else if (Char.IsDigit(ch) || (ch == Minus && !b.IsDelimited() && Char.IsDigit(b.Peek()))) { StringBuilder intToken = new StringBuilder(); intToken.Append(ch); while (!b.IsDelimited()) { ch = b.GetCharacter(); if (Char.IsDigit(ch)) intToken.Append(ch); else { error = true; return null; } } return new Token(Token.Kind.Integer, intToken.ToString(), startPosition); } // Case 4: Function symbol else if (Char.IsLetterOrDigit(ch) || ch == AtSign) { StringBuilder symbolToken = new StringBuilder(); symbolToken.Append(ch); while (!b.IsDelimited()) { ch = b.GetCharacter(); if (Char.IsLetterOrDigit(ch) || ch == Underscore) symbolToken.Append(ch); else { error = true; return null; } } string str = symbolToken.ToString(); if (str == "true" || str == "false" || str == "True" || str == "False") return new Token(Token.Kind.Boolean, str, startPosition); else if (str == "null") return new Token(Token.Kind.Null, str, startPosition); else return new Token(Token.Kind.Symbol, str, startPosition); } // Case 5: wildcard else if (ch == Underscore && b.IsDelimited()) { return new Token(Token.Kind.Wildcard, new String(ch, 1), startPosition); } // Case 6: error else { error = true; return null; } }