/*
	This file is part of solidity.
	solidity is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.
	solidity is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.
	You should have received a copy of the GNU General Public License
	along with solidity.  If not, see .
*/
// SPDX-License-Identifier: GPL-3.0
/**
 * @author julius 
 * @date 2019
 *Component that imports an AST from json format to the internal format
 */
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
namespace solidity::frontend
{
using SourceLocation = langutil::SourceLocation;
template
ASTPointer ASTJsonImporter::nullOrCast(Json::Value const& _json)
{
	if (_json.isNull())
		return nullptr;
	else
		return dynamic_pointer_cast(convertJsonToASTNode(_json));
}
// ============ public ===========================
map> ASTJsonImporter::jsonToSourceUnit(map const& _sourceList)
{
	m_sourceList = _sourceList;
	for (auto const& src: _sourceList)
		m_sourceLocations.emplace_back(make_shared(src.first));
	for (auto const& srcPair: m_sourceList)
	{
		astAssert(!srcPair.second.isNull(), "");
		astAssert(member(srcPair.second,"nodeType") == "SourceUnit", "The 'nodeType' of the highest node must be 'SourceUnit'.");
		m_currentSourceName = srcPair.first;
		m_sourceUnits[srcPair.first] = createSourceUnit(srcPair.second, srcPair.first);
	}
	return m_sourceUnits;
}
// ============ private ===========================
// =========== general creation functions ==============
template 
ASTPointer ASTJsonImporter::createASTNode(Json::Value const& _node, Args&&... _args)
{
	astAssert(member(_node, "id").isInt64(), "'id'-field must be 64bit integer.");
	int64_t id = _node["id"].asInt64();
	astAssert(m_usedIDs.insert(id).second, "Found duplicate node ID!");
	auto n = make_shared(
		id,
		createSourceLocation(_node),
		forward(_args)...
	);
	return n;
}
SourceLocation const ASTJsonImporter::createSourceLocation(Json::Value const& _node)
{
	astAssert(member(_node, "src").isString(), "'src' must be a string");
	return solidity::langutil::parseSourceLocation(_node["src"].asString(), m_currentSourceName, m_sourceLocations.size());
}
template
ASTPointer ASTJsonImporter::convertJsonToASTNode(Json::Value const& _node)
{
	ASTPointer ret = dynamic_pointer_cast(convertJsonToASTNode(_node));
	astAssert(ret, "cast of converted json-node must not be nullptr");
	return ret;
}
ASTPointer ASTJsonImporter::convertJsonToASTNode(Json::Value const& _json)
{
	astAssert(_json["nodeType"].isString() && _json.isMember("id"), "JSON-Node needs to have 'nodeType' and 'id' fields.");
	string nodeType = _json["nodeType"].asString();
	if (nodeType == "PragmaDirective")
		return createPragmaDirective(_json);
	if (nodeType == "ImportDirective")
		return createImportDirective(_json);
	if (nodeType == "ContractDefinition")
		return createContractDefinition(_json);
	if (nodeType == "InheritanceSpecifier")
		return createInheritanceSpecifier(_json);
	if (nodeType == "UsingForDirective")
		return createUsingForDirective(_json);
	if (nodeType == "StructDefinition")
		return createStructDefinition(_json);
	if (nodeType == "EnumDefinition")
		return createEnumDefinition(_json);
	if (nodeType == "EnumValue")
		return createEnumValue(_json);
	if (nodeType == "ParameterList")
		return createParameterList(_json);
	if (nodeType == "OverrideSpecifier")
		return createOverrideSpecifier(_json);
	if (nodeType == "FunctionDefinition")
		return createFunctionDefinition(_json);
	if (nodeType == "VariableDeclaration")
		return createVariableDeclaration(_json);
	if (nodeType == "ModifierDefinition")
		return createModifierDefinition(_json);
	if (nodeType == "ModifierInvocation")
		return createModifierInvocation(_json);
	if (nodeType == "EventDefinition")
		return createEventDefinition(_json);
	if (nodeType == "ElementaryTypeName")
		return createElementaryTypeName(_json);
	if (nodeType == "UserDefinedTypeName")
		return createUserDefinedTypeName(_json);
	if (nodeType == "FunctionTypeName")
		return createFunctionTypeName(_json);
	if (nodeType == "Mapping")
		return createMapping(_json);
	if (nodeType == "ArrayTypeName")
		return createArrayTypeName(_json);
	if (nodeType == "InlineAssembly")
		return createInlineAssembly(_json);
	if (nodeType == "Block")
		return createBlock(_json);
	if (nodeType == "PlaceholderStatement")
		return createPlaceholderStatement(_json);
	if (nodeType == "IfStatement")
		return createIfStatement(_json);
	if (nodeType == "TryCatchClause")
		return createTryCatchClause(_json);
	if (nodeType == "TryStatement")
		return createTryStatement(_json);
	if (nodeType == "WhileStatement")
		return createWhileStatement(_json, false);
	if (nodeType == "DoWhileStatement")
		return createWhileStatement(_json, true);
	if (nodeType == "ForStatement")
		return createForStatement(_json);
	if (nodeType == "Continue")
		return createContinue(_json);
	if (nodeType == "Break")
		return createBreak(_json);
	if (nodeType == "Return")
		return createReturn(_json);
	if (nodeType == "EmitStatement")
		return createEmitStatement(_json);
	if (nodeType == "Throw")
		return createThrow(_json);
	if (nodeType == "VariableDeclarationStatement")
		return createVariableDeclarationStatement(_json);
	if (nodeType == "ExpressionStatement")
		return createExpressionStatement(_json);
	if (nodeType == "Conditional")
		return createConditional(_json);
	if (nodeType == "Assignment")
		return createAssignment(_json);
	if (nodeType == "TupleExpression")
		return createTupleExpression(_json);
	if (nodeType == "UnaryOperation")
		return createUnaryOperation(_json);
	if (nodeType == "BinaryOperation")
		return createBinaryOperation(_json);
	if (nodeType == "FunctionCall")
		return createFunctionCall(_json);
	if (nodeType == "FunctionCallOptions")
		return createFunctionCallOptions(_json);
	if (nodeType == "NewExpression")
		return createNewExpression(_json);
	if (nodeType == "MemberAccess")
		return createMemberAccess(_json);
	if (nodeType == "IndexAccess")
		return createIndexAccess(_json);
	if (nodeType == "IndexRangeAccess")
		return createIndexRangeAccess(_json);
	if (nodeType == "Identifier")
		return createIdentifier(_json);
	if (nodeType == "ElementaryTypeNameExpression")
		return createElementaryTypeNameExpression(_json);
	if (nodeType == "Literal")
		return createLiteral(_json);
	if (nodeType == "StructuredDocumentation")
		return createDocumentation(_json);
	else
		astAssert(false, "Unknown type of ASTNode: " + nodeType);
}
// ============ functions to instantiate the AST-Nodes from Json-Nodes ==============
ASTPointer ASTJsonImporter::createSourceUnit(Json::Value const& _node, string const& _srcName)
{
	optional license;
	if (_node.isMember("license") && !_node["license"].isNull())
		license = _node["license"].asString();
	vector> nodes;
	for (auto& child: member(_node, "nodes"))
		nodes.emplace_back(convertJsonToASTNode(child));
	ASTPointer tmp = createASTNode(_node, license, nodes);
	tmp->annotation().path = _srcName;
	return tmp;
}
ASTPointer ASTJsonImporter::createPragmaDirective(Json::Value const& _node)
{
	vector tokens;
	vector literals;
	for (auto const& lit: member(_node, "literals"))
	{
		string l = lit.asString();
		literals.push_back(l);
		tokens.push_back(scanSingleToken(l));
	}
	return createASTNode(_node, tokens, literals);
}
ASTPointer ASTJsonImporter::createImportDirective(Json::Value const& _node)
{
	ASTPointer unitAlias = memberAsASTString(_node, "unitAlias");
	ASTPointer path = memberAsASTString(_node, "file");
	ImportDirective::SymbolAliasList symbolAliases;
	for (auto& tuple: member(_node, "symbolAliases"))
	{
		astAssert(tuple["local"].isNull() || tuple["local"].isString(), "expected 'local' to be a string or null!");
		symbolAliases.push_back({
			createIdentifier(tuple["foreign"]),
			tuple["local"].isNull() ? nullptr : make_shared(tuple["local"].asString()),
			createSourceLocation(tuple["foreign"])}
		);
	}
	ASTPointer tmp = createASTNode(
		_node,
		path,
		unitAlias,
		move(symbolAliases)
	);
	astAssert(_node["absolutePath"].isString(), "Expected 'absolutePath' to be a string!");
	tmp->annotation().absolutePath = _node["absolutePath"].asString();
	return tmp;
}
ASTPointer ASTJsonImporter::createContractDefinition(Json::Value const& _node)
{
	astAssert(_node["name"].isString(), "Expected 'name' to be a string!");
	std::vector> baseContracts;
	for (auto& base: _node["baseContracts"])
		baseContracts.push_back(createInheritanceSpecifier(base));
	std::vector> subNodes;
	for (auto& subnode: _node["nodes"])
		subNodes.push_back(convertJsonToASTNode(subnode));
	return createASTNode(
		_node,
		make_shared(_node["name"].asString()),
		_node["documentation"].isNull() ? nullptr : createDocumentation(member(_node, "documentation")),
		baseContracts,
		subNodes,
		contractKind(_node),
		memberAsBool(_node, "abstract")
	);
}
ASTPointer ASTJsonImporter::createInheritanceSpecifier(Json::Value const& _node)
{
	std::vector> arguments;
	for (auto& arg: member(_node, "arguments"))
		arguments.push_back(convertJsonToASTNode(arg));
	return createASTNode(
		_node,
		createUserDefinedTypeName(member(_node, "baseName")),
		member(_node, "arguments").isNull() ? nullptr : make_unique>>(arguments)
	);
}
ASTPointer ASTJsonImporter::createUsingForDirective(Json::Value const& _node)
{
	return createASTNode(
		_node,
		createUserDefinedTypeName(member(_node, "libraryName")),
		_node["typeName"].isNull() ? nullptr  : convertJsonToASTNode(_node["typeName"])
	);
}
ASTPointer ASTJsonImporter::createStructDefinition(Json::Value const& _node)
{
	std::vector> members;
	for (auto& member: _node["members"])
		members.push_back(createVariableDeclaration(member));
	return createASTNode(
		_node,
		memberAsASTString(_node, "name"),
		members
	);
}
ASTPointer ASTJsonImporter::createEnumDefinition(Json::Value const& _node)
{
	std::vector> members;
	for (auto& member: _node["members"])
		members.push_back(createEnumValue(member));
	return createASTNode(
		_node,
		memberAsASTString(_node, "name"),
		members
	);
}
ASTPointer ASTJsonImporter::createEnumValue(Json::Value const& _node)
{
	return createASTNode(
		_node,
		memberAsASTString(_node, "name")
	);
}
ASTPointer ASTJsonImporter::createParameterList(Json::Value const&  _node)
{
	std::vector> parameters;
	for (auto& param: _node["parameters"])
		parameters.push_back(createVariableDeclaration(param));
	return createASTNode(
		_node,
		parameters
	);
}
ASTPointer ASTJsonImporter::createOverrideSpecifier(Json::Value const&  _node)
{
	std::vector> overrides;
	for (auto& param: _node["overrides"])
		overrides.push_back(createUserDefinedTypeName(param));
	return createASTNode(
		_node,
		overrides
	);
}
ASTPointer ASTJsonImporter::createFunctionDefinition(Json::Value const&  _node)
{
	astAssert(_node["kind"].isString(), "Expected 'kind' to be a string!");
	Token kind;
	string kindStr = member(_node, "kind").asString();
	if (kindStr == "constructor")
		kind = Token::Constructor;
	else if (kindStr == "function")
		kind = Token::Function;
	else if (kindStr == "fallback")
		kind = Token::Fallback;
	else if (kindStr == "receive")
		kind = Token::Receive;
	else
		astAssert(false, "Expected 'kind' to be one of [constructor, function, fallback, receive]");
	std::vector> modifiers;
	for (auto& mod: member(_node, "modifiers"))
		modifiers.push_back(createModifierInvocation(mod));
	return createASTNode(
		_node,
		memberAsASTString(_node, "name"),
		kind == Token::Constructor ? Visibility::Default : visibility(_node),
		stateMutability(_node),
		kind,
		memberAsBool(_node, "virtual"),
		_node["overrides"].isNull() ? nullptr : createOverrideSpecifier(member(_node, "overrides")),
		_node["documentation"].isNull() ? nullptr : createDocumentation(member(_node, "documentation")),
		createParameterList(member(_node, "parameters")),
		modifiers,
		createParameterList(member(_node, "returnParameters")),
		memberAsBool(_node, "implemented") ? createBlock(member(_node, "body")) : nullptr
	);
}
ASTPointer ASTJsonImporter::createVariableDeclaration(Json::Value const& _node)
{
	astAssert(_node["name"].isString(), "Expected 'name' to be a string!");
	VariableDeclaration::Mutability mutability{};
	astAssert(member(_node, "mutability").isString(), "'mutability' expected to be string.");
	string const mutabilityStr = member(_node, "mutability").asString();
	if (mutabilityStr == "constant")
	{
		mutability = VariableDeclaration::Mutability::Constant;
		astAssert(memberAsBool(_node, "constant"), "");
	}
	else
	{
		astAssert(!memberAsBool(_node, "constant"), "");
		if (mutabilityStr == "mutable")
			mutability = VariableDeclaration::Mutability::Mutable;
		else if (mutabilityStr == "immutable")
			mutability = VariableDeclaration::Mutability::Immutable;
		else
			astAssert(false, "");
	}
	return createASTNode(
		_node,
		nullOrCast(member(_node, "typeName")),
		make_shared(member(_node, "name").asString()),
		nullOrCast(member(_node, "value")),
		visibility(_node),
		_node["documentation"].isNull() ? nullptr : createDocumentation(member(_node, "documentation")),
		memberAsBool(_node, "stateVariable"),
		_node.isMember("indexed") ? memberAsBool(_node, "indexed") : false,
		mutability,
		_node["overrides"].isNull() ? nullptr : createOverrideSpecifier(member(_node, "overrides")),
		location(_node)
	);
}
ASTPointer ASTJsonImporter::createModifierDefinition(Json::Value const&  _node)
{
	return createASTNode(
		_node,
		memberAsASTString(_node, "name"),
		_node["documentation"].isNull() ? nullptr : createDocumentation(member(_node, "documentation")),
		createParameterList(member(_node, "parameters")),
		memberAsBool(_node, "virtual"),
		_node["overrides"].isNull() ? nullptr : createOverrideSpecifier(member(_node, "overrides")),
		_node["body"].isNull() ? nullptr: createBlock(member(_node, "body"))
	);
}
ASTPointer ASTJsonImporter::createModifierInvocation(Json::Value const&  _node)
{
	std::vector> arguments;
	for (auto& arg: member(_node, "arguments"))
		arguments.push_back(convertJsonToASTNode(arg));
	return createASTNode(
		_node,
		createIdentifier(member(_node, "modifierName")),
		member(_node, "arguments").isNull() ? nullptr : make_unique>>(arguments)
	);
}
ASTPointer ASTJsonImporter::createEventDefinition(Json::Value const&  _node)
{
	return createASTNode(
		_node,
		memberAsASTString(_node, "name"),
		_node["documentation"].isNull() ? nullptr : createDocumentation(member(_node, "documentation")),
		createParameterList(member(_node, "parameters")),
		memberAsBool(_node, "anonymous")
	);
}
ASTPointer ASTJsonImporter::createElementaryTypeName(Json::Value const& _node)
{
	unsigned short firstNum;
	unsigned short secondNum;
	astAssert(_node["name"].isString(), "Expected 'name' to be a string!");
	string name = member(_node, "name").asString();
	Token token;
	tie(token, firstNum, secondNum) = TokenTraits::fromIdentifierOrKeyword(name);
	ElementaryTypeNameToken elem(token, firstNum,  secondNum);
	std::optional mutability = {};
	if (_node.isMember("stateMutability"))
		mutability = stateMutability(_node);
	return createASTNode(_node, elem, mutability);
}
ASTPointer ASTJsonImporter::createUserDefinedTypeName(Json::Value const& _node)
{
	astAssert(_node["name"].isString(), "Expected 'name' to be a string!");
	vector namePath;
	vector strs;
	string nameString = member(_node, "name").asString();
	boost::algorithm::split(strs, nameString, boost::is_any_of("."));
	for (string s: strs)
		namePath.emplace_back(s);
	return createASTNode(
		_node,
		namePath
	);
}
ASTPointer ASTJsonImporter::createFunctionTypeName(Json::Value const&  _node)
{
	return createASTNode(
		_node,
		createParameterList(member(_node, "parameterTypes")),
		createParameterList(member(_node, "returnParameterTypes")),
		visibility(_node),
		stateMutability(_node)
	);
}
ASTPointer ASTJsonImporter::createMapping(Json::Value const&  _node)
{
	return createASTNode(
		_node,
		convertJsonToASTNode(member(_node, "keyType")),
		convertJsonToASTNode(member(_node, "valueType"))
	);
}
ASTPointer ASTJsonImporter::createArrayTypeName(Json::Value const&  _node)
{
	return createASTNode(
		_node,
		convertJsonToASTNode(member(_node, "baseType")),
		nullOrCast(member(_node, "length"))
	);
}
ASTPointer ASTJsonImporter::createInlineAssembly(Json::Value const& _node)
{
	astAssert(_node["evmVersion"].isString(), "Expected evmVersion to be a string!");
	auto evmVersion = langutil::EVMVersion::fromString(_node["evmVersion"].asString());
	astAssert(evmVersion.has_value(), "Invalid EVM version!");
	astAssert(m_evmVersion == evmVersion, "Imported tree evm version differs from configured evm version!");
	yul::Dialect const& dialect = yul::EVMDialect::strictAssemblyForEVM(evmVersion.value());
	shared_ptr operations = make_shared(AsmJsonImporter(m_currentSourceName).createBlock(member(_node, "AST")));
	return createASTNode(
		_node,
		nullOrASTString(_node, "documentation"),
		dialect,
		operations
	);
}
ASTPointer ASTJsonImporter::createBlock(Json::Value const& _node)
{
	std::vector> statements;
	for (auto& stat: member(_node, "statements"))
		statements.push_back(convertJsonToASTNode(stat));
	return createASTNode(
		_node,
		nullOrASTString(_node, "documentation"),
		statements
	);
}
ASTPointer ASTJsonImporter::createPlaceholderStatement(Json::Value const&  _node)
{
	return createASTNode(
		_node,
		nullOrASTString(_node, "documentation")
	);
}
ASTPointer ASTJsonImporter::createIfStatement(Json::Value const&  _node)
{
	return createASTNode(
		_node,
		nullOrASTString(_node, "documentation"),
		convertJsonToASTNode(member(_node, "condition")),
		convertJsonToASTNode(member(_node, "trueBody")),
		nullOrCast(member(_node, "falseBody"))
	);
}
ASTPointer ASTJsonImporter::createTryCatchClause(Json::Value const&  _node)
{
	return createASTNode(
		_node,
		memberAsASTString(_node, "errorName"),
		nullOrCast(member(_node, "parameters")),
		convertJsonToASTNode(member(_node, "block"))
	);
}
ASTPointer ASTJsonImporter::createTryStatement(Json::Value const&  _node)
{
	vector> clauses;
	for (auto& param: _node["clauses"])
		clauses.emplace_back(createTryCatchClause(param));
	return createASTNode(
		_node,
		nullOrASTString(_node, "documentation"),
		convertJsonToASTNode(member(_node, "externalCall")),
		clauses
	);
}
ASTPointer ASTJsonImporter::createWhileStatement(Json::Value const&  _node, bool _isDoWhile=false)
{
	return createASTNode(
		_node,
		nullOrASTString(_node, "documentation"),
		convertJsonToASTNode(member(_node, "condition")),
		convertJsonToASTNode(member(_node, "body")),
		_isDoWhile
	);
}
ASTPointer ASTJsonImporter::createForStatement(Json::Value const&  _node)
{
	return createASTNode(
		_node,
		nullOrASTString(_node, "documentation"),
		nullOrCast(member(_node, "initializationExpression")),
		nullOrCast(member(_node, "condition")),
		nullOrCast(member(_node, "loopExpression")),
		convertJsonToASTNode(member(_node, "body"))
	);
}
ASTPointer ASTJsonImporter::createContinue(Json::Value const&  _node)
{
	return createASTNode(
		_node,
		nullOrASTString(_node, "documentation")
	);
}
ASTPointer ASTJsonImporter::createBreak(Json::Value const&  _node)
{
	return createASTNode(
		_node,
		nullOrASTString(_node, "documentation")
	);
}
ASTPointer ASTJsonImporter::createReturn(Json::Value const&  _node)
{
	return createASTNode(
		_node,
		nullOrASTString(_node, "documentation"),
		nullOrCast(member(_node, "expression"))
	);
}
ASTPointer ASTJsonImporter::createThrow(Json::Value const&  _node)
{
	return createASTNode(
		_node,
		nullOrASTString(_node, "documentation")
	);
}
ASTPointer ASTJsonImporter::createEmitStatement(Json::Value const&  _node)
{
	return createASTNode(
		_node,
		nullOrASTString(_node, "documentation"),
		createFunctionCall(member(_node, "eventCall"))
	);
}
ASTPointer ASTJsonImporter::createVariableDeclarationStatement(Json::Value const& _node)
{
	std::vector> variables;
	for (auto& var: member(_node, "declarations"))
		variables.push_back(var.isNull() ? nullptr : createVariableDeclaration(var)); //unnamed components are empty pointers
	return createASTNode(
		_node,
		nullOrASTString(_node, "documentation"),
		variables,
		nullOrCast(member(_node, "initialValue"))
	);
}
ASTPointer ASTJsonImporter::createExpressionStatement(Json::Value const&  _node)
{
	return createASTNode(
		_node,
		nullOrASTString(_node, "documentation"),
		convertJsonToASTNode(member(_node, "expression"))
	);
}
ASTPointer ASTJsonImporter::createConditional(Json::Value const&  _node)
{
	return createASTNode(
		_node,
		convertJsonToASTNode(member(_node, "condition")),
		convertJsonToASTNode(member(_node, "trueExpression")),
		convertJsonToASTNode(member(_node, "falseExpression"))
	);
}
ASTPointer ASTJsonImporter::createAssignment(Json::Value const&  _node)
{
	return createASTNode(
		_node,
		convertJsonToASTNode(member(_node, "leftHandSide")),
		scanSingleToken(member(_node, "operator")),
		convertJsonToASTNode(member(_node, "rightHandSide"))
	);
}
ASTPointer ASTJsonImporter::createTupleExpression(Json::Value const&  _node)
{
	std::vector> components;
	for (auto& comp: member(_node, "components"))
		components.push_back(nullOrCast(comp));
	return createASTNode(
		_node,
		components,
		memberAsBool(_node, "isInlineArray")
	);
}
ASTPointer ASTJsonImporter::createUnaryOperation(Json::Value const&  _node)
{
	return createASTNode(
		_node,
		scanSingleToken(member(_node, "operator")),
		convertJsonToASTNode(member(_node, "subExpression")),
		memberAsBool(_node, "prefix")
	);
}
ASTPointer ASTJsonImporter::createBinaryOperation(Json::Value const&  _node)
{
	return createASTNode(
		_node,
		convertJsonToASTNode(member(_node, "leftExpression")),
		scanSingleToken(member(_node, "operator")),
		convertJsonToASTNode(member(_node, "rightExpression"))
	);
}
ASTPointer ASTJsonImporter::createFunctionCall(Json::Value const&  _node)
{
	std::vector> arguments;
	for (auto& arg: member(_node, "arguments"))
		arguments.push_back(convertJsonToASTNode(arg));
	std::vector> names;
	for (auto& name: member(_node, "names"))
	{
		astAssert(name.isString(), "Expected 'names' members to be strings!");
		names.push_back(make_shared(name.asString()));
	}
	return createASTNode(
		_node,
		convertJsonToASTNode(member(_node, "expression")),
		arguments,
		names
	);
}
ASTPointer ASTJsonImporter::createFunctionCallOptions(Json::Value const&  _node)
{
	std::vector> options;
	for (auto& option: member(_node, "options"))
		options.push_back(convertJsonToASTNode(option));
	std::vector> names;
	for (auto& name: member(_node, "names"))
	{
		astAssert(name.isString(), "Expected 'names' members to be strings!");
		names.push_back(make_shared(name.asString()));
	}
	return createASTNode(
		_node,
		convertJsonToASTNode(member(_node, "expression")),
		options,
		names
	);
}
ASTPointer ASTJsonImporter::createNewExpression(Json::Value const&  _node)
{
	return createASTNode(
		_node,
		convertJsonToASTNode(member(_node, "typeName"))
	);
}
ASTPointer ASTJsonImporter::createMemberAccess(Json::Value const&  _node)
{
	return createASTNode(
		_node,
		convertJsonToASTNode(member(_node, "expression")),
		memberAsASTString(_node, "memberName")
	);
}
ASTPointer ASTJsonImporter::createIndexAccess(Json::Value const& _node)
{
	return createASTNode(
		_node,
		convertJsonToASTNode(member(_node, "baseExpression")),
		nullOrCast(member(_node, "indexExpression"))
	);
}
ASTPointer ASTJsonImporter::createIndexRangeAccess(Json::Value const& _node)
{
	return createASTNode(
		_node,
		convertJsonToASTNode(member(_node, "baseExpression")),
		nullOrCast(member(_node, "startExpression")),
		nullOrCast(member(_node, "endExpression"))
	);
}
ASTPointer ASTJsonImporter::createIdentifier(Json::Value const& _node)
{
	return createASTNode(_node, memberAsASTString(_node, "name"));
}
ASTPointer ASTJsonImporter::createElementaryTypeNameExpression(Json::Value const&  _node)
{
	return createASTNode(
		_node,
		createElementaryTypeName(member(_node, "typeName"))
	);
}
ASTPointer ASTJsonImporter::createLiteral(Json::Value const&  _node)
{
	static string const valStr = "value";
	static string const hexValStr = "hexValue";
	astAssert(member(_node, valStr).isString() || member(_node, hexValStr).isString(), "Literal-value is unset.");
	ASTPointer value = _node.isMember(hexValStr) ?
		make_shared(util::asString(util::fromHex(_node[hexValStr].asString()))) :
		make_shared(_node[valStr].asString());
	return createASTNode(
		_node,
		literalTokenKind(_node),
		value,
		member(_node, "subdenomination").isNull() ? Literal::SubDenomination::None : subdenomination(_node)
	);
}
ASTPointer ASTJsonImporter::createDocumentation(Json::Value const&  _node)
{
	static string const textString = "text";
	astAssert(member(_node, textString).isString(), "'text' must be a string");
	return createASTNode(
		_node,
		make_shared(_node[textString].asString())
	);
}
// ===== helper functions ==========
Json::Value ASTJsonImporter::member(Json::Value const& _node, string const& _name)
{
	if (!_node.isMember(_name))
		return Json::nullValue;
	return _node[_name];
}
Token ASTJsonImporter::scanSingleToken(Json::Value const& _node)
{
	langutil::Scanner scanner{langutil::CharStream(_node.asString(), "")};
	astAssert(scanner.peekNextToken() == Token::EOS, "Token string is too long.");
	return scanner.currentToken();
}
ASTPointer ASTJsonImporter::nullOrASTString(Json::Value const& _json, string const& _name)
{
	return _json[_name].isString() ? memberAsASTString(_json, _name) : nullptr;
}
ASTPointer ASTJsonImporter::memberAsASTString(Json::Value const& _node, string const& _name)
{
	Json::Value value = member(_node, _name);
	astAssert(value.isString(), "field " + _name + " must be of type string.");
	return make_shared(_node[_name].asString());
}
bool ASTJsonImporter::memberAsBool(Json::Value const& _node, string const& _name)
{
	Json::Value value = member(_node, _name);
	astAssert(value.isBool(), "field " + _name + " must be of type boolean.");
	return _node[_name].asBool();
}
// =========== JSON to definition helpers =======================
ContractKind ASTJsonImporter::contractKind(Json::Value const& _node)
{
	ContractKind kind;
	astAssert(!member(_node, "contractKind").isNull(), "'Contract-kind' can not be null.");
	if (_node["contractKind"].asString() == "interface")
		kind = ContractKind::Interface;
	else if (_node["contractKind"].asString() == "contract")
		kind = ContractKind::Contract;
	else if (_node["contractKind"].asString() == "library")
		kind = ContractKind::Library;
	else
		astAssert(false, "Unknown ContractKind");
	return kind;
}
Token ASTJsonImporter::literalTokenKind(Json::Value const& _node)
{
	astAssert(member(_node, "kind").isString(), "Token-'kind' expected to be a string.");
	Token tok;
	if (_node["kind"].asString() == "number")
		tok = Token::Number;
	else if (_node["kind"].asString() == "string")
		tok = Token::StringLiteral;
	else if (_node["kind"].asString() == "bool")
		tok = (member(_node, "value").asString() == "true") ? Token::TrueLiteral : Token::FalseLiteral;
	else
		astAssert(false, "Unknown kind of literalString");
	return tok;
}
Visibility ASTJsonImporter::visibility(Json::Value const& _node)
{
	Json::Value visibility = member(_node, "visibility");
	astAssert(visibility.isString(), "'visibility' expected to be a string.");
	string const visibilityStr = visibility.asString();
	if (visibilityStr == "default")
		return Visibility::Default;
	else if (visibilityStr == "private")
		return Visibility::Private;
	else if ( visibilityStr == "internal")
		return Visibility::Internal;
	else if (visibilityStr == "public")
		return Visibility::Public;
	else if (visibilityStr == "external")
		return Visibility::External;
	else
		astAssert(false, "Unknown visibility declaration");
}
VariableDeclaration::Location ASTJsonImporter::location(Json::Value const& _node)
{
	Json::Value storageLoc = member(_node, "storageLocation");
	astAssert(storageLoc.isString(), "'storageLocation' expected to be a string.");
	string const storageLocStr = storageLoc.asString();
	if (storageLocStr == "default")
		return VariableDeclaration::Location::Unspecified;
	else if (storageLocStr == "storage")
		return VariableDeclaration::Location::Storage;
	else if (storageLocStr == "memory")
		return VariableDeclaration::Location::Memory;
	else if (storageLocStr == "calldata")
		return VariableDeclaration::Location::CallData;
	else
		astAssert(false, "Unknown location declaration");
}
Literal::SubDenomination ASTJsonImporter::subdenomination(Json::Value const& _node)
{
	Json::Value subDen = member(_node, "subdenomination");
	if (subDen.isNull())
		return Literal::SubDenomination::None;
	astAssert(subDen.isString(), "'subDenomination' expected to be string.");
	string const subDenStr = subDen.asString();
	if (subDenStr == "wei")
		return Literal::SubDenomination::Wei;
	else if (subDenStr == "gwei")
		return Literal::SubDenomination::Gwei;
	else if (subDenStr == "ether")
		return Literal::SubDenomination::Ether;
	else if (subDenStr == "seconds")
		return Literal::SubDenomination::Second;
	else if (subDenStr == "minutes")
		return Literal::SubDenomination::Minute;
	else if (subDenStr == "hours")
		return Literal::SubDenomination::Hour;
	else if (subDenStr == "days")
		return Literal::SubDenomination::Day;
	else if (subDenStr == "weeks")
		return Literal::SubDenomination::Week;
	else if (subDenStr == "years")
		return Literal::SubDenomination::Year;
	else
		astAssert(false, "Unknown subdenomination");
}
StateMutability ASTJsonImporter::stateMutability(Json::Value const& _node)
{
	astAssert(member(_node, "stateMutability").isString(), "StateMutability' expected to be string.");
	string const mutabilityStr = member(_node, "stateMutability").asString();
	if (mutabilityStr == "pure")
		return StateMutability::Pure;
	else if (mutabilityStr == "view")
		return StateMutability::View;
	else if (mutabilityStr == "nonpayable")
		return StateMutability::NonPayable;
	else if (mutabilityStr == "payable")
		return StateMutability::Payable;
	else
		astAssert(false, "Unknown stateMutability");
}
}