// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use syntax::ast;
use syntax::ext::base::*;
use syntax::ext::base;
use syntax::feature_gate;
use syntax::parse::token;
use syntax::ptr::P;
use syntax_pos::Span;
use syntax_pos::symbol::Symbol;
use syntax_pos::hygiene::SyntaxContext;
use syntax::tokenstream::TokenTree;

pub fn expand_syntax_ext<'cx>(cx: &'cx mut ExtCtxt,
                              sp: Span,
                              tts: &[TokenTree])
                              -> Box<base::MacResult + 'cx> {
    if !cx.ecfg.enable_concat_idents() {
        feature_gate::emit_feature_err(&cx.parse_sess,
                                       "concat_idents",
                                       sp,
                                       feature_gate::GateIssue::Language,
                                       feature_gate::EXPLAIN_CONCAT_IDENTS);
        return base::DummyResult::expr(sp);
    }

    let mut res_str = String::new();
    for (i, e) in tts.iter().enumerate() {
        if i & 1 == 1 {
            match *e {
                TokenTree::Token(_, token::Comma) => {}
                _ => {
                    cx.span_err(sp, "concat_idents! expecting comma.");
                    return DummyResult::expr(sp);
                }
            }
        } else {
            match *e {
                TokenTree::Token(_, token::Ident(ident)) => res_str.push_str(&ident.name.as_str()),
                _ => {
                    cx.span_err(sp, "concat_idents! requires ident args.");
                    return DummyResult::expr(sp);
                }
            }
        }
    }
    let res = ast::Ident {
        name: Symbol::intern(&res_str),
        ctxt: SyntaxContext::empty().apply_mark(cx.current_expansion.mark),
    };

    struct Result {
        ident: ast::Ident,
        span: Span,
    };

    impl Result {
        fn path(&self) -> ast::Path {
            ast::Path {
                span: self.span,
                segments: vec![ast::PathSegment::from_ident(self.ident, self.span)],
            }
        }
    }

    impl base::MacResult for Result {
        fn make_expr(self: Box<Self>) -> Option<P<ast::Expr>> {
            Some(P(ast::Expr {
                id: ast::DUMMY_NODE_ID,
                node: ast::ExprKind::Path(None, self.path()),
                span: self.span,
                attrs: ast::ThinVec::new(),
            }))
        }

        fn make_ty(self: Box<Self>) -> Option<P<ast::Ty>> {
            Some(P(ast::Ty {
                id: ast::DUMMY_NODE_ID,
                node: ast::TyKind::Path(None, self.path()),
                span: self.span,
            }))
        }
    }

    Box::new(Result {
        ident: res,
        span: sp.with_ctxt(sp.ctxt().apply_mark(cx.current_expansion.mark)),
    })
}
