//
// AttributesParser.cpp
//
// Library: CppParser
// Package: Attributes
// Module:  AttributesParser
//
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier:	BSL-1.0
//


#include "Poco/CppParser/AttributesParser.h"
#include "Poco/CppParser/CppToken.h"
#include "Poco/Exception.h"


using Poco::Token;
using Poco::SyntaxException;


namespace Poco {
namespace CppParser {


AttributesParser::AttributesParser(Attributes& attrs, std::istream& istr):
	_attrs(attrs),
	_tokenizer(istr)
{
}


AttributesParser::~AttributesParser()
{
}


void AttributesParser::parse()
{
	const Token* pNext = next();
	if (!isEOF(pNext))
	{
		pNext = parseAttributes(pNext);
	}
	if (!isEOF(pNext))
		throw Poco::SyntaxException("extra tokens found in attribute declaration");
}


const Token* AttributesParser::parseAttributes(const Token* pNext)
{
	pNext = parseAttribute(pNext);
	while (isOperator(pNext, OperatorToken::OP_COMMA) || isIdentifier(pNext))
	{
		if (!isIdentifier(pNext)) pNext = next();
		pNext = parseAttribute(pNext);
	}
	return pNext;
}


const Token* AttributesParser::parseAttribute(const Token* pNext)
{
	std::string id;
	std::string value;
	pNext = parseIdentifier(pNext, id);
	if (isOperator(pNext, OperatorToken::OP_ASSIGN))
	{
		pNext = next();
		if (isOperator(pNext, OperatorToken::OP_OPENBRACE))
		{
			pNext = parseComplexAttribute(pNext, id);
		}
		else if (isIdentifier(pNext) || isLiteral(pNext))
		{
			value = pNext->asString();
			pNext = next();
		}
		else throw SyntaxException("bad attribute declaration");
	}
	setAttribute(id, value);
	return pNext;
}


const Token* AttributesParser::parseComplexAttribute(const Token* pNext, const std::string& id)
{
	poco_assert_dbg (isOperator(pNext, OperatorToken::OP_OPENBRACE));

	pNext = next();
	std::string oldId(_id);
	if (!_id.empty())
	{
		_id.append(".");
		_id.append(id);
	}
	else _id = id;
	pNext = parseAttributes(pNext);
	_id = oldId;
	if (isOperator(pNext, OperatorToken::OP_CLOSBRACE))
		pNext = next();
	else
		throw SyntaxException("bad attribute declaration");

	return pNext;
}


const Token* AttributesParser::parseIdentifier(const Token* pNext, std::string& id)
{
	if (isIdentifier(pNext))
	{
		id = pNext->asString();
		pNext = next();
		while (isOperator(pNext, OperatorToken::OP_PERIOD))
		{
			id.append(".");
			pNext = next();
			if (isIdentifier(pNext))
			{
				id.append(pNext->asString());
				pNext = next();
			}
			else throw SyntaxException("identifier expected");
		}
		return pNext;
	}
	else throw SyntaxException("identifier expected");
}


void AttributesParser::setAttribute(const std::string& name, const std::string& value)
{
	std::string n;
	if (!_id.empty())
	{
		n.append(_id);
		n.append(".");
	}
	n.append(name);
	_attrs.set(n, value);
}


} } // namespace Poco::CppParser
