MacroWorker.java

package dev.civl.mc.transform.common;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import dev.civl.abc.ast.IF.AST;
import dev.civl.abc.ast.IF.ASTFactory;
import dev.civl.abc.ast.node.IF.ASTNode;
import dev.civl.abc.ast.node.IF.ASTNode.NodeKind;
import dev.civl.abc.ast.node.IF.SequenceNode;
import dev.civl.abc.ast.node.IF.declaration.VariableDeclarationNode;
import dev.civl.abc.ast.node.IF.expression.ExpressionNode;
import dev.civl.abc.ast.node.IF.statement.BlockItemNode;
import dev.civl.abc.ast.node.IF.type.TypeNode;
import dev.civl.abc.ast.type.IF.StandardBasicType;
import dev.civl.abc.ast.type.IF.StandardBasicType.BasicTypeKind;
import dev.civl.abc.ast.type.IF.Type;
import dev.civl.abc.ast.type.IF.Type.TypeKind;
import dev.civl.abc.token.IF.Formation;
import dev.civl.abc.token.IF.Macro;
import dev.civl.abc.token.IF.MacroExpansion;
import dev.civl.abc.token.IF.Source;
import dev.civl.abc.token.IF.SyntaxException;
import dev.civl.mc.config.IF.CIVLConfiguration;
import dev.civl.mc.transform.IF.MacroTransformer;

/**
 * Recovers macros.
 */
public class MacroWorker extends BaseWorker {
	private CIVLConfiguration config;

	public MacroWorker(ASTFactory astFactory, CIVLConfiguration config) {
		super(MacroTransformer.LONG_NAME, astFactory);
		this.identifierPrefix = "$macro_";
		this.config = config;
	}

	@Override
	protected AST transformCore(AST unit) throws SyntaxException {
		if (!this.hasHeader(unit, Pthread2CIVLWorker.PTHREAD_HEADER)
				|| !config.svcomp())
			return unit;

		SequenceNode<BlockItemNode> root = unit.getRootNode();
		AST newAst;
		List<BlockItemNode> newExternalList = new ArrayList<>();
		Map<String, VariableDeclarationNode> macroVars = new HashMap<>();

		unit.release();
		for (ASTNode child : root) {
			if (child != null)
				recoverMacro(child, macroVars);
		}
		for (BlockItemNode inputVar : macroVars.values())
			newExternalList.add(inputVar);
		for (BlockItemNode child : root) {
			if (child != null) {
				newExternalList.add(child);
				child.parent().removeChild(child.childIndex());
			}
		}
		root = nodeFactory.newSequenceNode(root.getSource(), "TranslationUnit",
				newExternalList);
		newAst = astFactory.newAST(root, unit.getSourceFiles(),
				unit.isWholeProgram());
		// newAst.prettyPrint(System.out, true);
		return newAst;
	}

	private void recoverMacro(ASTNode node,
			Map<String, VariableDeclarationNode> macros) {
		String sourceFile = node.getSource().getFirstToken().getSourceFile()
				.getName();
		Formation formation;

		if (sourceFile.endsWith(".h") || sourceFile.endsWith(".cvh")
				|| sourceFile.endsWith(".cvl"))
			return;
		formation = node.getSource().getFirstToken().getFormation();
		if (formation instanceof MacroExpansion) {
			if (node.nodeKind() == NodeKind.EXPRESSION) {
				Type type = ((ExpressionNode) node).getType();

				if (type.kind() == TypeKind.POINTER)
					return;
				if (type instanceof StandardBasicType) {
					if (((StandardBasicType) type).getBasicTypeKind() == BasicTypeKind.BOOL)
						return;
				}
				MacroExpansion expansion = (MacroExpansion) formation;
				Macro macro = expansion.getMacro();
				String name = macro.getName();
				ExpressionNode idNode;
				Source source = node.getSource();

				if (!macros.containsKey(name)) {
					VariableDeclarationNode newInputVar;
					TypeNode typeNode = typeNode(source, type);

					typeNode.setInputQualified(true);
					newInputVar = nodeFactory.newVariableDeclarationNode(
							source,
							nodeFactory.newIdentifierNode(source, name),
							typeNode);
					macros.put(name, newInputVar);
				}
				idNode = this.identifierExpression(source, name);
				node.parent().setChild(node.childIndex(), idNode);
			}
		} else {
			for (ASTNode child : node.children()) {
				if (child != null) {
					this.recoverMacro(child, macros);
				}
			}
		}
	}
}