ISOLibrary.java

/*
 * #%L
 * prolobjectlink-jpi-jtrolog
 * %%
 * Copyright (C) 2012 - 2018 WorkLogic Project
 * %%
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation, either version 2.1 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 Lesser Public License for more details.
 * 
 * You should have received a copy of the GNU General Lesser Public
 * License along with this program.  If not, see
 * <http://www.gnu.org/licenses/lgpl-2.1.html>.
 * #L%
 */
/*
 * tuProlog - Copyright (C) 2001-2002  aliCE team at deis.unibo.it
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
package jTrolog.lib;

import jTrolog.engine.*;
import jTrolog.terms.Number;
import jTrolog.terms.*;
import jTrolog.terms.Float;
import jTrolog.parser.Parser;
import jTrolog.errors.PrologException;

import java.util.Iterator;

/**
 * This class represents a tuProlog library providing most of the built-ins
 * predicates and functors defined by ISO standard.
 * 
 * Library/Theory dependency: BasicLibrary
 * 
 * 
 * 
 */
@SuppressWarnings({ "rawtypes", "serial" })
public class ISOLibrary extends Library {

	public boolean atom_length_2(BindingsTable bt, Struct arg, Term len) {
		if (!BasicLibrary.atom_1(bt, arg))
			return false;
		return bt.unify(len, new Int(arg.name.length()));
	}

	public boolean atom_chars_2(BindingsTable bt, Term arg0, Term arg1) throws PrologException {
		if (arg0 instanceof Var) {
			if (!(arg1 instanceof Struct))
				return false;

			Struct list = (Struct) arg1;
			if (list.equals(Term.emptyList))
				return bt.unify(arg0, new StructAtom(""));
			StringBuffer res = new StringBuffer();
			for (Iterator it = bt.structListIterator(list, true); it.hasNext();) {
				String character = it.next().toString();
				if (character.startsWith("'") && character.endsWith("'") && character.length() != 1)
					character = character.substring(1, character.length() - 1);
				res.append(character);
			}
			return bt.unify(arg0, new StructAtom(res.toString()));
		} else {
			if (!BasicLibrary.atom_1(bt, arg0))
				return false;
			Struct list = Parser.stringToStructList(((Struct) arg0).name);
			return bt.unify(arg1, bt.wrapWithID(list));
		}
	}

	public boolean char_code_2(BindingsTable bt, Term arg0, Term arg1) {
		if (arg1 instanceof Var) {
			if (BasicLibrary.atom_1(bt, arg0)) {
				String st = ((Struct) arg0).name;
				if (st.length() <= 1)
					return bt.unify(arg1, new Int(st.charAt(0)));
			}
		} else if (arg1 instanceof Int) {
			char c = (char) ((jTrolog.terms.Number) arg1).intValue();
			return bt.unify(arg0, new StructAtom("" + c));
		}
		return false;
	}

	//

	// functors

	public Term sin_1(BindingsTable bt, EvaluableTerm val) throws Throwable {
		return new jTrolog.terms.Double(Math.sin(bt.evalExpression(engine, val).doubleValue()));
	}

	public Term cos_1(BindingsTable bt, EvaluableTerm val) throws Throwable {
		return new jTrolog.terms.Double(Math.cos(bt.evalExpression(engine, val).doubleValue()));
	}

	public Term exp_1(BindingsTable bt, EvaluableTerm val) throws Throwable {
		return new jTrolog.terms.Double(Math.exp((bt.evalExpression(engine, val)).doubleValue()));
	}

	public Term atan_1(BindingsTable bt, EvaluableTerm val) throws Throwable {
		return new jTrolog.terms.Double(Math.atan(bt.evalExpression(engine, val).doubleValue()));
	}

	public Term log_1(BindingsTable bt, EvaluableTerm val) throws Throwable {
		return new jTrolog.terms.Double(Math.log(bt.evalExpression(engine, val).doubleValue()));
	}

	public Term sqrt_1(BindingsTable bt, EvaluableTerm val) throws Throwable {
		return new jTrolog.terms.Double(Math.sqrt(bt.evalExpression(engine, val).doubleValue()));
	}

	public Term abs_1(BindingsTable bt, EvaluableTerm val) throws Throwable {
		Number val0 = bt.evalExpression(engine, val);
		if (val0 instanceof Float)
			return new jTrolog.terms.Double(Math.abs(val0.doubleValue()));
		return new jTrolog.terms.Int(Math.abs(val0.intValue()));
	}

	public Term sign_1(BindingsTable bt, EvaluableTerm val) throws Throwable {
		Number val0 = bt.evalExpression(engine, val);
		if (val0 instanceof Float)
			return new jTrolog.terms.Double(val0.doubleValue() > 0 ? 1.0 : -1.0);
		return new jTrolog.terms.Double(val0.intValue() > 0 ? 1.0 : -1.0);
	}

	public Term float_integer_part_1(BindingsTable bt, EvaluableTerm val) throws Throwable {
		return new jTrolog.terms.Double((long) Math.rint(bt.evalExpression(engine, val).doubleValue()));
	}

	public Term float_fractional_part_1(BindingsTable bt, EvaluableTerm val) throws Throwable {
		double fl = bt.evalExpression(engine, val).doubleValue();
		return new jTrolog.terms.Double(Math.abs(fl - Math.rint(fl)));
	}

	// public boolean float_1(BindingsTable bt, EvaluableTerm val) throws
	// Throwable {
	// return engine.evalExpression(bt, val).isReal();
	// }

	public Term floor_1(BindingsTable bt, EvaluableTerm val) throws Throwable {
		return new Int((int) Math.floor(bt.evalExpression(engine, val).doubleValue()));
	}

	public Term round_1(BindingsTable bt, EvaluableTerm val) throws Throwable {
		return new jTrolog.terms.Long(Math.round(bt.evalExpression(engine, val).doubleValue()));
	}

	public Term truncate_1(BindingsTable bt, EvaluableTerm val) throws Throwable {
		return new Int((int) Math.rint(bt.evalExpression(engine, val).doubleValue()));
	}

	public Term ceiling_1(BindingsTable bt, EvaluableTerm val) throws Throwable {
		return new Int((int) Math.ceil(bt.evalExpression(engine, val).doubleValue()));
	}

	public Term div_2(BindingsTable bt, EvaluableTerm v0, EvaluableTerm v1) throws Throwable {
		return new jTrolog.terms.Int(bt.evalExpression(engine, v0).intValue() / bt.evalExpression(engine, v1).intValue());
	}

	public Term mod_2(BindingsTable bt, EvaluableTerm v0, EvaluableTerm v1) throws Throwable {
		return new Int(bt.evalExpression(engine, v0).intValue() % bt.evalExpression(engine, v1).intValue());
	}

	public Term rem_2(BindingsTable bt, EvaluableTerm v0, EvaluableTerm v1) throws Throwable {
		return new jTrolog.terms.Double(Math.IEEEremainder(bt.evalExpression(engine, v0).doubleValue(), bt.evalExpression(engine, v1).doubleValue()));
	}

	/**
	 * library theory
	 */
	public String getTheory() {
		return
		//
		// operators defined by the ISOLibrary theory
		//
		":- op(  300, yfx,  'div'). \n" + ":- op(  400, yfx,  'mod'). \n" + ":- op(  400, yfx,  'rem'). \n" + ":- op(  200, fx,   'sin'). \n" + ":- op(  200, fx,   'cos'). \n"
				+ ":- op(  200, fx,   'sqrt'). \n" + ":- op(  200, fx,   'atan'). \n" + ":- op(  200, fx,   'exp'). \n" + ":- op(  200, fx,   'log'). \n" +
				//
				// flags defined by the ISOLibrary theory
				//
				":- flag(bounded, [true,false], true, false).\n" + ":- flag(max_integer, ["
				+ Integer.toString(Integer.MAX_VALUE)
				+ "], "
				+ Integer.toString(Integer.MAX_VALUE)
				+ ",false).\n"
				+ ":- flag(min_integer, ["
				+ Integer.toString(Integer.MIN_VALUE)
				+ "], "
				+ Integer.toString(Integer.MIN_VALUE)
				+ ",false).\n"
				+ ":- flag(integer_rounding_function, [up,down], down, false).\n"
				+ ":- flag(char_conversion,[on,off],off,false).\n"
				+ ":- flag(debug,[on,off],off,false).\n"
				+ ":- flag(max_arity, ["
				+ Integer.toString(Integer.MAX_VALUE)
				+ "], "
				+ Integer.toString(Integer.MAX_VALUE)
				+ ",false).\n"
				+ ":- flag(undefined_predicate, [error,fail,warning], fail, false).\n"
				+ ":- flag(double_quotes, [atom,chars,codes], atom, true).\n"
				+
				//
				//
				"unbound(X):-not bound(X).\n                                                                          "
				+
				//
				"atom_concat(F,S,R) :- atom_chars(F,FL),atom_chars(S,SL),!,append(FL,SL,RS),atom_chars(R,RS).\n          "
				+ "atom_concat(F,S,R) :- atom_chars(R,RS),append(FL,SL,RS),atom_chars(F,FL),atom_chars(S,SL).\n            "
				+ "atom_codes(A,L):-atom_chars(A,L1),!,chars_codes(L1,L).\n"
				+ "atom_codes(A,L):-chars_codes(L1,L),atom_chars(A,L1).\n"
				+ "chars_codes([],[]).\n"
				+ "chars_codes([X|L1],[Y|L2]):-char_code(X,Y),chars_codes(L1,L2).\n"
				+ "sub_atom(Atom,B,L,A,Sub):-atom_chars(Atom,L1),atom_chars(Sub,L2),!,sub_list(L2,L1,B),length(L2,L), length(L1,Len), A is Len - (B+L).\n"
				+ "sub_atom(Atom,B,L,A,Sub):-atom_chars(Atom,L1),sub_list(L2,L1,B),atom_chars(Sub,L2),length(L2,L), length(L1,Len), A is Len - (B+L).\n"
				+ "sub_list([],_,0).\n"
				+ "sub_list([X|L1],[X|L2],0):- sub_list_seq(L1,L2).\n"
				+ "sub_list(L1,[_|L2],N):- sub_list(L1,L2,M), N is M + 1.\n"
				+ "sub_list_seq([],L).\n"
				+ "sub_list_seq([X|L1],[X|L2]):-sub_list_seq(L1,L2).\n"
				+ "number_chars(Number,List):-num_atom(Number,Struct),atom_chars(Struct,List),!.\n"
				+ "number_chars(Number,List):-atom_chars(Struct,List),num_atom(Number,Struct).\n"
				+ "number_codes(Number,List):-num_atom(Number,Struct),atom_codes(Struct,List),!.\n"
				+ "number_codes(Number,List):-atom_codes(Struct,List),num_atom(Number,Struct).\n";
		//
		// ISO default
		// "current_prolog_flag(changeable_flags,[ char_conversion(on,off), debug(on,off), undefined_predicate(error,fail,warning),double_quotes(chars,codes,atom) ]).\n"+
		// "current_prolog_flag(changeable_flags,[]).\n                                                              "+
	}

	public String[] getSynonym(String primitiveName) {
		if (primitiveName.equals("ground"))
			return new String[] { "bound" };
		return null;
	}

}