Ejemplo n.º 1
0
TypeRef Parse_Type_ErasedType(TokenStream& lex, bool allow_trait_list)
{
    Token   tok;

    auto ps = lex.start_span();
    ::std::vector<Type_TraitPath>   traits;
    ::std::vector<AST::LifetimeRef>   lifetimes;
    do {
        if( LOOK_AHEAD(lex) == TOK_LIFETIME ) {
            GET_TOK(tok, lex);
            lifetimes.push_back(AST::LifetimeRef( /*lex.point_span(),*/ lex.get_ident(mv$(tok)) ));
        }
        else
        {
            AST::HigherRankedBounds hrbs;
            if( lex.lookahead(0) == TOK_RWORD_FOR )
            {
                hrbs = Parse_HRB(lex);
            }
            traits.push_back({ mv$(hrbs), Parse_Path(lex, PATH_GENERIC_TYPE) });
        }
    } while( GET_TOK(tok, lex) == TOK_PLUS );
    PUTBACK(tok, lex);

    return TypeRef(lex.end_span(mv$(ps)), TypeData::make_ErasedType({ mv$(traits), mv$(lifetimes) }));
}
Ejemplo n.º 2
0
TypeRef Parse_Type_Path(TokenStream& lex, ::AST::HigherRankedBounds hrbs, bool allow_trait_list)
{
    Token   tok;

    auto ps = lex.start_span();

    if( hrbs.empty() && !allow_trait_list )
    {
        return TypeRef(TypeRef::TagPath(), lex.end_span(mv$(ps)), Parse_Path(lex, PATH_GENERIC_TYPE));
    }
    else
    {
        ::std::vector<Type_TraitPath>   traits;
        ::std::vector<AST::LifetimeRef> lifetimes;

        traits.push_back(Type_TraitPath { mv$(hrbs), Parse_Path(lex, PATH_GENERIC_TYPE) });

        if( allow_trait_list )
        {
            while( GET_TOK(tok, lex) == TOK_PLUS )
            {
                if( LOOK_AHEAD(lex) == TOK_LIFETIME ) {
                    GET_TOK(tok, lex);
                    lifetimes.push_back(AST::LifetimeRef( /*lex.point_span(),*/ lex.get_ident(mv$(tok)) ));
                }
                else
                {
                    if( lex.lookahead(0) == TOK_RWORD_FOR )
                    {
                        hrbs = Parse_HRB(lex);
                    }
                    traits.push_back({ mv$(hrbs), Parse_Path(lex, PATH_GENERIC_TYPE) });
                }
            }
            PUTBACK(tok, lex);
        }

        if( !traits[0].hrbs.empty() || traits.size() > 1 || lifetimes.size() > 0 )
        {
            if( lifetimes.empty())
                lifetimes.push_back(AST::LifetimeRef());
            return TypeRef(lex.end_span(mv$(ps)), mv$(traits), mv$(lifetimes));
        }
        else
        {
            return TypeRef(TypeRef::TagPath(), lex.end_span(mv$(ps)), mv$(traits.at(0).path));
        }
    }
}
Ejemplo n.º 3
0
/// Parse an entire macro_rules! block into a format that exec.cpp can use
MacroRulesPtr Parse_MacroRules(TokenStream& lex)
{
    TRACE_FUNCTION_F("");

    Token tok;

    // Parse the patterns and replacements
    ::std::vector<MacroRule>    rules;
    while( GET_TOK(tok, lex) != TOK_EOF )
    {
        lex.putback(tok);

        rules.push_back( Parse_MacroRules_Var(lex) );
        if(GET_TOK(tok, lex) != TOK_SEMICOLON) {
            CHECK_TOK(tok, TOK_EOF);
            break;
        }
    }
    DEBUG("- " << rules.size() << " rules");

    ::std::vector<MacroRulesArm>    rule_arms;

    // Re-parse the patterns into a unified form
    for(auto& rule : rules)
    {
        MacroRulesArm   arm = MacroRulesArm( mv$(rule.m_pattern), mv$(rule.m_contents) );

        enumerate_names(arm.m_pattern,  arm.m_param_names);

        rule_arms.push_back( mv$(arm) );
    }

    auto rv = new MacroRules( );
    rv->m_hygiene = lex.getHygiene();
    rv->m_rules = mv$(rule_arms);

    return MacroRulesPtr(rv);
}
Ejemplo n.º 4
0
/// Parse a single arm of a macro_rules! block - `(foo) => (bar)`
MacroRule Parse_MacroRules_Var(TokenStream& lex)
{
    TRACE_FUNCTION;
    Token tok;

    MacroRule   rule;

    // Pattern
    enum eTokenType close;
    switch(GET_TOK(tok, lex))
    {
    case TOK_BRACE_OPEN:    close = TOK_BRACE_CLOSE;    break;
    case TOK_PAREN_OPEN:    close = TOK_PAREN_CLOSE;    break;
    default:
        throw ParseError::Unexpected(lex, tok);
    }
    // - Pattern entries
    ::std::vector< ::std::string>   names;
    rule.m_pattern = Parse_MacroRules_Pat(lex, tok.type(), close,  names);

    GET_CHECK_TOK(tok, lex, TOK_FATARROW);

    // Replacement
    switch(GET_TOK(tok, lex))
    {
    case TOK_BRACE_OPEN:    close = TOK_BRACE_CLOSE;    break;
    case TOK_PAREN_OPEN:    close = TOK_PAREN_CLOSE;    break;
    default:
        throw ParseError::Unexpected(lex, tok);
    }
    rule.m_contents = Parse_MacroRules_Cont(lex, tok.type(), close, names);

    DEBUG("Rule - ["<<rule.m_pattern<<"] => "<<rule.m_contents<<"");

    return rule;
}
Ejemplo n.º 5
0
static int _parse (SCAN *scan, int dim, double **buf)
{                               /* --- parse normalization statistics */
  int    k, n = 0;              /* loop variable, counter */
  double *p;                    /* to access the statistics elements */

  assert(scan);                 /* check the function arguments */
  if ((sc_token(scan) != T_ID)  /* check whether 'scales' follows */
  ||  (strcmp(sc_value(scan), "scales") != 0))
    ERR_STR("scales");          /* if not, abort the function */
  GET_TOK();                    /* consume 'scales' */
  GET_CHR('=');                 /* consume '=' */
  for (k = 0; (dim <= 0) || (k < dim); k++) {
    if (k > 0) { GET_CHR(',');} /* if not first, consume ',' */
    if (k >= n) {               /* if the statistics vector is full */
      if (dim > 0) n  = dim;    /* compute the new vector size */
      else         n += (n > BLKSIZE) ? n >> 1 : BLKSIZE;
      p = (double*)realloc(*buf, (n+n) *sizeof(double));
      if (!p) ERROR(E_NOMEM);   /* enlarge the buffer vector */
      *buf = p;                 /* and set the new vector, */
    }                           /* then note factor and offset */
    p = *buf +k +k;             /* get the element to set */
    GET_CHR('[');               /* consume '[' */
    if (sc_token(scan) != T_NUM) ERROR(E_NUMEXP);
    p[0] = strtod(sc_value(scan), NULL);
    GET_TOK();                  /* consume the offset */
    GET_CHR(',');               /* consume '[' */
    if (sc_token(scan) != T_NUM) ERROR(E_NUMEXP);
    p[1] = strtod(sc_value(scan), NULL);
    GET_TOK();                  /* consume the factor */
    GET_CHR(']');               /* consume '[' */
    if ((dim <= 0) && (sc_token(scan) != ',')) {
      k++; break; }             /* check for more scaling params. */
  }
  GET_CHR(';');                 /* consume ';' */
  return k;                     /* return 'ok' */
}  /* _parse() */
Ejemplo n.º 6
0
    ::std::unique_ptr<TokenStream> expand(const Span& sp, const ::AST::Crate& crate, const ::std::string& ident, const TokenTree& tt, AST::Module& mod) override
    {
        Token   tok;
        auto lex = TTStream(sp, tt);
        if( ident != "" )
            ERROR(sp, E0000, "asm! doesn't take an ident");

        auto template_text = get_string(sp, lex,  crate, mod);
        ::std::vector<::AST::ExprNode_Asm::ValRef>  outputs;
        ::std::vector<::AST::ExprNode_Asm::ValRef>  inputs;
        ::std::vector<::std::string>    clobbers;
        ::std::vector<::std::string>    flags;

        // Outputs
        if( lex.lookahead(0) == TOK_DOUBLE_COLON )
        {
            GET_TOK(tok, lex);
            lex.putback(Token(TOK_COLON));
        }
        else if( lex.lookahead(0) == TOK_COLON )
        {
            GET_TOK(tok, lex);

            while( lex.lookahead(0) == TOK_STRING )
            {
                //auto name = get_string(sp, lex);
                GET_CHECK_TOK(tok, lex, TOK_STRING);
                auto name = mv$(tok.str());

                GET_CHECK_TOK(tok, lex, TOK_PAREN_OPEN);
                auto val = Parse_Expr0(lex);
                GET_CHECK_TOK(tok, lex, TOK_PAREN_CLOSE);

                outputs.push_back( ::AST::ExprNode_Asm::ValRef { mv$(name), mv$(val) } );

                if( lex.lookahead(0) != TOK_COMMA )
                    break;

                GET_TOK(tok, lex);
            }
        }
        else
        {
        }

        // Inputs
        if( lex.lookahead(0) == TOK_DOUBLE_COLON )
        {
            GET_TOK(tok, lex);
            lex.putback(Token(TOK_COLON));
        }
        else if( lex.lookahead(0) == TOK_COLON )
        {
            GET_TOK(tok, lex);

            while( lex.lookahead(0) == TOK_STRING )
            {
                GET_CHECK_TOK(tok, lex, TOK_STRING);
                auto name = mv$(tok.str());

                GET_CHECK_TOK(tok, lex, TOK_PAREN_OPEN);
                auto val = Parse_Expr0(lex);
                GET_CHECK_TOK(tok, lex, TOK_PAREN_CLOSE);

                inputs.push_back( ::AST::ExprNode_Asm::ValRef { mv$(name), mv$(val) } );

                if( lex.lookahead(0) != TOK_COMMA )
                    break;
                GET_TOK(tok, lex);
            }
        }
        else
        {
        }

        // Clobbers
        if( lex.lookahead(0) == TOK_DOUBLE_COLON )
        {
            GET_TOK(tok, lex);
            lex.putback(Token(TOK_COLON));
        }
        else if( lex.lookahead(0) == TOK_COLON )
        {
            GET_TOK(tok, lex);

            while( lex.lookahead(0) == TOK_STRING )
            {
                GET_CHECK_TOK(tok, lex, TOK_STRING);
                clobbers.push_back( mv$(tok.str()) );

                if( lex.lookahead(0) != TOK_COMMA )
                    break;
                GET_TOK(tok, lex);
            }
        }
        else
        {
        }

        // Flags
        if( lex.lookahead(0) == TOK_DOUBLE_COLON )
        {
            GET_TOK(tok, lex);
            lex.putback(Token(TOK_COLON));
        }
        else if( lex.lookahead(0) == TOK_COLON )
        {
            GET_TOK(tok, lex);

            while( lex.lookahead(0) == TOK_STRING )
            {
                GET_CHECK_TOK(tok, lex, TOK_STRING);
                flags.push_back( mv$(tok.str()) );

                if( lex.lookahead(0) != TOK_COMMA )
                    break;
                GET_TOK(tok, lex);
            }
        }
        else
        {
        }

        // trailing `: voltaile` - TODO: Is this valid?
        if( lex.lookahead(0) == TOK_DOUBLE_COLON )
        {
            GET_TOK(tok, lex);
            lex.putback(Token(TOK_COLON));
        }
        else if( lex.lookahead(0) == TOK_COLON )
        {
            GET_TOK(tok, lex);

            if( GET_TOK(tok, lex) == TOK_IDENT && tok.str() == "volatile" )
            {
                flags.push_back( "volatile" );
            }
            else
            {
                PUTBACK(tok, lex);
            }
        }
        else
        {
        }

        // has to be the end
        if( lex.lookahead(0) != TOK_EOF )
        {
            ERROR(sp, E0000, "Unexpected token in asm! - " << lex.getToken());
        }

        // Convert this into an AST node and insert as an intepolated expression
        ::AST::ExprNodeP rv = ::AST::ExprNodeP( new ::AST::ExprNode_Asm { mv$(template_text), mv$(outputs), mv$(inputs), mv$(clobbers), mv$(flags) } );
        return box$( TTStreamO(sp, TokenTree(Token( InterpolatedFragment(InterpolatedFragment::EXPR, rv.release()) ))));
    }
Ejemplo n.º 7
0
TypeRef Parse_Type_Int(TokenStream& lex, bool allow_trait_list)
{
    //TRACE_FUNCTION;
    auto ps = lex.start_span();

    Token tok;

    switch( GET_TOK(tok, lex) )
    {
    case TOK_INTERPOLATED_TYPE:
        return mv$(tok.frag_type());
    // '!' - Only ever used as part of function prototypes, but is kinda a type... not allowed here though
    case TOK_EXCLAM:
        return TypeRef( Span(tok.get_pos()), TypeData::make_Bang({}) );
    // '_' = Wildcard (type inferrence variable)
    case TOK_UNDERSCORE:
        return TypeRef(Span(tok.get_pos()));

    // 'unsafe' - An unsafe function type
    case TOK_RWORD_UNSAFE:
    // 'extern' - A function type with an ABI
    case TOK_RWORD_EXTERN:
    // 'fn' - Rust function
    case TOK_RWORD_FN:
        PUTBACK(tok, lex);
        return Parse_Type_Fn(lex);

    case TOK_RWORD_IMPL:
        return Parse_Type_ErasedType(lex, allow_trait_list);

    // '<' - An associated type cast
    case TOK_LT:
    case TOK_DOUBLE_LT: {
        PUTBACK(tok, lex);
        auto path = Parse_Path(lex, PATH_GENERIC_TYPE);
        return TypeRef(TypeRef::TagPath(), lex.end_span(mv$(ps)), mv$(path));
        }
    //
    case TOK_RWORD_FOR: {
        auto hrls = Parse_HRB(lex);
        switch(LOOK_AHEAD(lex))
        {
        case TOK_RWORD_UNSAFE:
        case TOK_RWORD_EXTERN:
        case TOK_RWORD_FN:
            return Parse_Type_Fn(lex, hrls);
        default:
            return Parse_Type_Path(lex, hrls, true);
        }
        }
    // <ident> - Either a primitive, or a path
    case TOK_IDENT:
        if( lex.lookahead(0) == TOK_EXCLAM )
        {
            lex.getToken();
            // TODO: path macros
            return TypeRef(TypeRef::TagMacro(), Parse_MacroInvocation(ps, mv$(tok.str()), lex));
        }
        // or a primitive
        //if( auto ct = coretype_fromstring(tok.str()) )
        //{
        //    return TypeRef(TypeRef::TagPrimitive(), Span(tok.get_pos()), ct);
        //}
        PUTBACK(tok, lex);
        return Parse_Type_Path(lex, {}, allow_trait_list);
        // - Fall through to path handling
    // '::' - Absolute path
    case TOK_DOUBLE_COLON:
    // 'self' - This relative path
    case TOK_RWORD_SELF:
    // 'super' - Parent relative path
    case TOK_RWORD_SUPER:
    // ':path' fragment
    case TOK_INTERPOLATED_PATH:
        PUTBACK(tok, lex);
        return Parse_Type_Path(lex, {}, allow_trait_list);

    // HACK! Convert && into & &
    case TOK_DOUBLE_AMP:
        lex.putback(Token(TOK_AMP));
    // '&' - Reference type
    case TOK_AMP: {
        AST::LifetimeRef lifetime;
        // Reference
        tok = lex.getToken();
        if( tok.type() == TOK_LIFETIME ) {
            lifetime = AST::LifetimeRef(/*lex.point_span(), */lex.get_ident(::std::move(tok)));
            tok = lex.getToken();
        }
        bool is_mut = false;
        if( tok.type() == TOK_RWORD_MUT ) {
            is_mut = true;
        }
        else {
            PUTBACK(tok, lex);
        }
        return TypeRef(TypeRef::TagReference(), lex.end_span(mv$(ps)), ::std::move(lifetime), is_mut, Parse_Type(lex, false));
        }
    // '*' - Raw pointer
    case TOK_STAR:
        // Pointer
        switch( GET_TOK(tok, lex) )
        {
        case TOK_RWORD_MUT:
            // Mutable pointer
            return TypeRef(TypeRef::TagPointer(), lex.end_span(mv$(ps)), true, Parse_Type(lex, false));
        case TOK_RWORD_CONST:
            // Immutable pointer
            return TypeRef(TypeRef::TagPointer(), lex.end_span(mv$(ps)), false, Parse_Type(lex, false));
        default:
            throw ParseError::Unexpected(lex, tok, {TOK_RWORD_CONST, TOK_RWORD_MUT});
        }
        throw ParseError::BugCheck("Reached end of Parse_Type:STAR");
    // '[' - Array type
    case TOK_SQUARE_OPEN: {
        // Array
        TypeRef inner = Parse_Type(lex);
        if( GET_TOK(tok, lex)  == TOK_SEMICOLON ) {
            // Sized array
            AST::Expr array_size = Parse_Expr(lex);
            GET_CHECK_TOK(tok, lex, TOK_SQUARE_CLOSE);
            return TypeRef(TypeRef::TagSizedArray(), lex.end_span(mv$(ps)), mv$(inner), array_size.take_node());
        }
        else if( tok.type() == TOK_SQUARE_CLOSE )
        {
            return TypeRef(TypeRef::TagUnsizedArray(), lex.end_span(mv$(ps)), mv$(inner));
        }
        else {
            throw ParseError::Unexpected(lex, tok/*, "; or ]"*/);
        }
        }

    // '(' - Tuple (or lifetime bounded trait)
    case TOK_PAREN_OPEN: {
        DEBUG("Tuple");
        if( GET_TOK(tok, lex) == TOK_PAREN_CLOSE )
            return TypeRef(TypeRef::TagTuple(), lex.end_span(mv$(ps)), {});
        PUTBACK(tok, lex);

        TypeRef inner = Parse_Type(lex, true);
        if( LOOK_AHEAD(lex) == TOK_PAREN_CLOSE )
        {
            // Type in parens, NOT a tuple
            GET_CHECK_TOK(tok, lex, TOK_PAREN_CLOSE);
            return inner;
        }
        else
        {
            ::std::vector<TypeRef>  types;
            types.push_back( mv$(inner) );
            while( GET_TOK(tok, lex) == TOK_COMMA )
            {
                if( GET_TOK(tok, lex) == TOK_PAREN_CLOSE )
                    break;
                else
                    PUTBACK(tok, lex);
                types.push_back( Parse_Type(lex) );
            }
            CHECK_TOK(tok, TOK_PAREN_CLOSE);
            return TypeRef(TypeRef::TagTuple(), lex.end_span(mv$(ps)), mv$(types)); }
        }
    default:
        throw ParseError::Unexpected(lex, tok);
    }
    throw ParseError::BugCheck("Reached end of Parse_Type");
}
Ejemplo n.º 8
0
TypeRef Parse_Type_Fn(TokenStream& lex, ::AST::HigherRankedBounds hrbs)
{
    auto ps = lex.start_span();
    TRACE_FUNCTION;
    Token   tok;

    ::std::string   abi = "";
    bool    is_unsafe = false;

    GET_TOK(tok, lex);

    // `unsafe`
    if( tok.type() == TOK_RWORD_UNSAFE )
    {
        is_unsafe = true;
        GET_TOK(tok, lex);
    }
    // `exern`
    if( tok.type() == TOK_RWORD_EXTERN )
    {
        if( GET_TOK(tok, lex) == TOK_STRING ) {
            abi = tok.str();
            if( abi == "" )
                ERROR(lex.point_span(), E0000, "Empty ABI");
            GET_TOK(tok, lex);
        }
        else {
            abi = "C";
        }
    }
    // `fn`
    CHECK_TOK(tok, TOK_RWORD_FN);

    ::std::vector<TypeRef>  args;
    bool is_variadic = false;
    GET_CHECK_TOK(tok, lex, TOK_PAREN_OPEN);
    while( LOOK_AHEAD(lex) != TOK_PAREN_CLOSE )
    {
        if( LOOK_AHEAD(lex) == TOK_TRIPLE_DOT ) {
            GET_TOK(tok, lex);
            is_variadic = true;
            break;
        }
        // Handle `ident: `
        if( (lex.lookahead(0) == TOK_IDENT || lex.lookahead(0) == TOK_UNDERSCORE) && lex.lookahead(1) == TOK_COLON ) {
            GET_TOK(tok, lex);
            GET_TOK(tok, lex);
        }
        args.push_back( Parse_Type(lex) );
        if( GET_TOK(tok, lex) != TOK_COMMA ) {
            PUTBACK(tok, lex);
            break;
        }
    }
    GET_CHECK_TOK(tok, lex, TOK_PAREN_CLOSE);

    // `-> RetType`
    TypeRef ret_type = TypeRef(TypeRef::TagUnit(), Span(tok.get_pos()));
    if( GET_TOK(tok, lex) == TOK_THINARROW )
    {
        ret_type = Parse_Type(lex, false);
    }
    else {
        PUTBACK(tok, lex);
    }

    return TypeRef(TypeRef::TagFunction(), lex.end_span(mv$(ps)), mv$(hrbs), is_unsafe, mv$(abi), mv$(args), is_variadic, mv$(ret_type));
}
Ejemplo n.º 9
0
/// Parse the pattern of a macro_rules! arm
::std::vector<MacroPatEnt> Parse_MacroRules_Pat(TokenStream& lex, enum eTokenType open, enum eTokenType close,  ::std::vector< ::std::string>& names)
{
    TRACE_FUNCTION;
    Token tok;

    ::std::vector<MacroPatEnt>  ret;

     int    depth = 0;
    while( GET_TOK(tok, lex) != close || depth > 0 )
    {
        if( tok.type() == open )
        {
            depth ++;
        }
        else if( tok.type() == close )
        {
            if(depth == 0)
                throw ParseError::Generic(FMT("Unmatched " << Token(close) << " in macro pattern"));
            depth --;
        }

        switch(tok.type())
        {
        case TOK_DOLLAR:
            switch( GET_TOK(tok, lex) )
            {
            // TODO: Allow any reserved word
            case TOK_RWORD_TYPE:
            case TOK_RWORD_PUB:
            case TOK_IDENT: {
                ::std::string   name = tok.type() == TOK_IDENT ? mv$(tok.str()) : FMT(tok);
                GET_CHECK_TOK(tok, lex, TOK_COLON);
                GET_CHECK_TOK(tok, lex, TOK_IDENT);
                ::std::string   type = mv$(tok.str());

                unsigned int idx = ::std::find( names.begin(), names.end(), name ) - names.begin();
                if( idx == names.size() )
                    names.push_back( name );

                if(0)
                    ;
                else if( type == "tt" )
                    ret.push_back( MacroPatEnt(name, idx, MacroPatEnt::PAT_TT) );
                else if( type == "pat" )
                    ret.push_back( MacroPatEnt(name, idx, MacroPatEnt::PAT_PAT) );
                else if( type == "ident" )
                    ret.push_back( MacroPatEnt(name, idx, MacroPatEnt::PAT_IDENT) );
                else if( type == "path" )
                    ret.push_back( MacroPatEnt(name, idx, MacroPatEnt::PAT_PATH) );
                else if( type == "expr" )
                    ret.push_back( MacroPatEnt(name, idx, MacroPatEnt::PAT_EXPR) );
                else if( type == "stmt" )
                    ret.push_back( MacroPatEnt(name, idx, MacroPatEnt::PAT_STMT) );
                else if( type == "ty" )
                    ret.push_back( MacroPatEnt(name, idx, MacroPatEnt::PAT_TYPE) );
                else if( type == "meta" )
                    ret.push_back( MacroPatEnt(name, idx, MacroPatEnt::PAT_META) );
                else if( type == "block" )
                    ret.push_back( MacroPatEnt(name, idx, MacroPatEnt::PAT_BLOCK) );
                else if( type == "item" )
                    ret.push_back( MacroPatEnt(name, idx, MacroPatEnt::PAT_ITEM) );
                else
                    ERROR(lex.point_span(), E0000, "Unknown fragment type '" << type << "'");
                break; }
            case TOK_PAREN_OPEN: {
                auto subpat = Parse_MacroRules_Pat(lex, TOK_PAREN_OPEN, TOK_PAREN_CLOSE, names);
                enum eTokenType joiner = TOK_NULL;
                GET_TOK(tok, lex);
                if( tok.type() != TOK_PLUS && tok.type() != TOK_STAR )
                {
                    DEBUG("joiner = " << tok);
                    joiner = tok.type();
                    GET_TOK(tok, lex);
                }
                DEBUG("tok = " << tok);
                switch(tok.type())
                {
                case TOK_PLUS:
                    DEBUG("$()+ " << subpat);
                    ret.push_back( MacroPatEnt(Token(joiner), true, ::std::move(subpat)) );
                    break;
                case TOK_STAR:
                    DEBUG("$()* " << subpat);
                    ret.push_back( MacroPatEnt(Token(joiner), false, ::std::move(subpat)) );
                    break;
                default:
                    throw ParseError::Unexpected(lex, tok);
                }
                break; }
            default:
                throw ParseError::Unexpected(lex, tok);
            }
            break;
        case TOK_EOF:
            throw ParseError::Unexpected(lex, tok);
        default:
            ret.push_back( MacroPatEnt(tok) );
            break;
        }
    }

    return ret;
}
Ejemplo n.º 10
0
/// Parse the contents (replacement) of a macro_rules! arm
::std::vector<MacroExpansionEnt> Parse_MacroRules_Cont(
    TokenStream& lex,
    enum eTokenType open, enum eTokenType close,
    const ::std::vector< ::std::string>& var_names,
    ::std::map<unsigned int,bool>* var_set_ptr=nullptr
    )
{
    TRACE_FUNCTION;

    Token tok;
    ::std::vector<MacroExpansionEnt> ret;

     int    depth = 0;
    while( GET_TOK(tok, lex) != close || depth > 0 )
    {
        if( tok.type() == TOK_EOF ) {
            throw ParseError::Unexpected(lex, tok);
        }
        if( tok.type() == TOK_NULL )
            continue ;

        if( tok.type() == open )
        {
            DEBUG("depth++");
            depth ++;
        }
        else if( tok.type() == close )
        {
            DEBUG("depth--");
            if(depth == 0)
                ERROR(lex.point_span(), E0000, "Unmatched " << Token(close) << " in macro content");
            depth --;
        }

        // `$` - Macro metavars
        if( tok.type() == TOK_DOLLAR )
        {
            GET_TOK(tok, lex);

            // `$(`
            if( tok.type() == TOK_PAREN_OPEN )
            {
                ::std::map<unsigned int, bool> var_set;
                auto content = Parse_MacroRules_Cont(lex, TOK_PAREN_OPEN, TOK_PAREN_CLOSE, var_names, &var_set);
                // ^^ The above will eat the PAREN_CLOSE

                GET_TOK(tok, lex);
                enum eTokenType joiner = TOK_NULL;
                if( tok.type() != TOK_PLUS && tok.type() != TOK_STAR )
                {
                    joiner = tok.type();
                    GET_TOK(tok, lex);
                }
                bool is_optional = (tok.type() == TOK_STAR);
                if( var_set_ptr ) {
                    for(const auto& v : var_set) {
                        // If `is_optional`: Loop may not be expanded, so var_not_opt=false
                        // Else, inherit
                        bool var_not_opt = (is_optional ? false : v.second);
                        var_set_ptr->insert( ::std::make_pair(v.first, var_not_opt) ).first->second |= var_not_opt;
                    }
                }
                DEBUG("joiner = " << Token(joiner) << ", content = " << content);
                switch(tok.type())
                {
                case TOK_PLUS:
                case TOK_STAR:
                    // TODO: Ensure that +/* match up?
                    ret.push_back( MacroExpansionEnt({mv$(content), joiner, mv$(var_set)}) );
                    break;
                default:
                    throw ParseError::Unexpected(lex, tok);
                }

            }
            //else if( tok.type() == TOK_IDENT || tok_is_rword(tok.type()) )
            else if( tok.type() == TOK_IDENT || tok.type() == TOK_RWORD_TYPE || tok.type() == TOK_RWORD_PUB )
            {
                // Look up the named parameter in the list of param names for this arm
                auto name = tok.type() == TOK_IDENT ? tok.str() : FMT(tok);
                unsigned int idx = ::std::find(var_names.begin(), var_names.end(), name) - var_names.begin();
                if( idx == var_names.size() ) {
                    // TODO: `error-chain`'s quick_error macro has an arm which refers to an undefined metavar.
                    // - Maybe emit a warning and use a marker index.
                    WARNING(lex.point_span(), W0000, "Macro variable $" << name << " not found");
                    // Emit the literal $ <name>
                    ret.push_back( MacroExpansionEnt(Token(TOK_DOLLAR)) );
                    ret.push_back( MacroExpansionEnt(mv$(tok)) );
                    continue ;
                }
                if( var_set_ptr ) {
                    var_set_ptr->insert( ::std::make_pair(idx,true) );
                }
                ret.push_back( MacroExpansionEnt(idx) );
            }
            else if( tok.type() == TOK_RWORD_CRATE )
            {
                ret.push_back( MacroExpansionEnt( (1<<30) | 0 ) );
            }
            else
            {
                throw ParseError::Unexpected(lex, tok);
            }
        }
        else
        {
            ret.push_back( MacroExpansionEnt( mv$(tok) ) );
        }
    }

    return ret;
}
Ejemplo n.º 11
0
static int _domains (ATTSET *set, SCAN *scan, int tflags)
{                               /* --- parse attribute domains */
  ATT        *att;              /* attribute read */
  int        type;              /* attribute type */
  int        t;                 /* temporary buffer */
  double     wgt;               /* buffer for attribute weight */
  const char *v;                /* token value */

  while ((sc_token(scan) == T_ID) /* parse domain definitions */
  &&     ((strcmp(sc_value(scan), "dom")    == 0)
  ||      (strcmp(sc_value(scan), "domain") == 0))) {
    GET_TOK();                  /* consume 'dom' */
    GET_CHR('(');               /* consume '(' */
    t = sc_token(scan);         /* check next token for a valid name */
    if ((t != T_ID) && (t != T_NUM)) ERROR(E_ATTEXP);
    att = att_create(sc_value(scan), AT_NOM);
    if (!att) ERROR(E_NOMEM);   /* create an attribute and */
    t = as_attadd(set, att);    /* add it to the attribute set */
    if (t) { att_delete(att); ERROR((t > 0) ? E_DUPATT : E_NOMEM); }
    GET_TOK();                  /* consume attribute name */
    GET_CHR(')');               /* consume ')' */
    GET_CHR('=');               /* consume '=' */
    type = -1;                  /* init. attribute type to 'none' */
    t = sc_token(scan);         /* test next token */
    if      (t == '{')          /* if a set of values follows, */
      type = tflags & AT_NOM;   /* attribute is nominal */
    else if (t == T_ID) {       /* if an identifier follows */
      v = sc_value(scan);       /* get it for simpler comparisons */
      if      ((strcmp(v, "ZZ")      == 0)
      ||       (strcmp(v, "Z")       == 0)
      ||       (strcmp(v, "int")     == 0)
      ||       (strcmp(v, "integer") == 0))
        type = tflags & AT_INT; /* attribute is integer-valued */
      else if ((strcmp(v, "IR")      == 0)
      ||       (strcmp(v, "R")       == 0)
      ||       (strcmp(v, "real")    == 0)
      ||       (strcmp(v, "float")   == 0))
        type = tflags & AT_REAL;/* attribute is real-valued */
    }                           /* (get and check attribute type) */
    if (type <= 0) ERROR(E_DOMAIN);
    att->type = type;           /* set attribute type */
    if (type != AT_NOM) {       /* if attribute is numeric */
      GET_TOK();                /* consume type indicator */
      if (type == AT_INT) {     /* if attribute is integer-valued */
        att->min.i =  INT_MAX;  /* initialize minimal */
        att->max.i = -INT_MAX;} /* and maximal value */
      else {                    /* if attribute is real-valued */
        att->min.f =  FLT_MAX;  /* initialize minimal */
        att->max.f = -FLT_MAX;  /* and maximal value */
      }
      if (sc_token(scan) == '[') { /* if a range of values is given */
        GET_TOK();              /* consume '[' */
        if (sc_token(scan) != T_NUM) ERROR(E_NUMEXP);
        if (att_valadd(att, sc_value(scan), NULL) != 0)
          ERROR(E_NUMBER);      /* get and check lower bound */
        GET_TOK();              /* consume lower bound */
        GET_CHR(',');           /* consume ',' */
        if (sc_token(scan) != T_NUM) ERROR(E_NUMEXP);
        if (att_valadd(att, sc_value(scan), NULL) != 0)
          ERROR(E_NUMBER);      /* get and check upper bound */
        GET_TOK();              /* consume upper bound */
        GET_CHR(']');           /* consume ']' */
      } }
    else {                      /* if attribute is nominal */
      GET_CHR('{');             /* consume '{' */
      if (sc_token(scan) != '}') {
        while (1) {             /* read a list of values */
          t = sc_token(scan);   /* check for a name */
          if ((t != T_ID) && (t != T_NUM)) ERROR(E_VALEXP);
          t = att_valadd(att, sc_value(scan), NULL);
          if (t) ERROR((t > 0) ? E_DUPVAL : E_NOMEM);
          GET_TOK();            /* get and consume attribute value */
          if (sc_token(scan) != ',') break;
          GET_TOK();            /* if at end of list, abort loop, */
        }                       /* otherwise consume ',' */
      }
      GET_CHR('}');             /* consume '}' */
    }
    if (sc_token(scan) == ':'){ /* if a direction indication follows */
      GET_TOK();                /* consume ',' */
      if (sc_token(scan) != T_ID) ERR_STR("in");
      v = sc_value(scan);       /* get the direction indicator */
      if      (strcmp(v, "none") == 0) att->dir = DIR_NONE;
      else if (strcmp(v, "in")   == 0) att->dir = DIR_IN;
      else if (strcmp(v, "out")  == 0) att->dir = DIR_OUT;
      else if (strcmp(v, "id")   == 0) att->dir = DIR_ID;
      else if (strcmp(v, "wgt")  == 0) att->dir = DIR_WGT;
      else ERR_STR("in");       /* get the direction code */
      GET_TOK();                /* and consume the token */
    }
    if (sc_token(scan) == ','){ /* if a weight indication follows */
      if (sc_token(scan) != T_NUM)             ERROR(E_NUMEXP);
      wgt = atof(sc_value(scan));     /* get the attribute weight */
      if ((wgt <= NV_REAL) || (wgt > FLT_MAX)) ERROR(E_NUMBER);
      att->weight = (float)wgt; /* check and set attribute weight */
      GET_TOK();                /* and consume the token */
    }
    GET_CHR(';');               /* consume ';' */
  }  /* while ((sc_token(scan) == T_ID) .. */
  return 0;                     /* return 'ok' */
}  /* _domains() */