package org.matheclipse.core.reflection.system;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.Reader; 
import java.util.HashMap;
import java.util.HashSet;

import org.matheclipse.core.basic.Config;
import org.matheclipse.core.eval.EvalEngine;
import org.matheclipse.core.eval.exception.RuleCreationError;
import org.matheclipse.core.eval.exception.Validate;
import org.matheclipse.core.eval.exception.WrongNumberOfArguments;
import org.matheclipse.core.eval.interfaces.IFunctionEvaluator;
import org.matheclipse.core.expression.F;
import org.matheclipse.core.interfaces.IAST;
import org.matheclipse.core.interfaces.IExpr;
import org.matheclipse.core.interfaces.IStringX;
import org.matheclipse.core.interfaces.ISymbol;

/**
 * Package[{<list of public package rule headers>}, {<list of rules in
 * this package>}}
 * 
 */
public class Package implements IFunctionEvaluator {

	public Package() {
	}

	public IExpr evaluate(final IAST ast) {
		Validate.checkSize(ast, 4);

		if (!(ast.arg1() instanceof IStringX) || !ast.get(2).isList() || !ast.get(3).isList()) {
			throw new WrongNumberOfArguments(ast, 1, ast.size() - 1);
		}
		if (Config.SERVER_MODE) {
			throw new RuleCreationError(null);
		}
		IAST symbols = (IAST) ast.get(2);
		IAST list = (IAST) ast.get(3);
		evalPackage(symbols, list);
		// System.out.println(resultList);
		return F.Null;
	}

	public static void evalPackage(IAST publicSymbols, IAST list) {
		HashMap convertedSymbolMap = new HashMap();
		HashSet publicSymbolSet = new HashSet();

		ISymbol toSymbol;
		for (int i = 1; i < publicSymbols.size(); i++) {
			IExpr expr = publicSymbols.get(i);
			if (expr.isSymbol()) {
				publicSymbolSet.add((ISymbol) expr);
				toSymbol = F.predefinedSymbol(((ISymbol) expr).toString());
				convertedSymbolMap.put((ISymbol) expr, toSymbol);
			}
		}

		// determine "private package rule headers" in convertedSymbolMap
		for (int i = 1; i < list.size(); i++) {
			if (list.get(i).isAST()) {
				determineRuleHead((IAST) list.get(i), publicSymbolSet, convertedSymbolMap);
			}
		}

		// convert the rules into a new list:
		IAST resultList = F.List();
		for (int i = 1; i < list.size(); i++) {
			resultList.add(convertSymbolsInExpr(list.get(i), convertedSymbolMap));
		}
		EvalEngine engine = EvalEngine.get();
		try {
			engine.setPackageMode(true);
			// evaluate the new converted rules
			for (int i = 1; i < resultList.size(); i++) {
				EvalEngine.eval(resultList.get(i));
			}
		} finally {
			engine.setPackageMode(false);
		}
	}

	/**
	 * Determine the head symbol of the given rule
	 * 
	 * @param rule
	 * @param unprotectedSymbolSet
	 * @param convertedSymbolMap
	 */
	private static void determineRuleHead(IAST rule, HashSet unprotectedSymbolSet,
			HashMap convertedSymbolMap) {
		ISymbol lhsHead;
		if (rule.size() > 1
				&& (rule.head().equals(F.Set) || rule.head().equals(F.SetDelayed) || rule.head().equals(F.UpSet) || rule.head()
						.equals(F.UpSetDelayed))) {
			// determine the head to which this rule is associated
			lhsHead = null;
			if (rule.arg1().isAST()) {
				lhsHead = ((IAST) rule.arg1()).topHead();
			} else if (rule.arg1().isSymbol()) {
				lhsHead = (ISymbol) rule.arg1();
			}

			if (lhsHead != null && !unprotectedSymbolSet.contains(lhsHead)) {
				ISymbol toSymbol = convertedSymbolMap.get(lhsHead);
				if (toSymbol == null) {
					// define a package private symbol
					toSymbol = F.predefinedSymbol("@" + EvalEngine.getNextCounter() + lhsHead.toString());
					convertedSymbolMap.put(lhsHead, toSymbol);
				}
			}

		}
	}

	/**
	 * Convert all symbols which are keys in convertedSymbols in
	 * the given expr and return the resulting expression.
	 * 
	 * @param expr
	 * @param convertedSymbols
	 * @return
	 */
	private static IExpr convertSymbolsInExpr(IExpr expr, HashMap convertedSymbols) {
		IExpr result = expr;
		if (expr.isAST()) {
			result = convertSymbolsInList((IAST) expr, convertedSymbols);
		} else if (expr.isSymbol()) {
			ISymbol toSymbol = convertedSymbols.get((ISymbol) expr);
			if (toSymbol != null) {
				result = toSymbol;
			}
		}

		return result;
	}

	/**
	 * Convert all symbols which are keys in convertedSymbols in
	 * the given ast list and return the resulting list.
	 * 
	 * @param ast
	 * @param convertedSymbols
	 * @return
	 */
	private static IAST convertSymbolsInList(IAST ast, HashMap convertedSymbols) {
		IAST result = ast.clone();
		for (int i = 0; i < result.size(); i++) {
			IExpr expr = result.get(i);
			if (expr.isAST()) {
				result.set(i, convertSymbolsInList((IAST) expr, convertedSymbols));
			} else if (expr.isSymbol()) {
				ISymbol toSymbol = convertedSymbols.get((ISymbol) expr);
				if (toSymbol != null) {
					result.set(i, toSymbol);
				}
			}
		}

		return result;
	}

	public IExpr numericEval(IAST functionList) {
		return null;
	}

	public void setUp(ISymbol symbol) {
		symbol.setAttributes(ISymbol.HOLDALL);
	}

	/**
	 * Load a package from the given reader
	 * 
	 * @param is
	 */
	public static void loadPackage(final EvalEngine engine, final Reader is) {
		String record = null;
		final BufferedReader r = new BufferedReader(is);// new
		try {
			StringBuilder builder = new StringBuilder(2048);
			while ((record = r.readLine()) != null) {
				builder.append(record);
				builder.append('\n');
			}

			IExpr parsedExpression = engine.parse(builder.toString());
			if (parsedExpression != null && parsedExpression.isAST()) {
				IAST ast = (IAST) parsedExpression;
				if (ast.size() != 4 || !(ast.arg1() instanceof IStringX) || !ast.arg2().isList() || !ast.arg3().isList()) {
					throw new WrongNumberOfArguments(ast, 3, ast.size() - 1);
				}
				IAST symbols = (IAST) ast.arg2();
				IAST list = (IAST) ast.arg3();
				evalPackage(symbols, list);
			}

		} catch (final Exception e) {
			e.printStackTrace();
		} finally {
			try {
				r.close();
				is.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

}

 

Ads help maintain this website.