All Downloads are FREE. Search and download functionalities are using the official Maven repository.

swiprolog.language.Analyzer Maven / Gradle / Ivy

Go to download

An implementation of the KR Interface defined in the KR Tools project for SWI Prolog.

There is a newer version: 1.4.0
Show newest version
/**
 * Knowledge Representation Tools. Copyright (C) 2014 Koen Hindriks.
 *
 * This program 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.
 *
 * This program 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
 * this program. If not, see .
 */

package swiprolog.language;

import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import krTools.language.DatabaseFormula;
import krTools.language.Query;
import krTools.parser.SourceInfo;
import swiprolog.parser.PrologOperators;

/**
 * Analyzer to identify unused and undefined predicates.
 */
public class Analyzer {
	private static final org.jpl7.Term ANON_VAR = new org.jpl7.Variable("_");
	/**
	 * Map of definitions.
	 */
	private final Map> definitions = new LinkedHashMap<>();
	/**
	 * Map of queries.
	 */
	private final Map> used = new LinkedHashMap<>();
	/**
	 * Input
	 */
	private final Set dbfs;
	private final Set queries;
	/**
	 * Output
	 */
	private final Set undefined = new HashSet<>();
	private final Set unused = new HashSet<>();

	/**
	 * Creates an analyzer.
	 */
	public Analyzer(Set dbfs, Set queries) {
		this.dbfs = dbfs;
		this.queries = queries;
	}

	public void analyze() {
		for (DatabaseFormula dbf : this.dbfs) {
			addDefinition(dbf);
		}
		for (Query query : this.queries) {
			addQuery(query);
		}
		this.undefined.addAll(this.used.keySet());
		this.undefined.removeAll(this.definitions.keySet());
		this.unused.addAll(this.definitions.keySet());
		this.unused.removeAll(this.used.keySet());
	}

	public Set getUndefined() {
		Set undefined = new HashSet<>();
		for (String undf : this.undefined) {
			undefined.addAll(this.used.get(undf));
		}
		return undefined;
	}

	public Set getUnused() {
		Set unused = new HashSet<>();
		for (String df : this.unused) {
			unused.addAll(this.definitions.get(df));
		}
		return unused;
	}

	/**
	 * Assumes the given DatabaseFormula is either a single term, or the :-/2
	 * function.
	 */
	private void addDefinition(DatabaseFormula formula) {
		PrologDBFormula plFormula = (PrologDBFormula) formula;
		org.jpl7.Term term = plFormula.getTerm();
		org.jpl7.Term headTerm = term;
		// The :- function needs special attention.
		String sig = JPLUtils.getSignature(term);
		if (sig.equals(":-/1")) {
			// Directive: the first argument is a query.
			addQuery(new PrologQuery(term.arg(1), formula.getSourceInfo()));
		} else if (sig.equals(":-/2")) {
			// The first argument is the only defined term.
			headTerm = term.arg(1);
			// The other argument is a conjunction of queried terms.
			addQuery(new PrologQuery(term.arg(2), formula.getSourceInfo()));
		}

		String headSig = JPLUtils.getSignature(headTerm);
		// Ignore built-in operators.
		if (!PrologOperators.prologBuiltin(headSig)) {
			// Add a new definition node
			List formulas;
			if (this.definitions.containsKey(headSig)) {
				formulas = this.definitions.get(headSig);
			} else {
				formulas = new LinkedList<>();
			}
			formulas.add(new PrologDBFormula(headTerm, formula.getSourceInfo()));
			this.definitions.put(headSig, formulas);
		}
	}

	/**
	 * Add a query (a use of predicates).
	 */
	public void addQuery(Query query) {
		addQuery(((PrologQuery) query).getTerm(), query.getSourceInfo());
	}

	/**
	 * Add predicates used in a clause as queries.
	 */
	public void addQuery(DatabaseFormula formula) {
		// we may assume the formula is a single term, so we can just
		// as well handle the inner term as a general term.
		addQuery(((PrologDBFormula) formula).getTerm(), formula.getSourceInfo());
	}

	private void addQuery(org.jpl7.Term plTerm, SourceInfo info) {
		// check if the term needs to be unpacked
		String termSig = JPLUtils.getSignature(plTerm);
		// there is only one /1 operator we need to unpack: not/1
		if (termSig.equals("not/1")) {
			addQuery(plTerm.arg(1), info);
		} else if (termSig.equals(";/2") || termSig.equals(",/2") || termSig.equals("forall/2")) {
			// unpack the conjunction, disjunction and forall /2-operators
			addQuery(plTerm.arg(1), info);
			addQuery(plTerm.arg(2), info);
		} else if (termSig.equals("findall/3") || termSig.equals("setof/3") || termSig.equals("aggregate/3")
				|| termSig.equals("aggregate_all/3")) {
			// findall, setof aggregate and aggregate_all /3-operators only
			// have a query in the second argument.
			addQuery(plTerm.arg(2), info);
		} else if (termSig.equals("aggregate/4") || termSig.equals("aggregate_all/4")) {
			// aggregate and aggregate_all /4-operators have the query in
			// the third argument.
			addQuery(plTerm.arg(3), info);
		} else if (termSig.equals("predsort/3")) {
			// first argument is name that will be called as name/3
			org.jpl7.Term stubfunc = new org.jpl7.Compound(plTerm.arg(1).name(),
					new org.jpl7.Term[] { ANON_VAR, ANON_VAR, ANON_VAR });
			addQuery(stubfunc, info);
		} else if (termSig.equals("dynamic/1")) {
			// recognize predicate declaration(s).
			for (org.jpl7.Term dynamicPred : JPLUtils.getOperands(",", plTerm.arg(1))) {
				addDefinition(new PrologDBFormula(dynamicPred, info));
			}
		} else if (!PrologOperators.prologBuiltin(termSig)) {
			// if we get here, the term should not be unpacked
			// but needs to be added as a query node
			// Add a new definition node
			List formulas;
			if (this.used.containsKey(termSig)) {
				formulas = this.used.get(termSig);
			} else {
				formulas = new LinkedList<>();
			}
			formulas.add(new PrologQuery(plTerm, info));
			this.used.put(termSig, formulas);
		}
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy