Files
textmate/Frameworks/scope/src/parse.cc
2012-08-10 18:44:16 +02:00

213 lines
4.7 KiB
C++

#include "parse.h"
/*
atom: «string» | '*'
scope: «atom» ('.' «atom»)*
path: '^'? «scope» ('>'? «scope»)* '$'?
group: '(' «selector» ')'
filter: ("L:"|"R:"|"B:") («group» | «path»)
expression: '-'? («filter» | «group» | «path»)
composite: «expression» ([|&-] «expression»)*
selector: «composite» (',' «composite»)*
*/
// #define ENTER fprintf(stderr, "%s\n", __FUNCTION__)
#define ENTER
namespace scope
{
namespace parse
{
using namespace types;
struct context_t
{
char const* it;
char const* last;
bool ws ();
bool parse_char (char const* ch, char* dst = NULL);
bool parse_atom (atom_t& res);
bool parse_scope (scope::types::scope_t& res);
bool parse_path (path_t& res);
bool parse_path (any_ptr& res);
bool parse_group (any_ptr& res);
bool parse_filter (any_ptr& res);
bool parse_expression (expression_t& res);
bool parse_composite (composite_t& res);
bool parse_selector (selector_t& res);
};
bool context_t::parse_atom (atom_t& res)
{
ENTER;
if(parse_char("*"))
return res = scope::types::atom_any, true;
if(!isalnum(*it) && *it < 0x80)
return false;
char const* from = it;
while(isalnum(*it) || *it == '_' || *it == '-' || *it == '+' || *it > 0x7F)
++it;
res.insert(res.end(), from, it);
return true;
}
bool context_t::parse_scope (scope::types::scope_t& res)
{
ENTER;
bool rc = false;
res.anchor_to_previous = parse_char(">") && ws();
do {
res.atoms.push_back(atom_t());
if(!parse_atom(res.atoms.back()))
{
res.atoms.pop_back();
break;
}
rc = true;
} while(parse_char("."));
return rc;
}
bool context_t::parse_path (path_t& res)
{
ENTER;
res.anchor_to_bol = parse_char("^") && ws();
do {
res.scopes.push_back(scope::types::scope_t());
if(!parse_scope(res.scopes.back()))
break;
} while(ws());
if(res.scopes.size() > 1)
res.scopes.pop_back();
res.anchor_to_eol = parse_char("$");
return true;
}
bool context_t::parse_path (any_ptr& res)
{
path_t tmp;
if(parse_path(tmp))
return res.reset(new path_t(tmp)), true;
return false;
}
bool context_t::parse_group (any_ptr& res)
{
ENTER;
char const* bt = it;
group_t group;
if(parse_char("(") && parse_selector(group.selector) && ws() && parse_char(")"))
return res.reset(new group_t(group)), true;
return it = bt, false;
}
bool context_t::parse_filter (any_ptr& res)
{
ENTER;
char const* bt = it;
filter_t filter;
char side;
if(parse_char("LRB", &side) && parse_char(":") && ws() && (parse_group(filter.selector) || parse_path(filter.selector)))
return filter.filter = filter_t::side_t(side), res.reset(new filter_t(filter)), true;
return it = bt, false;
}
bool context_t::parse_expression (expression_t& res)
{
ENTER;
if(parse_char("-") && ws())
res.negate = true;
return parse_filter(res.selector) || parse_group(res.selector) || parse_path(res.selector);
}
bool context_t::parse_composite (composite_t& res)
{
ENTER;
bool rc = false;
char op = expression_t::op_none;
do {
expression_t tmp(op);
if(!parse_expression(tmp))
break;
res.expressions.push_back(tmp);
rc = true;
} while(ws() && parse_char("&|-", &op) && ws());
return rc;
}
bool context_t::parse_selector (selector_t& res)
{
ENTER;
bool rc = false;
ws();
do {
composite_t tmp;
if(!parse_composite(tmp))
break;
res.composites.push_back(tmp);
rc = true;
} while(ws() && parse_char(",") && ws());
return rc;
}
// =============================
// = General Utility Functions =
// =============================
bool context_t::ws ()
{
while(it != last && strchr(" \t", *it))
++it;
return true;
}
bool context_t::parse_char (char const* ch, char* dst)
{
if(it == last || !strchr(ch, *it))
return false;
if(dst)
*dst = *it;
return ++it, true;
}
// =======
// = API =
// =======
char const* scope (char const* first, char const* last, scope::types::scope_t& scope)
{
context_t context = { first, last };
context.ws();
context.parse_scope(scope);
return context.it;
}
char const* path (char const* first, char const* last, scope::types::path_t& path)
{
context_t context = { first, last };
context.ws();
context.parse_path(path);
return context.it;
}
char const* selector (char const* first, char const* last, scope::types::selector_t& selector)
{
context_t context = { first, last };
context.ws();
context.parse_selector(selector);
return context.it;
}
} /* parse */
} /* scope */