Code Cleanup

- Eliminated Lexer.
This commit is contained in:
Paul Beckingham 2011-07-26 00:37:49 -04:00
parent 0c08b29e48
commit 9bf1ec2f7c
8 changed files with 5 additions and 989 deletions

View file

@ -6,13 +6,10 @@ Deprecated Code
This is code that is going to be phased out "soon", and therefore is not This is code that is going to be phased out "soon", and therefore is not
worth fixing or documenting. worth fixing or documenting.
- Arguments.{h,cpp}
- Expression.{h,cpp}
- Variant.{h,cpp} - Variant.{h,cpp}
- Location.{h,cpp} - Location.{h,cpp}
- TDB.{h,cpp} - TDB.{h,cpp}
- Att.{h,cpp} - Att.{h,cpp}
- Lexer.{h,cpp}
New Code Needs New Code Needs
This is code that needs to be written, usually down at the C++ function level. This is code that needs to be written, usually down at the C++ function level.

View file

@ -19,7 +19,6 @@ set (task_SRCS A3.cpp A3.h
File.cpp File.h File.cpp File.h
Hooks.cpp Hooks.h Hooks.cpp Hooks.h
JSON.cpp JSON.h JSON.cpp JSON.h
Lexer.cpp Lexer.h
Location.cpp Location.h Location.cpp Location.h
Nibbler.cpp Nibbler.h Nibbler.cpp Nibbler.h
Path.cpp Path.h Path.cpp Path.h

View file

@ -1,374 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// taskwarrior - a command line task list manager.
//
// Copyright 2011, Paul Beckingham, Federico Hernandez.
// All rights reserved.
//
// This program is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free Software
// Foundation; either version 2 of the License, or (at your option) any later
// version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
// details.
//
// You should have received a copy of the GNU General Public License along with
// this program; if not, write to the
//
// Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor,
// Boston, MA
// 02110-1301
// USA
//
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
// This lexer works by breaking the input stream into tokens. The essence of
// the algorithm lies in the distinction between adjacent tokens, such that
// between the two extremes lies a good solution.
//
// At one extreme, the entire input is considered one token. Clearly this is
// only correct for trivial input. At the other extreme, every character of the
// input is a token. This is also wrong.
//
// If the input is as follows:
//
// It is almost 11:00am.
//
// The desired tokenization is:
//
// It
// <space>
// is
// <space>
// almost
// <space>
// 11
// :
// 00
// am
// .
// \n
//
// This can be achieved by allowing transitions to denote token boundaries.
// Given the following character classes:
//
// letter: a-z A-Z
// digit: 0-9
// whitespace: <space> <tab> <newline> <cr> <lf> <vertical-tab>
// other: Everything else
//
// Then a token boundary is a transition between:
// letter -> !letter
// digit -> !digit
// whitespace -> any
// other -> any
//
// This has the effect of allowing groups of consecutive letters to be
// considered one token, as well as groups of digits.
//
////////////////////////////////////////////////////////////////////////////////
#include <iostream>
#include <util.h>
#include <Lexer.h>
static const int other = -1;
static const int alpha = -2;
static const int digit = -3;
static const int white = -4;
static const int quote = -5;
////////////////////////////////////////////////////////////////////////////////
Lexer::Lexer (const std::string& input)
: mInput (input)
, mAlpha ("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
, mDigit ("0123456789")
, mQuote ("'\"")
, mWhite (" \t\n\r\f")
, mAlphaCoalesce (true)
, mDigitCoalesce (true)
, mQuotedCoalesce (false)
, mWhiteCoalesce (false)
, mSkipWhitespace (false)
{
}
////////////////////////////////////////////////////////////////////////////////
void Lexer::tokenize (std::vector <std::string>& all)
{
all.clear (); // Prevent repeated accumulation.
std::string token;
bool inQuote = false;
char quoteChar = '\0';
for (unsigned int i = 0; i < mInput.length (); ++i)
{
bool specialFound = false;
for (unsigned int s = 0; s < mSpecialTokens.size (); ++s)
{
std::string potential = mInput.substr (
i, min (mSpecialTokens[s].length (), mInput.length () - i));
if (potential == mSpecialTokens[s])
{
// Capture currently assembled token, the special token, increment over
// that token, and skip all remaining code in the loop.
if (token.length ())
{
all.push_back (token);
token = "";
}
all.push_back (potential);
i += potential.length () - 1;
specialFound = true;
}
}
if (specialFound)
continue;
char c = mInput[i];
char next = '\0';
if (i < mInput.length () - 1)
next = mInput[i + 1];
// Classify current and next characters.
int thisChar = classify (c);
int nextChar = classify (next);
// Properly set inQuote, quoteChar.
if (!inQuote && thisChar == quote)
{
quoteChar = c;
inQuote = true;
}
else if (inQuote && c == quoteChar)
{
inQuote = false;
}
// Detect transitions.
bool transition = false;
if (thisChar != nextChar)
transition = true;
token += c;
// Transitions mean new token. All 'other' characters are separate tokens.
if (transition || nextChar == other)
{
if (!inQuote || !mQuotedCoalesce)
{
if (!mSkipWhitespace || thisChar != white)
all.push_back (token);
token = "";
}
}
// Non-transitions - runs.
else
{
// Runs may be optionally coalesced.
if (!(mAlphaCoalesce && nextChar == alpha) &&
!(mDigitCoalesce && nextChar == digit) &&
!(mWhiteCoalesce && nextChar == white))
{
if (!inQuote || !mQuotedCoalesce)
{
if (!mSkipWhitespace || thisChar != white)
all.push_back (token);
token = "";
}
}
}
}
}
////////////////////////////////////////////////////////////////////////////////
void Lexer::categorizeAsAlpha (char value)
{
if (mAlpha.find (value) == std::string::npos)
mAlpha += value;
std::string::size_type pos;
if ((pos = mDigit.find (value)) != std::string::npos) mDigit.erase (pos, 1);
if ((pos = mQuote.find (value)) != std::string::npos) mQuote.erase (pos, 1);
if ((pos = mWhite.find (value)) != std::string::npos) mWhite.erase (pos, 1);
}
////////////////////////////////////////////////////////////////////////////////
void Lexer::ignoreAsAlpha (char value)
{
std::string::size_type pos;
if ((pos = mAlpha.find (value)) != std::string::npos) mAlpha.erase (pos, 1);
}
////////////////////////////////////////////////////////////////////////////////
void Lexer::setAlpha (const std::string& value)
{
mAlpha = value;
std::string::size_type pos;
for (unsigned int i = 0; i < mAlpha.length (); ++i)
{
if ((pos = mDigit.find (mAlpha[i])) != std::string::npos) mDigit.erase (pos, 1);
if ((pos = mQuote.find (mAlpha[i])) != std::string::npos) mQuote.erase (pos, 1);
if ((pos = mWhite.find (mAlpha[i])) != std::string::npos) mWhite.erase (pos, 1);
}
}
////////////////////////////////////////////////////////////////////////////////
void Lexer::categorizeAsDigit (char value)
{
if (mDigit.find (value) == std::string::npos)
mDigit += value;
std::string::size_type pos;
if ((pos = mAlpha.find (value)) != std::string::npos) mAlpha.erase (pos, 1);
if ((pos = mQuote.find (value)) != std::string::npos) mQuote.erase (pos, 1);
if ((pos = mWhite.find (value)) != std::string::npos) mWhite.erase (pos, 1);
}
////////////////////////////////////////////////////////////////////////////////
void Lexer::ignoreAsDigit (char value)
{
std::string::size_type pos;
if ((pos = mDigit.find (value)) != std::string::npos) mDigit.erase (pos, 1);
}
////////////////////////////////////////////////////////////////////////////////
void Lexer::setDigit (const std::string& value)
{
mDigit = value;
std::string::size_type pos;
for (unsigned int i = 0; i < mDigit.length (); ++i)
{
if ((pos = mAlpha.find (mDigit[i])) != std::string::npos) mAlpha.erase (pos, 1);
if ((pos = mQuote.find (mDigit[i])) != std::string::npos) mQuote.erase (pos, 1);
if ((pos = mWhite.find (mDigit[i])) != std::string::npos) mWhite.erase (pos, 1);
}
}
////////////////////////////////////////////////////////////////////////////////
void Lexer::categorizeAsQuote (char value)
{
if (mQuote.find (value) == std::string::npos)
mQuote += value;
std::string::size_type pos;
if ((pos = mAlpha.find (value)) != std::string::npos) mAlpha.erase (pos, 1);
if ((pos = mDigit.find (value)) != std::string::npos) mDigit.erase (pos, 1);
if ((pos = mWhite.find (value)) != std::string::npos) mWhite.erase (pos, 1);
}
////////////////////////////////////////////////////////////////////////////////
void Lexer::ignoreAsQuote (char value)
{
std::string::size_type pos;
if ((pos = mQuote.find (value)) != std::string::npos) mQuote.erase (pos, 1);
}
////////////////////////////////////////////////////////////////////////////////
void Lexer::setQuote (const std::string& value)
{
mQuote = value;
std::string::size_type pos;
for (unsigned int i = 0; i < mQuote.length (); ++i)
{
if ((pos = mAlpha.find (mQuote[i])) != std::string::npos) mAlpha.erase (pos, 1);
if ((pos = mDigit.find (mQuote[i])) != std::string::npos) mDigit.erase (pos, 1);
if ((pos = mWhite.find (mQuote[i])) != std::string::npos) mWhite.erase (pos, 1);
}
}
////////////////////////////////////////////////////////////////////////////////
void Lexer::categorizeAsWhite (char value)
{
if (mWhite.find (value) == std::string::npos)
mWhite += value;
std::string::size_type pos;
if ((pos = mAlpha.find (value)) != std::string::npos) mAlpha.erase (pos, 1);
if ((pos = mDigit.find (value)) != std::string::npos) mDigit.erase (pos, 1);
if ((pos = mQuote.find (value)) != std::string::npos) mQuote.erase (pos, 1);
}
////////////////////////////////////////////////////////////////////////////////
void Lexer::ignoreAsWhite (char value)
{
std::string::size_type pos;
if ((pos = mWhite.find (value)) != std::string::npos) mWhite.erase (pos, 1);
}
////////////////////////////////////////////////////////////////////////////////
void Lexer::setWhite (const std::string& value)
{
mWhite = value;
std::string::size_type pos;
for (unsigned int i = 0; i < mWhite.length (); ++i)
{
if ((pos = mAlpha.find (mWhite[i])) != std::string::npos) mAlpha.erase (pos, 1);
if ((pos = mDigit.find (mWhite[i])) != std::string::npos) mDigit.erase (pos, 1);
if ((pos = mQuote.find (mWhite[i])) != std::string::npos) mQuote.erase (pos, 1);
}
}
////////////////////////////////////////////////////////////////////////////////
void Lexer::coalesceAlpha (bool value)
{
mAlphaCoalesce = value;
}
////////////////////////////////////////////////////////////////////////////////
void Lexer::coalesceDigits (bool value)
{
mDigitCoalesce = value;
}
////////////////////////////////////////////////////////////////////////////////
void Lexer::coalesceQuoted (bool value)
{
mQuotedCoalesce = value;
}
////////////////////////////////////////////////////////////////////////////////
void Lexer::coalesceWhite (bool value)
{
mWhiteCoalesce = value;
}
////////////////////////////////////////////////////////////////////////////////
void Lexer::skipWhitespace (bool value)
{
mSkipWhitespace = value;
}
////////////////////////////////////////////////////////////////////////////////
void Lexer::specialToken (const std::string& special)
{
mSpecialTokens.push_back (special);
}
////////////////////////////////////////////////////////////////////////////////
int Lexer::classify (char c)
{
if (mAlpha.find (c) != std::string::npos) return alpha;
if (mDigit.find (c) != std::string::npos) return digit;
if (mWhite.find (c) != std::string::npos) return white;
if (mQuote.find (c) != std::string::npos) return quote;
return other;
}
////////////////////////////////////////////////////////////////////////////////

View file

@ -1,84 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// taskwarrior - a command line task list manager.
//
// Copyright 2011, Paul Beckingham, Federico Hernandez.
// All rights reserved.
//
// This program is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free Software
// Foundation; either version 2 of the License, or (at your option) any later
// version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
// details.
//
// You should have received a copy of the GNU General Public License along with
// this program; if not, write to the
//
// Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor,
// Boston, MA
// 02110-1301
// USA
//
////////////////////////////////////////////////////////////////////////////////
#ifndef INCLUDED_LEXER
#define INCLUDED_LEXER
#include <vector>
#include <string>
class Lexer
{
public:
Lexer (const std::string&);
void tokenize (std::vector <std::string>&);
void categorizeAsAlpha (char);
void ignoreAsAlpha (char);
void setAlpha (const std::string&);
void categorizeAsDigit (char);
void ignoreAsDigit (char);
void setDigit (const std::string&);
void categorizeAsQuote (char);
void ignoreAsQuote (char);
void setQuote (const std::string&);
void categorizeAsWhite (char);
void ignoreAsWhite (char);
void setWhite (const std::string&);
void coalesceAlpha (bool);
void coalesceDigits (bool);
void coalesceQuoted (bool);
void coalesceWhite (bool);
void skipWhitespace (bool);
void specialToken (const std::string&);
private:
int classify (char);
std::string mInput;
std::string mAlpha;
std::string mDigit;
std::string mQuote;
std::string mWhite;
bool mAlphaCoalesce;
bool mDigitCoalesce;
bool mQuotedCoalesce;
bool mWhiteCoalesce;
bool mSkipWhitespace;
std::vector <std::string> mSpecialTokens;
};
#endif
////////////////////////////////////////////////////////////////////////////////

View file

@ -6,11 +6,10 @@ include_directories (${CMAKE_SOURCE_DIR}
${CMAKE_SOURCE_DIR}/test ${CMAKE_SOURCE_DIR}/test
${TASK_INCLUDE_DIRS}) ${TASK_INCLUDE_DIRS})
set (test_SRCS arguments.t att.t autocomplete.t color.t config.t date.t set (test_SRCS att.t autocomplete.t color.t config.t date.t directory.t dom.t
directory.t dom.t duration.t file.t i18n.t json.t lexer.t list.t duration.t file.t i18n.t json.t list.t nibbler.t path.t record.t
nibbler.t path.t record.t rx.t t.benchmark.t t.t taskmod.t tdb.t rx.t t.benchmark.t t.t taskmod.t tdb.t tdb2.t text.t uri.t util.t
tdb2.t text.t uri.t util.t variant.t view.t variant.t view.t json_test)
json_test)
add_custom_target (test ./run_all DEPENDS ${test_SRCS} add_custom_target (test ./run_all DEPENDS ${test_SRCS}
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/test) WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/test)

View file

@ -1,190 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// taskwarrior - a command line task list manager.
//
// Copyright 2006 - 2011, Paul Beckingham, Federico Hernandez.
// All rights reserved.
//
// This program is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free Software
// Foundation; either version 2 of the License, or (at your option) any later
// version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
// details.
//
// You should have received a copy of the GNU General Public License along with
// this program; if not, write to the
//
// Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor,
// Boston, MA
// 02110-1301
// USA
//
////////////////////////////////////////////////////////////////////////////////
#include <Context.h>
#include <Arguments.h>
#include <text.h>
#include <test.h>
Context context;
////////////////////////////////////////////////////////////////////////////////
int main (int argc, char** argv)
{
UnitTest t (95);
const char* fake[] =
{
// task list proj:foo 1,3,5-10 12 pattern1 rc.name1=value1 rc.name2:value2 \
// 234 -- pattern2 n:v
"task", // context.program
"list", // command
"proj:foo", // n:v
"1,3,5-10", // sequence
"12", // sequence
"pattern1", // text
"rc.name1=value1", // n:v
"rc.name2:value2", // n:v
"234", // text
"--", // terminator
"pattern2", // text
"n:v", // text (due to terminator)
};
// void capture (int, char**);
Arguments a1;
a1.capture (12, &fake[0]);
t.is (a1.size (), (size_t)12, "12 arguments expected");
// std::string combine ();
t.is (a1.combine (),
"task list proj:foo 1,3,5-10 12 pattern1 rc.name1=value1 rc.name2:value2 "
"234 -- pattern2 n:v",
"combine good");
// bool is_attr (const std::string&);
t.ok (Arguments::is_attr ("project:"), "name: -> attr");
t.ok (Arguments::is_attr ("project:\"\""), "name:\"\" -> attr");
t.ok (Arguments::is_attr ("project:one"), "name:one -> attr");
t.ok (Arguments::is_attr ("project:\"one\""), "name:\"one\" -> attr");
t.ok (Arguments::is_attr ("project:\"one two\""), "name:\"one two\" -> attr");
t.notok (Arguments::is_attr ("name"), "name -> not attr");
t.notok (Arguments::is_attr ("(name=val and 1<2)"), "(name=val and 1<2) -> not attr");
// bool is_attmod (const std::string&);
t.ok (Arguments::is_attmod ("project.is:"), "name.is: -> attmod");
t.ok (Arguments::is_attmod ("project.is:\"\""), "name.is:\"\" -> attmod");
t.ok (Arguments::is_attmod ("project.is:one"), "name.is:one -> attmod");
t.ok (Arguments::is_attmod ("project.is:\"one\""), "name.is:\"one\" -> attmod");
t.ok (Arguments::is_attmod ("project.is:\"one two\""), "name.is:\"one two\" -> attmod");
t.notok (Arguments::is_attmod ("name"), "name -> not attmod");
t.notok (Arguments::is_attmod ("(name=value and 1<2"), "(name=value and 1<2 -> not attmod");
// bool is_subst (const std::string&);
t.notok (Arguments::is_subst ("///"), "/// -> not subst");
t.notok (Arguments::is_subst ("//to/"), "//to/ -> not subst");
t.ok (Arguments::is_subst ("/from//"), "/from// -> subst");
t.ok (Arguments::is_subst ("/from/to/"), "/from/to/ -> subst");
t.ok (Arguments::is_subst ("/from from/to to/"), "/from from/to to/ -> subst");
t.notok (Arguments::is_subst ("///g"), "///g -> not subst");
t.notok (Arguments::is_subst ("//to/g"), "//to/g -> not subst");
t.ok (Arguments::is_subst ("/from//g"), "/from//g -> subst");
t.ok (Arguments::is_subst ("/from/to/g"), "/from/to/g -> subst");
t.ok (Arguments::is_subst ("/from from/to to/g"), "/from from/to to/g -> subst");
// bool is_pattern (const std::string&);
t.notok (Arguments::is_pattern ("//"), "// -> not pattern");
t.notok (Arguments::is_pattern ("///"), "/// -> not pattern");
t.ok (Arguments::is_pattern ("/one/"), "/one/ -> pattern");
t.ok (Arguments::is_pattern ("/one two/"), "/one two/ -> pattern");
t.ok (Arguments::is_pattern ("/ /"), "/ / -> pattern");
// bool is_id (const std::string&);
t.ok (Arguments::is_id ("1"), "1 -> id");
t.ok (Arguments::is_id ("1,2"), "1,2 -> id");
t.ok (Arguments::is_id ("1-2"), "1-2 -> id");
t.ok (Arguments::is_id ("1,2,3"), "1,2,3 -> id");
t.ok (Arguments::is_id ("1-2,3,4-5"), "1-2,3,4-5 -> id");
t.notok (Arguments::is_id ("1-2-3"), "1-2-3 -> no id");
// bool is_uuid (const std::string&);
t.ok (Arguments::is_uuid ("00000000-0000-0000-0000-000000000000"),
"00000000-0000-0000-0000-000000000000 -> uuid");
t.ok (Arguments::is_uuid ("eeeeeeee-eeee-eeee-eeee-eeeeeeeeeeee,ffffffff-ffff-ffff-ffff-ffffffffffff"),
"eeeeeeee-eeee-eeee-eeee-eeeeeeeeeeee,ffffffff-ffff-ffff-ffff-ffffffffffff -> uuid");
// bool is_tag (const std::string&);
t.ok (Arguments::is_tag ("+one"), "+one -> tag");
t.ok (Arguments::is_tag ("-one"), "-one -> tag");
t.notok (Arguments::is_tag ("+one "), "+one -> not tag");
t.notok (Arguments::is_tag ("-one "), "-one -> not tag");
t.notok (Arguments::is_tag ("+"), "+ -> not tag");
t.notok (Arguments::is_tag ("-"), "- -> not tag");
t.notok (Arguments::is_tag ("++"), "++ -> not tag");
t.notok (Arguments::is_tag ("--"), "-- -> not tag");
t.notok (Arguments::is_tag ("+one two"), "+one two -> not tag");
// bool is_operator (const std::string&);
t.ok (Arguments::is_operator ("!"), "! -> operator");
t.ok (Arguments::is_operator ("-"), "- -> operator");
t.ok (Arguments::is_operator ("*"), "* -> operator");
t.ok (Arguments::is_operator ("/"), "/ -> operator");
t.ok (Arguments::is_operator ("+"), "+ -> operator");
t.ok (Arguments::is_operator ("-"), "- -> operator");
t.ok (Arguments::is_operator ("<"), "< -> operator");
t.ok (Arguments::is_operator ("<="), "<= -> operator");
t.ok (Arguments::is_operator (">="), ">= -> operator");
t.ok (Arguments::is_operator (">"), "> -> operator");
t.ok (Arguments::is_operator ("~"), "~ -> operator");
t.ok (Arguments::is_operator ("!~"), "!~ -> operator");
t.ok (Arguments::is_operator ("="), "= -> operator");
t.ok (Arguments::is_operator ("!="), "!= -> operator");
t.ok (Arguments::is_operator ("and"), "and -> operator");
t.ok (Arguments::is_operator ("xor"), "xor -> operator");
t.ok (Arguments::is_operator ("or"), "or -> operator");
t.ok (Arguments::is_operator ("("), "( -> operator");
t.ok (Arguments::is_operator (")"), ") -> operator");
t.notok (Arguments::is_operator ("$"), "$ -> not operator");
// bool is_expression (const std::string&);
t.notok (Arguments::is_expression ("foo"), "foo -> expression");
t.ok (Arguments::is_expression ("1+1"), "1+1 -> expression");
t.ok (Arguments::is_expression ("a~b"), "a~b -> expression");
t.ok (Arguments::is_expression ("(1)"), "(1) -> expression");
t.ok (Arguments::is_expression ("!a"), "!a -> expression");
// static bool valid_modifier (const std::string&);
t.ok (Arguments::valid_modifier ("before"), "before -> modifier");
t.ok (Arguments::valid_modifier ("under"), "under -> modifier");
t.ok (Arguments::valid_modifier ("below"), "below -> modifier");
t.ok (Arguments::valid_modifier ("after"), "after -> modifier");
t.ok (Arguments::valid_modifier ("over"), "over -> modifier");
t.ok (Arguments::valid_modifier ("above"), "above -> modifier");
t.ok (Arguments::valid_modifier ("none"), "none -> modifier");
t.ok (Arguments::valid_modifier ("any"), "any -> modifier");
t.ok (Arguments::valid_modifier ("is"), "is -> modifier");
t.ok (Arguments::valid_modifier ("equals"), "equals -> modifier");
t.ok (Arguments::valid_modifier ("isnt"), "isnt -> modifier");
t.ok (Arguments::valid_modifier ("not"), "not -> modifier");
t.ok (Arguments::valid_modifier ("has"), "has -> modifier");
t.ok (Arguments::valid_modifier ("contains"), "contains -> modifier");
t.ok (Arguments::valid_modifier ("hasnt"), "hasnt -> modifier");
t.ok (Arguments::valid_modifier ("startswith"), "startswith -> modifier");
t.ok (Arguments::valid_modifier ("left"), "left -> modifier");
t.ok (Arguments::valid_modifier ("endswith"), "endswith -> modifier");
t.ok (Arguments::valid_modifier ("right"), "right -> modifier");
t.ok (Arguments::valid_modifier ("word"), "word -> modifier");
t.ok (Arguments::valid_modifier ("noword"), "noword -> modifier");
t.notok (Arguments::valid_modifier ("duck"), "duck -> not modified");
return 0;
}
////////////////////////////////////////////////////////////////////////////////

View file

@ -47,7 +47,7 @@ int main (int argc, char** argv)
try try
{ {
// Prime the pump. // Prime the pump.
context.args.capture ("task"); context.a3.capture ("task");
// TODO dom.get rc.name // TODO dom.get rc.name
DOM dom; DOM dom;

View file

@ -1,331 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// taskwarrior - a command line task list manager.
//
// Copyright 2006 - 2011, Paul Beckingham.
// All rights reserved.
//
// This program is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free Software
// Foundation; either version 2 of the License, or (at your option) any later
// version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
// details.
//
// You should have received a copy of the GNU General Public License along with
// this program; if not, write to the
//
// Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor,
// Boston, MA
// 02110-1301
// USA
//
////////////////////////////////////////////////////////////////////////////////
#include <Lexer.h>
#include <Context.h>
#include <test.h>
Context context;
////////////////////////////////////////////////////////////////////////////////
int main (int argc, char** argv)
{
UnitTest t (80);
std::string input = "This is a test.";
std::vector <std::string> tokens;
{
Lexer l (input);
l.tokenize (tokens);
}
t.is (tokens.size (), (size_t) 8, "'This is a test.' -> 'This| |is| |a| |test|.'");
if (tokens.size () == 8)
{
t.is (tokens[0], "This", "'This is a test.' [0] -> 'This'");
t.is (tokens[1], " ", "'This is a test.' [1] -> ' '");
t.is (tokens[2], "is", "'This is a test.' [2] -> 'is'");
t.is (tokens[3], " ", "'This is a test.' [3] -> ' '");
t.is (tokens[4], "a", "'This is a test.' [4] -> 'a'");
t.is (tokens[5], " ", "'This is a test.' [5] -> ' '");
t.is (tokens[6], "test", "'This is a test.' [6] -> 'test'");
t.is (tokens[7], ".", "'This is a test.' [7] -> '.'");
}
else
{
t.skip ("'This is a test.' [0] -> 'This'");
t.skip ("'This is a test.' [1] -> ' '");
t.skip ("'This is a test.' [2] -> 'is'");
t.skip ("'This is a test.' [3] -> ' '");
t.skip ("'This is a test.' [4] -> 'a'");
t.skip ("'This is a test.' [5] -> ' '");
t.skip ("'This is a test.' [6] -> 'test'");
t.skip ("'This is a test.' [7] -> '.'");
}
input = "a12bcd345efgh6789";
{
Lexer l (input);
l.tokenize (tokens);
}
t.is (tokens.size (), (size_t) 6, "'a12bcd345efgh6789' -> 'a|12|bcd|345|efgh|6789'");
if (tokens.size () == 6)
{
t.is (tokens[0], "a", "'a12bcd345efgh6789' [0] -> 'a'");
t.is (tokens[1], "12", "'a12bcd345efgh6789' [1] -> '12'");
t.is (tokens[2], "bcd", "'a12bcd345efgh6789' [2] -> 'bcd'");
t.is (tokens[3], "345", "'a12bcd345efgh6789' [3] -> '345'");
t.is (tokens[4], "efgh", "'a12bcd345efgh6789' [4] -> 'efgh'");
t.is (tokens[5], "6789", "'a12bcd345efgh6789' [5] -> '6789'");
}
else
{
t.skip ("'a12bcd345efgh6789' [0] -> 'a'");
t.skip ("'a12bcd345efgh6789' [1] -> '12'");
t.skip ("'a12bcd345efgh6789' [2] -> 'bcd'");
t.skip ("'a12bcd345efgh6789' [3] -> '345'");
t.skip ("'a12bcd345efgh6789' [4] -> 'efgh'");
t.skip ("'a12bcd345efgh6789' [5] -> '6789'");
}
// Let's throw some ugly Perl at it.
input = "my $variable_name = 'single string';";
{
Lexer l (input);
l.categorizeAsAlpha ('_');
l.coalesceQuoted (true);
l.tokenize (tokens);
}
t.is (tokens.size (), (size_t) 9, "'my $variable_name = 'single string';' -> 'my| |$|variable_name| |=| |'|single string|'|;'");
if (tokens.size () == 9)
{
t.is (tokens[0], "my", "'my $variable_name = 'single string';' [0] -> 'my'");
t.is (tokens[1], " ", "'my $variable_name = 'single string';' [1] -> ' '");
t.is (tokens[2], "$", "'my $variable_name = 'single string';' [2] -> '$'");
t.is (tokens[3], "variable_name", "'my $variable_name = 'single string';' [3] -> 'variable_name'");
t.is (tokens[4], " ", "'my $variable_name = 'single string';' [4] -> ' '");
t.is (tokens[5], "=", "'my $variable_name = 'single string';' [5] -> '='");
t.is (tokens[6], " ", "'my $variable_name = 'single string';' [6] -> ' '");
t.is (tokens[7], "'single string'", "'my $variable_name = 'single string';' [8] -> ''single string''");
t.is (tokens[8], ";", "'my $variable_name = 'single string';' [10] -> ';'");
}
else
{
t.skip ("'my $variable_name = 'single string';' [0] -> 'my'");
t.skip ("'my $variable_name = 'single string';' [1] -> ' '");
t.skip ("'my $variable_name = 'single string';' [2] -> '$'");
t.skip ("'my $variable_name = 'single string';' [3] -> 'variable_name'");
t.skip ("'my $variable_name = 'single string';' [4] -> ' '");
t.skip ("'my $variable_name = 'single string';' [5] -> '='");
t.skip ("'my $variable_name = 'single string';' [6] -> ' '");
t.skip ("'my $variable_name = 'single string';' [8] -> ''single string''");
t.skip ("'my $variable_name = 'single string';' [10] -> ';'");
}
// Now exercise all the configurable coalescence.
input = "ab 12 'a'";
{
Lexer l (input);
l.tokenize (tokens);
}
t.is (tokens.size (), (size_t) 8, "'ab 12 'a'' -> 'ab| | |12| |'|a|''");
if (tokens.size () == 8)
{
t.is (tokens[0], "ab", "'ab 12 'a'' [0] -> 'ab'");
t.is (tokens[1], " ", "'ab 12 'a'' [1] -> ' '");
t.is (tokens[2], " ", "'ab 12 'a'' [2] -> ' '");
t.is (tokens[3], "12", "'ab 12 'a'' [3] -> '12'");
t.is (tokens[4], " ", "'ab 12 'a'' [4] -> ' '");
t.is (tokens[5], "'", "'ab 12 'a'' [5] -> '''");
t.is (tokens[6], "a", "'ab 12 'a'' [6] -> 'a'");
t.is (tokens[7], "'", "'ab 12 'a'' [7] -> '''");
}
else
{
t.skip ("'ab 12 'a'' [0] -> 'ab'");
t.skip ("'ab 12 'a'' [1] -> ' '");
t.skip ("'ab 12 'a'' [2] -> ' '");
t.skip ("'ab 12 'a'' [3] -> '12'");
t.skip ("'ab 12 'a'' [4] -> ' '");
t.skip ("'ab 12 'a'' [5] -> '''");
t.skip ("'ab 12 'a'' [6] -> 'a'");
t.skip ("'ab 12 'a'' [7] -> '''");
}
{
Lexer l (input);
l.coalesceAlpha (false);
l.tokenize (tokens);
}
t.is (tokens.size (), (size_t) 9, "'ab 12 'a'' -> 'a|b| | |12| |'|a|''");
if (tokens.size () == 9)
{
t.is (tokens[0], "a", "'ab 12 'a'' [0] -> 'a'");
t.is (tokens[1], "b", "'ab 12 'a'' [1] -> 'b'");
t.is (tokens[2], " ", "'ab 12 'a'' [2] -> ' '");
t.is (tokens[3], " ", "'ab 12 'a'' [3] -> ' '");
t.is (tokens[4], "12", "'ab 12 'a'' [4] -> '12'");
t.is (tokens[5], " ", "'ab 12 'a'' [5] -> ' '");
t.is (tokens[6], "'", "'ab 12 'a'' [6] -> '''");
t.is (tokens[7], "a", "'ab 12 'a'' [7] -> 'a'");
t.is (tokens[8], "'", "'ab 12 'a'' [8] -> '''");
}
else
{
t.skip ("'ab 12 'a'' [0] -> 'a'");
t.skip ("'ab 12 'a'' [1] -> 'b'");
t.skip ("'ab 12 'a'' [2] -> ' '");
t.skip ("'ab 12 'a'' [3] -> ' '");
t.skip ("'ab 12 'a'' [4] -> '12'");
t.skip ("'ab 12 'a'' [5] -> ' '");
t.skip ("'ab 12 'a'' [6] -> '''");
t.skip ("'ab 12 'a'' [7] -> 'a'");
t.skip ("'ab 12 'a'' [8] -> '''");
}
{
Lexer l (input);
l.coalesceDigits (false);
l.tokenize (tokens);
}
t.is (tokens.size (), (size_t) 9, "'ab 12 'a'' -> 'ab| | |1|2| |'|a|''");
if (tokens.size () == 9)
{
t.is (tokens[0], "ab", "'ab 12 'a'' [0] -> 'ab'");
t.is (tokens[1], " ", "'ab 12 'a'' [1] -> ' '");
t.is (tokens[2], " ", "'ab 12 'a'' [2] -> ' '");
t.is (tokens[3], "1", "'ab 12 'a'' [3] -> '1'");
t.is (tokens[4], "2", "'ab 12 'a'' [4] -> '2'");
t.is (tokens[5], " ", "'ab 12 'a'' [5] -> ' '");
t.is (tokens[6], "'", "'ab 12 'a'' [6] -> '''");
t.is (tokens[7], "a", "'ab 12 'a'' [7] -> 'a'");
t.is (tokens[8], "'", "'ab 12 'a'' [8] -> '''");
}
else
{
t.skip ("'ab 12 'a'' [0] -> 'ab'");
t.skip ("'ab 12 'a'' [1] -> ' '");
t.skip ("'ab 12 'a'' [2] -> ' '");
t.skip ("'ab 12 'a'' [3] -> '1'");
t.skip ("'ab 12 'a'' [4] -> '2'");
t.skip ("'ab 12 'a'' [5] -> ' '");
t.skip ("'ab 12 'a'' [6] -> '''");
t.skip ("'ab 12 'a'' [7] -> 'a'");
t.skip ("'ab 12 'a'' [8] -> '''");
}
{
Lexer l (input);
l.coalesceQuoted (true);
l.tokenize (tokens);
}
t.is (tokens.size (), (size_t) 6, "'ab 12 'a'' -> 'ab| | |12| |'a''");
if (tokens.size () == 6)
{
t.is (tokens[0], "ab", "'ab 12 'a'' [0] -> 'ab'");
t.is (tokens[1], " ", "'ab 12 'a'' [1] -> ' '");
t.is (tokens[2], " ", "'ab 12 'a'' [2] -> ' '");
t.is (tokens[3], "12", "'ab 12 'a'' [3] -> '12'");
t.is (tokens[4], " ", "'ab 12 'a'' [4] -> ' '");
t.is (tokens[5], "'a'", "'ab 12 'a'' [5] -> ''a''");
}
else
{
t.skip ("'ab 12 'a'' [0] -> 'ab'");
t.skip ("'ab 12 'a'' [1] -> ' '");
t.skip ("'ab 12 'a'' [2] -> ' '");
t.skip ("'ab 12 'a'' [3] -> '12'");
t.skip ("'ab 12 'a'' [4] -> ' '");
t.skip ("'ab 12 'a'' [5] -> ''a''");
}
{
Lexer l (input);
l.coalesceWhite (true);
l.tokenize (tokens);
}
t.is (tokens.size (), (size_t) 7, "'ab 12 'a'' -> 'ab| |12| |'|a|''");
if (tokens.size () == 7)
{
t.is (tokens[0], "ab", "'ab 12 'a'' [0] -> 'ab'");
t.is (tokens[1], " ", "'ab 12 'a'' [1] -> ' '");
t.is (tokens[2], "12", "'ab 12 'a'' [2] -> '12'");
t.is (tokens[3], " ", "'ab 12 'a'' [3] -> ' '");
t.is (tokens[4], "'", "'ab 12 'a'' [4] -> '''");
t.is (tokens[5], "a", "'ab 12 'a'' [5] -> 'a'");
t.is (tokens[6], "'", "'ab 12 'a'' [6] -> '''");
}
else
{
t.skip ("'ab 12 'a'' [0] -> 'ab'");
t.skip ("'ab 12 'a'' [1] -> ' '");
t.skip ("'ab 12 'a'' [2] -> '12'");
t.skip ("'ab 12 'a'' [3] -> ' '");
t.skip ("'ab 12 'a'' [4] -> '''");
t.skip ("'ab 12 'a'' [5] -> 'a'");
t.skip ("'ab 12 'a'' [6] -> '''");
}
{
Lexer l (input);
l.skipWhitespace (true);
l.tokenize (tokens);
}
t.is (tokens.size (), (size_t) 5, "'ab 12 'a'' -> 'ab|12|'|a|''");
if (tokens.size () == 5)
{
t.is (tokens[0], "ab", "'ab 12 'a'' [0] -> 'ab'");
t.is (tokens[1], "12", "'ab 12 'a'' [1] -> '12'");
t.is (tokens[2], "'", "'ab 12 'a'' [2] -> '''");
t.is (tokens[3], "a", "'ab 12 'a'' [3] -> 'a'");
t.is (tokens[4], "'", "'ab 12 'a'' [4] -> '''");
}
else
{
t.skip ("'ab 12 'a'' [0] -> 'ab'");
t.skip ("'ab 12 'a'' [1] -> '12'");
t.skip ("'ab 12 'a'' [2] -> '''");
t.skip ("'ab 12 'a'' [3] -> 'a'");
t.skip ("'ab 12 'a'' [4] -> '''");
}
// Special tokens
input = "a := 1";
{
Lexer l (input);
l.skipWhitespace (true);
l.specialToken (":=");
l.tokenize (tokens);
}
t.is (tokens.size (), (size_t) 3, "'a := 1' -> 'a|:=|1'");
if (tokens.size () == 3)
{
t.is (tokens[0], "a", "'a := 1' [0] -> 'a'");
t.is (tokens[1], ":=", "'a := 1' [1] -> ':='");
t.is (tokens[2], "1", "'a := 1' [2] -> '1'");
}
else
{
t.skip ("'a := 1' [0] -> 'a'");
t.skip ("'a := 1' [1] -> ':='");
t.skip ("'a := 1' [2] -> '1'");
}
return 0;
}
////////////////////////////////////////////////////////////////////////////////