From b79567fbc72df23f870049652d5f254aba948bea Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Fri, 16 Sep 2011 16:03:25 +0200 Subject: Support for views; integrated part --- odb/pragma.cxx | 528 ++++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 447 insertions(+), 81 deletions(-) (limited to 'odb/pragma.cxx') diff --git a/odb/pragma.cxx b/odb/pragma.cxx index ea2a696..17eaa42 100644 --- a/odb/pragma.cxx +++ b/odb/pragma.cxx @@ -5,10 +5,14 @@ #include +#include // std::isalnum #include +#include #include +#include #include +#include #include #include @@ -40,96 +44,185 @@ accumulate (compiler::context& ctx, string const& k, any const& v, location_t) loc_pragmas loc_pragmas_; decl_pragmas decl_pragmas_; -static tree -parse_scoped_name (tree& t, - cpp_ttype& tt, - string& name, - bool is_type, - string const& prag) +static bool +parse_expression (tree& t, + cpp_ttype& tt, + cxx_tokens& ts, + string const& prag) { - tree scope, id; - bool first (true); - - if (tt == CPP_SCOPE) - { - name += "::"; - scope = global_namespace; - first = false; - tt = pragma_lex (&t); - } - else - scope = current_scope (); + // Keep reading tokens until we see a matching ')' while keeping track + // of their balance. + // + size_t balance (0); - while (true) + for (; tt != CPP_EOF; tt = pragma_lex (&t)) { - if (tt != CPP_NAME) - { - error () << "invalid name in db pragma " << prag << endl; - return 0; - } - - id = t; - name += IDENTIFIER_POINTER (t); - tt = pragma_lex (&t); - - bool last (tt != CPP_SCOPE); - tree decl = lookup_qualified_name (scope, id, last && is_type, false); + bool done (false); + cxx_token ct; - // If this is the first component in the name, then also search the - // outer scopes. - // - if (decl == error_mark_node && first && scope != global_namespace) + switch (tt) { - do + case CPP_OPEN_PAREN: { - scope = TYPE_P (scope) - ? CP_TYPE_CONTEXT (scope) - : CP_DECL_CONTEXT (scope); - decl = lookup_qualified_name (scope, id, last && is_type, false); - } while (decl == error_mark_node && scope != global_namespace); - } - - if (decl == error_mark_node) - { - if (last) + balance++; + break; + } + case CPP_CLOSE_PAREN: { - error () << "unable to resolve " << (is_type ? "type " : "") << "name " - << "'" << name << "' in db pragma " << prag << endl; + if (balance == 0) + done = true; + else + balance--; + break; } - else + case CPP_STRING: { - error () << "unable to resolve name '" << name << "' in db pragma " - << prag << endl; + ct.literal = TREE_STRING_POINTER (t); + break; } + case CPP_NAME: + { + ct.literal = IDENTIFIER_POINTER (t); + break; + } + case CPP_NUMBER: + { + switch (TREE_CODE (t)) + { + case INTEGER_CST: + { + tree type (TREE_TYPE (t)); + + HOST_WIDE_INT hwl (TREE_INT_CST_LOW (t)); + HOST_WIDE_INT hwh (TREE_INT_CST_HIGH (t)); + + unsigned long long l (hwl); + unsigned long long h (hwh); + unsigned short width (HOST_BITS_PER_WIDE_INT); + + unsigned long long v ((h << width) + l); + + ostringstream os; + os << v; + + if (type == long_long_integer_type_node) + os << "LL"; + else if (type == long_long_unsigned_type_node) + os << "ULL"; + else if (type == long_integer_type_node) + os << "L"; + else if (type == long_unsigned_type_node) + os << "UL"; + else if ( + TYPE_UNSIGNED (type) && + TYPE_PRECISION (type) >= TYPE_PRECISION (integer_type_node)) + os << "U"; + + ct.literal = os.str (); + break; + } + case REAL_CST: + { + tree type (TREE_TYPE (t)); + REAL_VALUE_TYPE val (TREE_REAL_CST (t)); + + // This is the best we can do. val cannot be INF or NaN. + // + char tmp[256]; + real_to_decimal (tmp, &val, sizeof (tmp), 0, true); + istringstream is (tmp); + ostringstream os; + + if (type == float_type_node) + { + float f; + is >> f; + os << f << 'F'; + } + else + { + double d; + is >> d; + os << d; + } + + ct.literal = os.str (); + break; + } + default: + { + error () + << "unexpected numeric constant in db pragma " << prag << endl; + return false; + } + } - return 0; + break; + } + default: + { + break; + } } - scope = decl; - - if (last) + if (done) break; - first = false; + ct.type = tt; + ts.push_back (ct); + } - if (TREE_CODE (scope) == TYPE_DECL) - scope = TREE_TYPE (scope); + return true; +} - name += "::"; - tt = pragma_lex (&t); - } - // Get the actual type if this is a TYPE_DECL. - // - if (is_type) +static string +parse_scoped_name (tree& token, cpp_ttype& type, string const& prag) +{ + try + { + cxx_pragma_lexer lex; + string st (lex.start (token, type)); + return lookup::parse_scoped_name (st, type, lex); + } + catch (lookup::invalid_name const&) { - if (TREE_CODE (scope) == TYPE_DECL) - scope = TREE_TYPE (scope); + error () << "invalid name in db pragma " << prag << endl; + return ""; + } +} - scope = TYPE_MAIN_VARIANT (scope); +static tree +resolve_scoped_name (tree& token, + cpp_ttype& type, + string& name, + bool is_type, + string const& prag) +{ + try + { + cxx_pragma_lexer lex; + cpp_ttype ptt; // Not used. + string st (lex.start (token, type)); + return lookup::resolve_scoped_name ( + st, type, ptt, lex, current_scope (), name, is_type); + } + catch (lookup::invalid_name const&) + { + error () << "invalid name in db pragma " << prag << endl; + return 0; } + catch (lookup::unable_to_resolve const& e) + { + if (e.last ()) + error () << "unable to resolve " << (is_type ? "type " : "") << "name " + << "'" << e.name () << "' in db pragma " << prag << endl; + else + error () << "unable to resolve name '" << e.name () << "' in db pragma " + << prag << endl; - return scope; + return 0; + } } static bool @@ -511,7 +604,9 @@ handle_pragma (cpp_reader* reader, } else if (p == "query") { + // query () // query ("statement") + // query (expr) // // Make sure we've got the correct declaration type. @@ -527,25 +622,59 @@ handle_pragma (cpp_reader* reader, tt = pragma_lex (&t); - if (tt != CPP_STRING) + view_query vq; + + bool s (false); + string str; + + if (tt == CPP_STRING) { - error () << "query statement expected in db pragma " << p << endl; - return; + s = true; + str = TREE_STRING_POINTER (t); + tt = pragma_lex (&t); } - val = string (TREE_STRING_POINTER (t)); + if (tt == CPP_CLOSE_PAREN) + { + if (s) + vq.literal = str; + else + { + // Empty query() pragma indicates that the statement will be + // provided at runtime. Encode this case as empty literal + // and expression. + // + } + } + else + { + // Expression. + // + if (s) + { + vq.expr.push_back (cxx_token ()); + vq.expr.back ().type = CPP_STRING; + vq.expr.back ().literal = str; + } - if (pragma_lex (&t) != CPP_CLOSE_PAREN) + if (!parse_expression (t, tt, vq.expr, p)) + return; // Diagnostics has already been issued. + } + + if (tt != CPP_CLOSE_PAREN) { error () << "')' expected at the end of db pragma " << p << endl; return; } + vq.scope = current_scope (); + vq.loc = loc; + val = vq; tt = pragma_lex (&t); } else if (p == "object") { - // object (name) + // object (fq-name [ = name] [: expr]) // // Make sure we've got the correct declaration type. @@ -568,17 +697,50 @@ handle_pragma (cpp_reader* reader, } view_object vo; - vo.node = parse_scoped_name (t, tt, vo.name, true, p); + vo.node = resolve_scoped_name (t, tt, vo.orig_name, true, p); if (vo.node == 0) return; // Diagnostics has already been issued. + if (tt == CPP_EQ) + { + // We have an alias. + // + if (pragma_lex (&t) != CPP_NAME) + { + error () << "alias name expected after '=' in db pragma " << p << endl; + return; + } + + vo.alias = IDENTIFIER_POINTER (t); + tt = pragma_lex (&t); + } + + if (tt == CPP_COLON) + { + // We have a condition. + + tt = pragma_lex (&t); + + if (!parse_expression (t, tt, vo.cond, p)) + return; // Diagnostics has already been issued. + + if (vo.cond.empty ()) + { + error () + << "join condition expected after ':' in db pragma " << p << endl; + return; + } + } + if (tt != CPP_CLOSE_PAREN) { error () << "')' expected at the end of db pragma " << p << endl; return; } + vo.scope = current_scope (); + vo.loc = loc; val = vo; name = "objects"; // Change the context entry name. adder = &accumulate; @@ -609,13 +771,217 @@ handle_pragma (cpp_reader* reader, tt = pragma_lex (&t); } - else if (p == "column" || - p == "value_column" || + else if (p == "column") + { + // column ("") + // column (".") + // column (""."") + // column (fq-name) (view only) + // column (expr) (view only) + // + + // Make sure we've got the correct declaration type. + // + if (decl != 0 && !check_spec_decl_type (decl, decl_name, p, loc)) + return; + + if (pragma_lex (&t) != CPP_OPEN_PAREN) + { + error () << "'(' expected after db pragma " << p << endl; + return; + } + + tt = pragma_lex (&t); + + bool s (false); + string str; + + // String can be just the column name, a table name followed by the + // column name, or part of an expression, depending on what comes + // after the string. + // + if (tt == CPP_STRING) + { + s = true; + str = TREE_STRING_POINTER (t); + tt = pragma_lex (&t); + } + + if (tt == CPP_CLOSE_PAREN) + { + if (s) + { + // "" or "." + // + table_column tc; + tc.expr = false; + + // Scan the string and see if we have any non-identifier + // characters. If so, assume it is an expression. While + // at it also see if there is '.'. + // + string::size_type p (string::npos); + + for (size_t i (0); i < str.size (); ++i) + { + char c (str[i]); + + if (!(isalnum (c) || c == '_')) + { + tc.expr = true; + break; + } + + if (c == '.') + { + if (p != string::npos) + { + // Second '.' -- something fishy is going on. + tc.expr = true; + break; + } + + p = i; + } + } + + if (!tc.expr && p != string::npos) + { + tc.table.assign (str, 0, p); + tc.column.assign (str, p + 1, string::npos); + } + else + tc.column = str; + + val = tc; + } + else + { + error () << "column name expected in db pragma " << p << endl; + return; + } + } + else if (tt == CPP_DOT) + { + if (s) + { + // ""."" + // + table_column tc; + tc.expr = false; + + if (pragma_lex (&t) != CPP_STRING) + { + error () << "column name expected after '.' in db pragma " << p + << endl; + return; + } + + tc.table = str; + tc.column = TREE_STRING_POINTER (t); + val = tc; + tt = pragma_lex (&t); + } + else + { + error () << "column name expected in db pragma " << p << endl; + return; + } + } + else + { + // We have an expression. + // + column_expr e; + + if (s) + { + e.push_back (column_expr_part ()); + e.back ().kind = column_expr_part::literal; + e.back ().value = str; + + if (tt != CPP_PLUS) + { + error () << "'+' or ')' expected in db pragma " << p << endl; + return; + } + + tt = pragma_lex (&t); + } + + for (;;) + { + if (tt == CPP_STRING) + { + e.push_back (column_expr_part ()); + e.back ().kind = column_expr_part::literal; + e.back ().value = TREE_STRING_POINTER (t); + + tt = pragma_lex (&t); + } + else if (tt == CPP_NAME || tt == CPP_SCOPE) + { + string name (parse_scoped_name (t, tt, p)); + + if (name.empty ()) + return; // Diagnostics has already been issued. + + // Resolve nested members if any. + // + for (; tt == CPP_DOT; tt = pragma_lex (&t)) + { + if (pragma_lex (&t) != CPP_NAME) + { + error () << "name expected after '.' in db pragma " << p << endl; + return; + } + + name += '.'; + name += IDENTIFIER_POINTER (t); + } + + e.push_back (column_expr_part ()); + e.back ().kind = column_expr_part::reference; + e.back ().value = name; + e.back ().scope = current_scope (); + e.back ().loc = loc; + } + else + { + error () << "string literal or name expected in db pragma " << p + << endl; + return; + } + + if (tt == CPP_PLUS) + tt = pragma_lex (&t); + else if (tt == CPP_CLOSE_PAREN) + break; + else + { + error () << "'+' or ')' expected in db pragma " << p << endl; + return; + } + } + + e.loc = loc; + val = e; + name = "column-expr"; + } + + if (tt != CPP_CLOSE_PAREN) + { + error () << "')' expected at the end of db pragma " << p << endl; + return; + } + + tt = pragma_lex (&t); + } + else if (p == "value_column" || p == "index_column" || p == "key_column" || p == "id_column") { - // column ("") // value_column ("") // index_column ("") // key_column ("") @@ -839,7 +1205,7 @@ handle_pragma (cpp_reader* reader, { // We have a potentially scopped enumerator name. // - dv.node = parse_scoped_name (t, tt, dv.value, false, p); + dv.node = resolve_scoped_name (t, tt, dv.value, false, p); if (dv.node == 0) return; // Diagnostics has already been issued. @@ -1021,7 +1387,7 @@ handle_pragma_qualifier (cpp_reader* reader, string const& p) if (tt == CPP_NAME || tt == CPP_SCOPE) { - decl = parse_scoped_name (t, tt, decl_name, true, p); + decl = resolve_scoped_name (t, tt, decl_name, true, p); if (decl == 0) return; // Diagnostics has already been issued. @@ -1059,7 +1425,7 @@ handle_pragma_qualifier (cpp_reader* reader, string const& p) if (tt == CPP_NAME || tt == CPP_SCOPE) { - decl = parse_scoped_name (t, tt, decl_name, false, p); + decl = resolve_scoped_name (t, tt, decl_name, false, p); if (decl == 0) return; // Diagnostics has already been issued. -- cgit v1.1