Package org.rascalmpl.library

Source Code of org.rascalmpl.library.Prelude$Sorting

/*******************************************************************************
* Copyright (c) 2009-2013 CWI
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
*   * Paul Klint - Paul.Klint@cwi.nl - CWI
*   * Jurgen J. Vinju - Jurgen.Vinju@cwi.nl - CWI
*   * Arnold Lankamp - Arnold.Lankamp@cwi.nl
*   * Davy Landman - Davy.Landman@cwi.nl
*   * Michael Steindorfer - Michael.Steindorfer@cwi.nl - CWI
*******************************************************************************/

/*******************************************************************************
*
* Warning this file is an experiment to determine the effect of collecting all
* classes used by the Prelude in a single class. Overall effect seems to be circa 10%
* reduction of import time.
*
* Do not edit/change this code, but use the original code instead.
*
*/
package org.rascalmpl.library;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.Reader;
import java.io.StringReader;
import java.io.StringWriter;
import java.lang.ref.WeakReference;
import java.math.BigInteger;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.nio.charset.Charset;
import java.security.DigestInputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.ParseException;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.PriorityQueue;
import java.util.Random;
import java.util.Set;
import java.util.UUID;
import java.util.regex.Pattern;

import org.apache.commons.lang.CharSetUtils;
import org.eclipse.imp.pdb.facts.IBool;
import org.eclipse.imp.pdb.facts.IConstructor;
import org.eclipse.imp.pdb.facts.IDateTime;
import org.eclipse.imp.pdb.facts.IInteger;
import org.eclipse.imp.pdb.facts.IList;
import org.eclipse.imp.pdb.facts.IListWriter;
import org.eclipse.imp.pdb.facts.IMap;
import org.eclipse.imp.pdb.facts.IMapWriter;
import org.eclipse.imp.pdb.facts.INode;
import org.eclipse.imp.pdb.facts.IRational;
import org.eclipse.imp.pdb.facts.ISet;
import org.eclipse.imp.pdb.facts.ISetWriter;
import org.eclipse.imp.pdb.facts.ISourceLocation;
import org.eclipse.imp.pdb.facts.IString;
import org.eclipse.imp.pdb.facts.ITuple;
import org.eclipse.imp.pdb.facts.IValue;
import org.eclipse.imp.pdb.facts.IValueFactory;
import org.eclipse.imp.pdb.facts.exceptions.FactTypeUseException;
import org.eclipse.imp.pdb.facts.impl.AbstractValueFactoryAdapter;
import org.eclipse.imp.pdb.facts.io.ATermReader;
import org.eclipse.imp.pdb.facts.io.BinaryValueReader;
import org.eclipse.imp.pdb.facts.io.BinaryValueWriter;
import org.eclipse.imp.pdb.facts.io.StandardTextReader;
import org.eclipse.imp.pdb.facts.io.StandardTextWriter;
import org.eclipse.imp.pdb.facts.type.Type;
import org.eclipse.imp.pdb.facts.type.TypeFactory;
import org.eclipse.imp.pdb.facts.type.TypeStore;
import org.rascalmpl.interpreter.IEvaluatorContext;
import org.rascalmpl.interpreter.TypeReifier;
import org.rascalmpl.interpreter.control_exceptions.Throw;
import org.rascalmpl.interpreter.env.ModuleEnvironment;
import org.rascalmpl.interpreter.result.ICallableValue;
import org.rascalmpl.interpreter.staticErrors.UndeclaredNonTerminal;
import org.rascalmpl.interpreter.types.NonTerminalType;
import org.rascalmpl.interpreter.types.ReifiedType;
import org.rascalmpl.interpreter.utils.RuntimeExceptionFactory;
import org.rascalmpl.parser.gtd.IGTD;
import org.rascalmpl.parser.gtd.exception.ParseError;
import org.rascalmpl.parser.gtd.exception.UndeclaredNonTerminalException;
import org.rascalmpl.unicode.UnicodeDetector;
import org.rascalmpl.unicode.UnicodeOutputStreamWriter;
import org.rascalmpl.uri.URIUtil;
import org.rascalmpl.values.uptr.Factory;
import org.rascalmpl.values.uptr.ProductionAdapter;
import org.rascalmpl.values.uptr.SymbolAdapter;
import org.rascalmpl.values.uptr.TreeAdapter;
import org.rascalmpl.values.uptr.visitors.TreeVisitor;

import com.ibm.icu.text.SimpleDateFormat;
import com.ibm.icu.util.Calendar;
import com.ibm.icu.util.TimeZone;
import com.ibm.icu.util.ULocale;

public class Prelude {
  private final TypeFactory types ;
  protected final IValueFactory values;
  private final Random random;
 
  public Prelude(IValueFactory values){
    super();
   
    this.values = values;
    this.types = TypeFactory.getInstance();
    this.tr = new TypeReifier(values);
    random = new Random();
  }

  /*
   * Boolean
   */
 
  public IValue arbBool()  // get an arbitrary boolean value.}
  {
    return values.bool(random.nextInt(2) == 1);
  }
 
  /*
   * DateTime
   */
  public IValue now()
  //@doc{Get the current datetime.}
  {
     return values.datetime(Calendar.getInstance().getTimeInMillis());
  }

  public IValue createDate(IInteger year, IInteger month, IInteger day)
  //@doc{Create a new date.}
  {
    return values.date(year.intValue(), month.intValue(), day.intValue());
  }
 
  public IValue createTime(IInteger hour, IInteger minute, IInteger second,
      IInteger millisecond)
  //@doc{Create a new time.}
  {
    return values.time(hour.intValue(), minute.intValue(), second.intValue(), millisecond.intValue());
  }

  public IValue createTime(IInteger hour, IInteger minute, IInteger second,
      IInteger millisecond, IInteger timezoneHourOffset, IInteger timezoneMinuteOffset)
  //@doc{Create a new time with the given numeric timezone offset.}
  {
    return values.time(hour.intValue(), minute.intValue(), second.intValue(),
        millisecond.intValue(), timezoneHourOffset.intValue(), timezoneMinuteOffset.intValue());
  }
 
  public IValue createDateTime(IInteger year, IInteger month, IInteger day,
      IInteger hour, IInteger minute, IInteger second, IInteger millisecond)
  //@doc{Create a new datetime.}
  {
    return values.datetime(year.intValue(), month.intValue(), day.intValue(), hour.intValue(),
        minute.intValue(), second.intValue(), millisecond.intValue());
  }

  public IValue createDateTime(IInteger year, IInteger month, IInteger day,
      IInteger hour, IInteger minute, IInteger second, IInteger millisecond,
      IInteger timezoneHourOffset, IInteger timezoneMinuteOffset)
  //@doc{Create a new datetime with the given numeric timezone offset.}
  {
    return values.datetime(year.intValue(), month.intValue(), day.intValue(), hour.intValue(),
        minute.intValue(), second.intValue(), millisecond.intValue(), timezoneHourOffset.intValue(),
        timezoneMinuteOffset.intValue());
  }
   
  public IValue joinDateAndTime(IDateTime date, IDateTime time)
  //@doc{Create a new datetime by combining a date and a time.}
  {
    return values.datetime(date.getYear(), date.getMonthOfYear(), date.getDayOfMonth(),
        time.getHourOfDay(), time.getMinuteOfHour(), time.getSecondOfMinute(),
        time.getMillisecondsOfSecond(), time.getTimezoneOffsetHours(), time.getTimezoneOffsetMinutes());
  }

  public IValue splitDateTime(IDateTime dt)
  //@doc{Split an existing datetime into a tuple with the date and the time.}
  {
    return values.tuple(values.date(dt.getYear(), dt.getMonthOfYear(), dt.getDayOfMonth()),
        values.time(dt.getHourOfDay(), dt.getMinuteOfHour(), dt.getSecondOfMinute(),
            dt.getMillisecondsOfSecond(), dt.getTimezoneOffsetHours(), dt.getTimezoneOffsetMinutes()));
  }
 
 
  public IValue incrementYears(IDateTime dt, IInteger n)
  //@doc{Increment the years by a given amount.}
  {
    return incrementDate(dt, Calendar.YEAR, "years", n)
  }
 
  public IValue incrementMonths(IDateTime dt, IInteger n)
  //@doc{Increment the months by a given amount.}
  {
    return incrementDate(dt, Calendar.MONTH, "months", n)
  }

  public IValue incrementDays(IDateTime dt, IInteger n)
  //@doc{Increment the days by a given amount.}
  {
    return incrementDate(dt, Calendar.DAY_OF_MONTH, "days", n)
  }

  private String getTZString(int hourOffset, int minuteOffset) {
    String tzString = "GMT" +
      ((hourOffset < 0 || (0 == hourOffset && minuteOffset < 0)) ? "-" : "+") +
      String.format("%02d",hourOffset >= 0 ? hourOffset : hourOffset * -1) +
      String.format("%02d",minuteOffset >= 0 ? minuteOffset : minuteOffset * -1);
    return tzString;
  }

  private final int millisInAMinute = 1000 * 60;
  private final int millisInAnHour = millisInAMinute * 60;

  private IValue incrementDTField(IDateTime dt, int field, IInteger amount) {
    Calendar cal = null;

    cal = dateTimeToCalendar(dt);
   
    // Make sure lenient is true, since this allows wrapping of fields. For
    // instance, if you have $2012-05-15, and subtract 15 months, this is
    // an error if lenient is false, but gives $2012-02-15 (as expected)
    // if lenient is true.
    cal.setLenient(true);

    cal.add(field, amount.intValue());

    // Turn the calendar back into a date, time, or datetime value
    if (dt.isDate()) {
      return calendarToDate(cal);
    } else {
      if (dt.isTime()) {
        return calendarToTime(cal);
      } else {
        return calendarToDateTime(cal);
      }
    }
  }

  private IValue calendarToDateTime(Calendar cal) {
    int timezoneHours = cal.get(Calendar.ZONE_OFFSET) / millisInAnHour;
    int timezoneMinutes = cal.get(Calendar.ZONE_OFFSET) % millisInAnHour / millisInAMinute;
    return createDateTime(values.integer(cal.get(Calendar.YEAR)),
        values.integer(cal.get(Calendar.MONTH)+1),
        values.integer(cal.get(Calendar.DAY_OF_MONTH)),
        values.integer(cal.get(Calendar.HOUR_OF_DAY)),
        values.integer(cal.get(Calendar.MINUTE)),
        values.integer(cal.get(Calendar.SECOND)),
        values.integer(cal.get(Calendar.MILLISECOND)),
        values.integer(timezoneHours),
        values.integer(timezoneMinutes));
  }

  private IValue calendarToTime(Calendar cal) {
    int timezoneHours = cal.get(Calendar.ZONE_OFFSET) / millisInAnHour;
    int timezoneMinutes = cal.get(Calendar.ZONE_OFFSET) % millisInAnHour / millisInAMinute;
    return createTime(values.integer(cal.get(Calendar.HOUR_OF_DAY)),
        values.integer(cal.get(Calendar.MINUTE)),
        values.integer(cal.get(Calendar.SECOND)),
        values.integer(cal.get(Calendar.MILLISECOND)),
        values.integer(timezoneHours),
        values.integer(timezoneMinutes));
  }

  private IValue calendarToDate(Calendar cal) {
    return createDate(values.integer(cal.get(Calendar.YEAR)),
        values.integer(cal.get(Calendar.MONTH)+1),
        values.integer(cal.get(Calendar.DAY_OF_MONTH)));
  }

  private Calendar dateTimeToCalendar(IDateTime dt) {
    Calendar cal;
    if (dt.isDate()) {
      cal = Calendar.getInstance(TimeZone.getDefault(), Locale.getDefault());
      cal.set(dt.getYear(), dt.getMonthOfYear()-1, dt.getDayOfMonth());
    } else {
      cal = Calendar.getInstance(TimeZone.getTimeZone(getTZString(dt.getTimezoneOffsetHours(), dt.getTimezoneOffsetMinutes())),Locale.getDefault());
      if (dt.isTime()) {
        cal.set(1970, 0, 1, dt.getHourOfDay(), dt.getMinuteOfHour(), dt.getSecondOfMinute());
      } else {
        cal.set(dt.getYear(), dt.getMonthOfYear()-1, dt.getDayOfMonth(), dt.getHourOfDay(), dt.getMinuteOfHour(), dt.getSecondOfMinute());
      }
      cal.set(Calendar.MILLISECOND, dt.getMillisecondsOfSecond());
    }
    return cal;
  }
 
  private IValue incrementTime(IDateTime dt, int field, String fieldName, IInteger amount) {
    if (dt.isDate())
      throw RuntimeExceptionFactory.invalidUseOfDateException("Cannot increment the " + fieldName + " on a date value.", null, null);
   
    return incrementDTField(dt, field, amount);
  }

  private IValue incrementDate(IDateTime dt, int field, String fieldName, IInteger amount) {
    if (dt.isTime())
      throw RuntimeExceptionFactory.invalidUseOfDateException("Cannot increment the " + fieldName + " on a time value.", null, null);
   
    return incrementDTField(dt, field, amount);
  }
 
  public IValue incrementHours(IDateTime dt, IInteger n)
  //@doc{Increment the hours by a given amount.}
  {
    return incrementTime(dt, Calendar.HOUR_OF_DAY, "hours", n);
  }   

  public IValue incrementMinutes(IDateTime dt, IInteger n)
  //@doc{Increment the minutes by a given amount.}
  {
    return incrementTime(dt, Calendar.MINUTE, "minutes", n);
  }   
 
  public IValue incrementSeconds(IDateTime dt, IInteger n)
  //@doc{Increment the seconds by a given amount.}
  {
    return incrementTime(dt, Calendar.SECOND, "seconds", n);
  }
 
  public IValue incrementMilliseconds(IDateTime dt, IInteger n)
  //@doc{Increment the milliseconds by a given amount.}
  {
    return incrementTime(dt, Calendar.MILLISECOND, "milliseconds", n);
  }

  public IValue decrementYears(IDateTime dt, IInteger n)
  //@doc{Decrement the years by a given amount.}
  {
    return incrementDate(dt, Calendar.YEAR, "years", n.negate());
  }   

  public IValue decrementMonths(IDateTime dt, IInteger n)
  //@doc{Decrement the months by a given amount.}
  {
    return incrementDate(dt, Calendar.MONTH, "months", n.negate())

  public IValue decrementDays(IDateTime dt, IInteger n)
  //@doc{Decrement the days by a given amount.}
  {
    return incrementDate(dt, Calendar.DAY_OF_MONTH, "days", n.negate());
  }

  public IValue decrementHours(IDateTime dt, IInteger n)
  //@doc{Decrement the hours by a given amount.}
  {
    return incrementTime(dt, Calendar.HOUR_OF_DAY, "hours", n.negate());
  }   

  public IValue decrementMinutes(IDateTime dt, IInteger n)
  //@doc{Decrement the minutes by a given amount.}
  {
    return incrementTime(dt, Calendar.MINUTE, "minutes", n.negate());
  }   

  public IValue decrementSeconds(IDateTime dt, IInteger n)
  //@doc{Decrement the seconds by a given amount.}
  {
    return incrementTime(dt, Calendar.SECOND, "seconds", n.negate())
  }   

  public IValue decrementMilliseconds(IDateTime dt, IInteger n)
  //@doc{Decrement the milliseconds by a given amount.}
  {
    return incrementTime(dt, Calendar.MILLISECOND, "milliseconds", n.negate());
  }   

  public IValue createDurationInternal(IDateTime dStart, IDateTime dEnd) {
    // dStart and dEnd both have to be dates, times, or datetimes
    Calendar startCal = Calendar.getInstance();
    startCal.setTimeInMillis(dStart.getInstant());
    Calendar endCal = Calendar.getInstance();
    endCal.setTimeInMillis(dEnd.getInstant());
   
    IValue duration = null;
    if (dStart.isDate()) {
      if (dEnd.isDate()) {
        duration = values.tuple(
            values.integer(startCal.fieldDifference(endCal.getTime(), Calendar.YEAR)),
            values.integer(startCal.fieldDifference(endCal.getTime(), Calendar.MONTH)),
            values.integer(startCal.fieldDifference(endCal.getTime(), Calendar.DAY_OF_MONTH)),
            values.integer(0), values.integer(0), values.integer(0),
            values.integer(0));
      } else if (dEnd.isTime()) {
        throw RuntimeExceptionFactory.invalidUseOfTimeException("Cannot determine the duration between a date with no time and a time with no date.", null, null)
      } else {
        throw RuntimeExceptionFactory.invalidUseOfDateTimeException("Cannot determine the duration between a date with no time and a datetime.", null, null);         
      }
    } else if (dStart.isTime()) {
      if (dEnd.isTime()) {
        duration = values.tuple(
            values.integer(0),
            values.integer(0),
            values.integer(0),
            values.integer(startCal.fieldDifference(endCal.getTime(), Calendar.HOUR_OF_DAY)),
            values.integer(startCal.fieldDifference(endCal.getTime(), Calendar.MINUTE)),
            values.integer(startCal.fieldDifference(endCal.getTime(), Calendar.SECOND)),
            values.integer(startCal.fieldDifference(endCal.getTime(), Calendar.MILLISECOND)));
      } else if (dEnd.isDate()) {
        throw RuntimeExceptionFactory.invalidUseOfDateException("Cannot determine the duration between a time with no date and a date with no time.", null, null)
      } else {
        throw RuntimeExceptionFactory.invalidUseOfDateTimeException("Cannot determine the duration between a time with no date and a datetime.", null, null);         
      }
    } else {
      if (dEnd.isDateTime()) {
        duration = values.tuple(
            values.integer(startCal.fieldDifference(endCal.getTime(), Calendar.YEAR)),
            values.integer(startCal.fieldDifference(endCal.getTime(), Calendar.MONTH)),
            values.integer(startCal.fieldDifference(endCal.getTime(), Calendar.DAY_OF_MONTH)),
            values.integer(startCal.fieldDifference(endCal.getTime(), Calendar.HOUR_OF_DAY)),
            values.integer(startCal.fieldDifference(endCal.getTime(), Calendar.MINUTE)),
            values.integer(startCal.fieldDifference(endCal.getTime(), Calendar.SECOND)),
            values.integer(startCal.fieldDifference(endCal.getTime(), Calendar.MILLISECOND)));
      } else if (dEnd.isDate()) {
        throw RuntimeExceptionFactory.invalidUseOfDateException("Cannot determine the duration between a datetime and a date with no time.", null, null)
      } else {
        throw RuntimeExceptionFactory.invalidUseOfTimeException("Cannot determine the duration between a datetime and a time with no date.", null, null);         
      }
    }
    return duration;
  }
 
  public IValue parseDate(IString inputDate, IString formatString)
  //@doc{Parse an input date given as a string using the given format string}
 
    try {
      java.text.SimpleDateFormat fmt = new java.text.SimpleDateFormat(formatString.getValue());
      fmt.parse(inputDate.getValue());
      java.util.Calendar cal = fmt.getCalendar();
      return values.date(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH) + 1, cal.get(Calendar.DATE));
    } catch (IllegalArgumentException iae) {
      throw RuntimeExceptionFactory.dateTimeParsingError("Cannot parse input date: " + inputDate.getValue() +
          " using format string: " + formatString.getValue(), null, null);
    } catch (ParseException e) {
      throw RuntimeExceptionFactory.dateTimeParsingError("Cannot parse input date: " + inputDate.getValue() +
          " using format string: " + formatString.getValue(), null, null);
    }
  }
 
  public IValue parseDateInLocale(IString inputDate, IString formatString, IString locale)
  //@doc{Parse an input date given as a string using a specific locale and format string}
  {
    try {
      java.text.SimpleDateFormat fmt = new java.text.SimpleDateFormat(formatString.getValue(), new Locale(locale.getValue()));
      fmt.parse(inputDate.getValue());
      java.util.Calendar cal = fmt.getCalendar();
      return values.date(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH) + 1, cal.get(Calendar.DATE));
    } catch (IllegalArgumentException iae) {
      throw RuntimeExceptionFactory.dateTimeParsingError("Cannot parse input date: " + inputDate.getValue() +
          " using format string: " + formatString.getValue() + " in locale: " + locale.getValue(), null, null);
    } catch (ParseException e) {
      throw RuntimeExceptionFactory.dateTimeParsingError("Cannot parse input date: " + inputDate.getValue() +
          " using format string: " + formatString.getValue() + " in locale: " + locale.getValue(), null, null);
    }
  }

  public IValue parseTime(IString inputTime, IString formatString)
  //@doc{Parse an input time given as a string using the given format string}
  {
    try {
      java.text.SimpleDateFormat fmt = new java.text.SimpleDateFormat(formatString.getValue());
      fmt.parse(inputTime.getValue());
      java.util.Calendar cal = fmt.getCalendar();
      // The value for zone offset comes back in milliseconds. The number of
      // hours is thus milliseconds / 1000 (to get to seconds) / 60 (to get to minutes)
      // / 60 (to get to hours). Minutes is this except for the last division,
      // but then we use mod 60 since this gives us total # of minutes, including
      // the hours we have already computed.
      int zoneHours = cal.get(Calendar.ZONE_OFFSET) / (1000 * 60 * 60);
      int zoneMinutes = (cal.get(Calendar.ZONE_OFFSET) / (1000 * 60)) % 60;
      return values.time(cal.get(Calendar.HOUR_OF_DAY), cal.get(Calendar.MINUTE), cal.get(Calendar.SECOND), cal.get(Calendar.MILLISECOND), zoneHours, zoneMinutes);
    } catch (IllegalArgumentException iae) {
      throw RuntimeExceptionFactory.dateTimeParsingError("Cannot parse input date: " + inputTime.getValue() +
          " using format string: " + formatString.getValue(), null, null);
    } catch (ParseException e) {
      throw RuntimeExceptionFactory.dateTimeParsingError("Cannot parse input date: " + inputTime.getValue() +
          " using format string: " + formatString.getValue(), null, null);
    }
  }
 
  public IValue parseTimeInLocale(IString inputTime, IString formatString, IString locale)
  //@doc{Parse an input time given as a string using a specific locale and format string}
  {
    try {
      java.text.SimpleDateFormat fmt = new java.text.SimpleDateFormat(formatString.getValue(), new Locale(locale.getValue()));
      fmt.parse(inputTime.getValue());
      java.util.Calendar cal = fmt.getCalendar();
      // The value for zone offset comes back in milliseconds. The number of
      // hours is thus milliseconds / 1000 (to get to seconds) / 60 (to get to minutes)
      // / 60 (to get to hours). Minutes is this except for the last division,
      // but then we use mod 60 since this gives us total # of minutes, including
      // the hours we have already computed.
      int zoneHours = cal.get(Calendar.ZONE_OFFSET) / (1000 * 60 * 60);
      int zoneMinutes = (cal.get(Calendar.ZONE_OFFSET) / (1000 * 60)) % 60;
      return values.time(cal.get(Calendar.HOUR_OF_DAY), cal.get(Calendar.MINUTE), cal.get(Calendar.SECOND), cal.get(Calendar.MILLISECOND), zoneHours, zoneMinutes);
    } catch (IllegalArgumentException iae) {
      throw RuntimeExceptionFactory.dateTimeParsingError("Cannot parse input time: " + inputTime.getValue() +
          " using format string: " + formatString.getValue() + " in locale: " + locale.getValue(), null, null);
    } catch (ParseException e) {
      throw RuntimeExceptionFactory.dateTimeParsingError("Cannot parse input time: " + inputTime.getValue() +
          " using format string: " + formatString.getValue() + " in locale: " + locale.getValue(), null, null);
    }
  }

  public IString printSymbol(IConstructor symbol, IBool withLayout) {
    return values.string(SymbolAdapter.toString(symbol, withLayout.getValue()));
  }
 
  public IValue parseDateTime(IString inputDateTime, IString formatString)
  //@doc{Parse an input datetime given as a string using the given format string}
  {
    try {
      java.text.SimpleDateFormat fmt = new java.text.SimpleDateFormat(formatString.getValue());
      fmt.setLenient(false);
      fmt.parse(inputDateTime.getValue());
      java.util.Calendar cal = fmt.getCalendar();
      int zoneHours = cal.get(Calendar.ZONE_OFFSET) / (1000 * 60 * 60);
      int zoneMinutes = (cal.get(Calendar.ZONE_OFFSET) / (1000 * 60)) % 60;
      return values.datetime(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH) + 1, cal.get(Calendar.DAY_OF_MONTH), cal.get(Calendar.HOUR_OF_DAY), cal.get(Calendar.MINUTE), cal.get(Calendar.SECOND), cal.get(Calendar.MILLISECOND), zoneHours, zoneMinutes);
    } catch (IllegalArgumentException iae) {
      throw RuntimeExceptionFactory.dateTimeParsingError("Cannot parse input datetime: " + inputDateTime.getValue() +
          " using format string: " + formatString.getValue(), null, null);
    } catch (ParseException e) {
      throw RuntimeExceptionFactory.dateTimeParsingError("Cannot parse input datetime: " + inputDateTime.getValue() +
          " using format string: " + formatString.getValue(), null, null);
    }     
  }
 
  public IValue parseDateTimeInLocale(IString inputDateTime, IString formatString, IString locale)
  //@doc{Parse an input datetime given as a string using a specific locale and format string}
  {
    try {
      java.text.SimpleDateFormat fmt = new java.text.SimpleDateFormat(formatString.getValue(), new Locale(locale.getValue()));
      fmt.parse(inputDateTime.getValue());
      java.util.Calendar cal = fmt.getCalendar();
      int zoneHours = cal.get(Calendar.ZONE_OFFSET) / (1000 * 60 * 60);
      int zoneMinutes = (cal.get(Calendar.ZONE_OFFSET) / (1000 * 60)) % 60;
      return values.datetime(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH) + 1, cal.get(Calendar.DAY_OF_MONTH), cal.get(Calendar.HOUR_OF_DAY), cal.get(Calendar.MINUTE), cal.get(Calendar.SECOND), cal.get(Calendar.MILLISECOND), zoneHours, zoneMinutes);
    } catch (IllegalArgumentException iae) {
      throw RuntimeExceptionFactory.dateTimeParsingError("Cannot parse input datetime: " + inputDateTime.getValue() +
          " using format string: " + formatString.getValue() + " in locale: " + locale.getValue(), null, null);
    } catch (ParseException e) {
      throw RuntimeExceptionFactory.dateTimeParsingError("Cannot parse input datetime: " + inputDateTime.getValue() +
          " using format string: " + formatString.getValue() + " in locale: " + locale.getValue(), null, null);
    }
  }

  private Calendar getCalendarForDate(IDateTime inputDate) {
    if (inputDate.isDate() || inputDate.isDateTime()) {
      Calendar cal = Calendar.getInstance(TimeZone.getDefault(),Locale.getDefault());
      cal.setLenient(false);
      cal.set(inputDate.getYear(), inputDate.getMonthOfYear()-1, inputDate.getDayOfMonth());
      return cal;
    } else {
      throw new IllegalArgumentException("Cannot get date for a datetime that only represents the time");
    }
  }
 
  private Calendar getCalendarForTime(IDateTime inputTime) {
    if (inputTime.isTime() || inputTime.isDateTime()) {
      Calendar cal = Calendar.getInstance(TimeZone.getTimeZone(getTZString(inputTime.getTimezoneOffsetHours(),inputTime.getTimezoneOffsetMinutes())),Locale.getDefault());
      cal.setLenient(false);
      cal.set(Calendar.HOUR_OF_DAY, inputTime.getHourOfDay());
      cal.set(Calendar.MINUTE, inputTime.getMinuteOfHour());
      cal.set(Calendar.SECOND, inputTime.getSecondOfMinute());
      cal.set(Calendar.MILLISECOND, inputTime.getMillisecondsOfSecond());
      return cal;
    } else {
      throw new IllegalArgumentException("Cannot get time for a datetime that only represents the date");
    }
  }

  private Calendar getCalendarForDateTime(IDateTime inputDateTime) {
    if (inputDateTime.isDateTime()) {
      Calendar cal = Calendar.getInstance(TimeZone.getTimeZone(getTZString(inputDateTime.getTimezoneOffsetHours(),inputDateTime.getTimezoneOffsetMinutes())),Locale.getDefault());
      cal.setLenient(false);
      cal.set(inputDateTime.getYear(), inputDateTime.getMonthOfYear()-1, inputDateTime.getDayOfMonth(), inputDateTime.getHourOfDay(), inputDateTime.getMinuteOfHour(), inputDateTime.getSecondOfMinute());
      cal.set(Calendar.MILLISECOND, inputDateTime.getMillisecondsOfSecond());
      return cal;
    } else {
      throw new IllegalArgumentException("Cannot get date and time for a datetime that only represents the date or the time");
    }
  }

  public IValue printDate(IDateTime inputDate, IString formatString)
  //@doc{Print an input date using the given format string}
  {
    try {
      SimpleDateFormat sd = new SimpleDateFormat(formatString.getValue());
      Calendar cal = getCalendarForDate(inputDate);
      sd.setCalendar(cal);
      return values.string(sd.format(cal.getTime()));
    } catch (IllegalArgumentException iae) {
      throw RuntimeExceptionFactory.dateTimePrintingError("Cannot print time with format " + formatString.getValue(), null, null);
    }
  }

  public IValue printDate(IDateTime inputDate)
  //@doc{Print an input date using a default format string}
  {
    SimpleDateFormat sd = new SimpleDateFormat("yyyy-MM-dd");
    Calendar cal = getCalendarForDate(inputDate);
    sd.setCalendar(cal);
    return values.string(sd.format(cal.getTime()));
  }
 
  public IValue printDateInLocale(IDateTime inputDate, IString formatString, IString locale)
  //@doc{Print an input date using a specific locale and format string}
  {
    try {
      SimpleDateFormat sd = new SimpleDateFormat(formatString.getValue(),new ULocale(locale.getValue()));
      Calendar cal = getCalendarForDate(inputDate);
      sd.setCalendar(cal);
      return values.string(sd.format(cal.getTime()));
    } catch (IllegalArgumentException iae) {
      throw RuntimeExceptionFactory.dateTimePrintingError("Cannot print time with format " + formatString.getValue() + ", in locale: " + locale.getValue(), null, null);
    }
  }

  public IValue printDateInLocale(IDateTime inputDate, IString locale)
  //@doc{Print an input date using a specific locale and a default format string}
  {
    try {
      SimpleDateFormat sd = new SimpleDateFormat("yyyy-MM-dd",new ULocale(locale.getValue()));
      Calendar cal = getCalendarForDate(inputDate);
      sd.setCalendar(cal);
      return values.string(sd.format(cal.getTime()));
    } catch (IllegalArgumentException iae) {
      throw RuntimeExceptionFactory.dateTimePrintingError("Cannot print time in locale: " + locale.getValue(), null, null);
    }
  }

  public IValue printTime(IDateTime inputTime, IString formatString)
  //@doc{Print an input time using the given format string}
  {
    try {
      SimpleDateFormat sd = new SimpleDateFormat(formatString.getValue());
      Calendar cal = getCalendarForTime(inputTime);
      sd.setCalendar(cal);
      return values.string(sd.format(cal.getTime()));
    } catch (IllegalArgumentException iae) {
      throw RuntimeExceptionFactory.dateTimePrintingError("Cannot print time with format: " + formatString.getValue(), null, null);
    }     
  }
 
  public IValue printTime(IDateTime inputTime)
  //@doc{Print an input time using a default format string}
  {
    SimpleDateFormat sd = new SimpleDateFormat("HH:mm:ss.SSSZ");
    Calendar cal = getCalendarForTime(inputTime);
    sd.setCalendar(cal);
    return values.string(sd.format(cal.getTime()));
  }
 
  public IValue printTimeInLocale(IDateTime inputTime, IString formatString, IString locale)
  //@doc{Print an input time using a specific locale and format string}
  {
    try {
      SimpleDateFormat sd = new SimpleDateFormat(formatString.getValue(),new ULocale(locale.getValue()));
      Calendar cal = getCalendarForTime(inputTime);
      sd.setCalendar(cal);
      return values.string(sd.format(cal.getTime()));
    } catch (IllegalArgumentException iae) {
      throw RuntimeExceptionFactory.dateTimePrintingError("Cannot print time in locale: " + locale.getValue(), null, null);
    }
  }

  public IValue printTimeInLocale(IDateTime inputTime, IString locale)
  //@doc{Print an input time using a specific locale and a default format string}
  {
    try {
      SimpleDateFormat sd = new SimpleDateFormat("HH:mm:ss.SSSZ",new ULocale(locale.getValue()));
      Calendar cal = getCalendarForTime(inputTime);
      sd.setCalendar(cal);
      return values.string(sd.format(cal.getTime()));
    } catch (IllegalArgumentException iae) {
      throw RuntimeExceptionFactory.dateTimePrintingError("Cannot print time in locale: " + locale.getValue(), null, null);
    }
  }

  public IValue printDateTime(IDateTime inputDateTime, IString formatString)
  //@doc{Print an input datetime using the given format string}
  {
    try {
      SimpleDateFormat sd = new SimpleDateFormat(formatString.getValue());
      Calendar cal = getCalendarForDateTime(inputDateTime);
      sd.setCalendar(cal);
      return values.string(sd.format(cal.getTime()));
    } catch (IllegalArgumentException iae) {
      throw RuntimeExceptionFactory.dateTimePrintingError("Cannot print datetime using format string: " + formatString.getValue(), null, null);
    }   
  }

  public IValue printDateTime(IDateTime inputDateTime)
  //@doc{Print an input datetime using a default format string}
  {
    SimpleDateFormat sd = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSZ");
    Calendar cal = getCalendarForDateTime(inputDateTime);
    sd.setCalendar(cal);
    return values.string(sd.format(cal.getTime()));
  }
 
  public IValue printDateTimeInLocale(IDateTime inputDateTime, IString formatString, IString locale)
  //@doc{Print an input datetime using a specific locale and format string}
  {
    try {
      SimpleDateFormat sd = new SimpleDateFormat(formatString.getValue(),new ULocale(locale.getValue()));
      Calendar cal = getCalendarForDateTime(inputDateTime);
      sd.setCalendar(cal);
      return values.string(sd.format(cal.getTime()));
    } catch (IllegalArgumentException iae) {
      throw RuntimeExceptionFactory.dateTimePrintingError("Cannot print datetime using format string: " + formatString.getValue() +
          " in locale: " + locale.getValue(), null, null);
    }
  }

  public IValue printDateTimeInLocale(IDateTime inputDateTime, IString locale)
  //@doc{Print an input datetime using a specific locale and a default format string}
  {
    try {
      SimpleDateFormat sd = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSZ",new ULocale(locale.getValue()));
      Calendar cal = getCalendarForDateTime(inputDateTime);
      sd.setCalendar(cal);
      return values.string(sd.format(cal.getTime()));
    } catch (IllegalArgumentException iae) {
      throw RuntimeExceptionFactory.dateTimePrintingError("Cannot print datetime in locale: " + locale.getValue(), null, null);
    }
  }
 
    public IValue daysDiff(IDateTime dtStart, IDateTime dtEnd)
    //@doc{Increment the years by a given amount.}
    {
            if (!(dtStart.isTime() || dtEnd.isTime())) {
                    Calendar startCal = Calendar.getInstance();
                    startCal.setTimeInMillis(dtStart.getInstant());
                    Calendar endCal = Calendar.getInstance();
                    endCal.setTimeInMillis(dtEnd.getInstant());
                   
                    return values.integer(startCal.fieldDifference(endCal.getTime(), Calendar.DAY_OF_MONTH));
            }
            throw RuntimeExceptionFactory.invalidUseOfTimeException("Both inputs must include dates.", null, null);
    }

    /*
   * Graph
   */
 
  private HashMap<IValue,Distance> distance;
  private HashMap<IValue, IValue> pred;
  private HashSet<IValue> settled;
  private PriorityQueue<IValue> Q;
  private int MAXDISTANCE = 10000;
 
  private HashMap<IValue, LinkedList<IValue>> adjacencyList;
 
  private void buildAdjacencyListAndDistance(ISet G){
    adjacencyList = new HashMap<IValue, LinkedList<IValue>> ();
    distance = new HashMap<IValue, Distance>();
   
    for(IValue v : G){
      ITuple tup = (ITuple) v;
      IValue from = tup.get(0);
      IValue to = tup.get(1);
     
      if(distance.get(from) == null)
        distance.put(from, new Distance(MAXDISTANCE));
      if(distance.get(to) == null)
        distance.put(to, new Distance(MAXDISTANCE));
     
      LinkedList<IValue> adjacencies = adjacencyList.get(from);
      if(adjacencies == null)
        adjacencies = new LinkedList<IValue>();
      adjacencies.add(to);
      adjacencyList.put(from, adjacencies);
    }
  }
 
  public IValue shortestPathPair(ISet G, IValue From, IValue To){
    buildAdjacencyListAndDistance(G);
    distance.put(From, new Distance(0));
   
    pred = new HashMap<IValue, IValue>();
    settled = new HashSet<IValue>();
    Q = new PriorityQueue<IValue>(G.size(), new NodeComparator(distance));
    Q.add(From);
   
    while(!Q.isEmpty()){
      IValue u = Q.remove();
      if(u.isEqual(To)) 
        return extractPath(From, u);
      settled.add(u);
      relaxNeighbours(u);
    }
    return values.list();
  }
 
  private void relaxNeighbours(IValue u){
    LinkedList<IValue> adjacencies = adjacencyList.get(u);
    if(adjacencies != null) {
      for(IValue v : adjacencyList.get(u)){
        if(!settled.contains(v)){
          Distance dv = distance.get(v);
          Distance du = distance.get(u);
          if(dv.intval > du.intval + 1){  // 1 is default weight of each edge
            dv.intval = du.intval + 1;
            pred.put(v,u);
            Q.add(v);
          }
        }
      }
    }
  }
 
  private IList extractPath(IValue start, IValue u){
    IListWriter w = values.listWriter();
   
    if(!start.isEqual(u)){
      w.insert(u);
      while(!pred.get(u).isEqual(start)){
        u = pred.get(u);
        w.insert(u);
      }
      // TODO Check if a path was found at all; it could be that we just hit the root of the graph.
    }
    w.insert(start);
    return w.done();
  }
 
  public void print(IValue arg, IEvaluatorContext eval){
    PrintWriter currentOutStream = eval.getStdOut();
   
    try{
      if(arg.getType().isString()){
        currentOutStream.print(((IString) arg).getValue().toString());
      }
      else if(arg.getType().isSubtypeOf(Factory.Tree)){
        currentOutStream.print(TreeAdapter.yield((IConstructor) arg));
      }
      else if (arg.getType().isSubtypeOf(Factory.Type)) {
        currentOutStream.print(SymbolAdapter.toString((IConstructor) ((IConstructor) arg).get("symbol"), false));
      }
      else{
        currentOutStream.print(arg.toString());
      }
    }finally{
      currentOutStream.flush();
    }
  }
 
  public void iprint(IValue arg, IEvaluatorContext eval){
    StandardTextWriter w = new StandardTextWriter(true, 2);
   
    try {
      w.write(arg, eval.getStdOut());
    }
    catch (IOException e) {
      RuntimeExceptionFactory.io(values.string("Could not print indented value"), eval.getCurrentAST(), eval.getStackTrace());
    }
    finally{
      eval.getStdOut().flush();
    }
  }
 
  public void iprintToFile(ISourceLocation sloc, IValue arg, IEvaluatorContext eval) {
    StandardTextWriter w = new StandardTextWriter(true, 2);
    StringWriter sw = new StringWriter();

    try {
      w.write(arg, sw);
      writeFile(sloc, values.list(values.string(sw.toString())), eval);
    } catch (IOException e) {
      throw RuntimeExceptionFactory.io(values.string(e.getMessage()), eval.getCurrentAST(), null);   
    }
  }
 
  public void iprintln(IValue arg, IEvaluatorContext eval){
    StandardTextWriter w = new StandardTextWriter(true, 2);
   
    try {
      w.write(arg, eval.getStdOut());
      eval.getStdOut().println();
    }
    catch (IOException e) {
      RuntimeExceptionFactory.io(values.string("Could not print indented value"), eval.getCurrentAST(), eval.getStackTrace());
    }
    finally{
      eval.getStdOut().flush();
    }
  }
 
  public void println(IEvaluatorContext eval) {
    eval.getStdOut().println();
    eval.getStdOut().flush();
  }
 
  public void println(IValue arg, IEvaluatorContext eval){
    PrintWriter currentOutStream = eval.getStdOut();
   
    try{
      if(arg.getType().isString()){
        currentOutStream.print(((IString) arg).getValue());
      }
      else if(arg.getType().isSubtypeOf(Factory.Tree)){
        currentOutStream.print(TreeAdapter.yield((IConstructor) arg));
      }
      else if (arg.getType().isSubtypeOf(Factory.Type)) {
        currentOutStream.print(SymbolAdapter.toString((IConstructor) ((IConstructor) arg).get("symbol"), false));
      }
      else{
        currentOutStream.print(arg.toString());
      }
      currentOutStream.println();
    }finally{
      currentOutStream.flush();
    }
  }
 
  public void rprintln(IValue arg, IEvaluatorContext eval){
    PrintWriter currentOutStream = eval.getStdOut();
   
    try{
      currentOutStream.print(arg.toString());
      currentOutStream.println();
    }finally{
      currentOutStream.flush();
    }
  }
 
  public void rprint(IValue arg, IEvaluatorContext eval){
    PrintWriter currentOutStream = eval.getStdOut();
   
    try{
      currentOutStream.print(arg.toString());
    }finally{
      currentOutStream.flush();
    }
  }

  @Deprecated
  public IValue readFile(IString filename){
    IListWriter w = values.listWriter(types.stringType());
   
    BufferedReader in = null;
    try{
      in = new BufferedReader(new FileReader(filename.getValue()));
      java.lang.String line;

      do {
        line = in.readLine();
        if(line != null){
          w.append(values.string(line));
        }
      } while (line != null);
    }catch(FileNotFoundException fnfex){
      throw RuntimeExceptionFactory.pathNotFound(values.sourceLocation(filename.getValue()), null, null);
    }catch(IOException ioex){
      throw RuntimeExceptionFactory.io(values.string(ioex.getMessage()), null, null);
    }finally{
      if(in != null){
        try{
          in.close();
        }catch(IOException ioex){
          throw RuntimeExceptionFactory.io(values.string(ioex.getMessage()), null, null);
        }
      }
    }
    return w.done();
  }
 
  // REFLECT -- copy in PreludeCompiled
  public IValue exists(ISourceLocation sloc, IEvaluatorContext ctx) {
    sloc = ctx.getHeap().resolveSourceLocation(sloc);
    return values.bool(ctx.getResolverRegistry().exists(sloc.getURI()));
  }
 
  // REFLECT -- copy in PreludeCompiled
  public IValue lastModified(ISourceLocation sloc, IEvaluatorContext ctx) {
    sloc = ctx.getHeap().resolveSourceLocation(sloc);
   
    try {
      return values.datetime(ctx.getResolverRegistry().lastModified(sloc.getURI()));
    } catch(FileNotFoundException e){
      throw RuntimeExceptionFactory.pathNotFound(sloc, null, null);
    }
    catch (IOException e) {
      throw RuntimeExceptionFactory.io(values.string(e.getMessage()), ctx.getCurrentAST(), ctx.getStackTrace());
    }
  }
 
  // REFLECT -- copy in PreludeCompiled
  public IValue isDirectory(ISourceLocation sloc, IEvaluatorContext ctx) {
    sloc = ctx.getHeap().resolveSourceLocation(sloc);
    return values.bool(ctx.getResolverRegistry().isDirectory(sloc.getURI()));
  }
 
  // REFLECT -- copy in PreludeCompiled
  public IValue isFile(ISourceLocation sloc, IEvaluatorContext ctx) {
    sloc = ctx.getHeap().resolveSourceLocation(sloc);
    return values.bool(ctx.getResolverRegistry().isFile(sloc.getURI()));
  }
 
  // REFLECT -- copy in PreludeCompiled
  public void remove(ISourceLocation sloc, IEvaluatorContext ctx) {
    try {
      sloc = ctx.getHeap().resolveSourceLocation(sloc);
      ctx.getResolverRegistry().remove(sloc.getURI());
    }
    catch (IOException e) {
      RuntimeExceptionFactory.io(values.string(e.getMessage()), null, null);
    }
  }
 
  // REFLECT -- copy in PreludeCompiled
  public void mkDirectory(ISourceLocation sloc, IEvaluatorContext ctx) {
    try {
      sloc = ctx.getHeap().resolveSourceLocation(sloc);
      ctx.getResolverRegistry().mkDirectory(sloc.getURI());
    }
    catch (IOException e) {
      RuntimeExceptionFactory.io(values.string(e.getMessage()), null, null);
    }
  }
 
  // REFLECT -- copy in PreludeCompiled
  public IValue listEntries(ISourceLocation sloc, IEvaluatorContext ctx) {
    sloc = ctx.getHeap().resolveSourceLocation(sloc);
   
    try {
      java.lang.String [] entries = ctx.getResolverRegistry().listEntries(sloc.getURI());
      IListWriter w = values.listWriter();
      for(java.lang.String entry : entries){
        w.append(values.string(entry));
      }
      return w.done();
    } catch(FileNotFoundException e){
      throw RuntimeExceptionFactory.pathNotFound(sloc, null, null);
    } catch (IOException e) {
      throw RuntimeExceptionFactory.io(values.string(e.getMessage()), null, null);
    }
  }
 
  public ISet charsets() {
    ISetWriter w = values.setWriter();
    for (String s : Charset.availableCharsets().keySet()) {
      w.insert(values.string(s));
    }
    return w.done();
  }
 
  // REFLECT -- copy in PreludeCompiled
  public IValue readFile(ISourceLocation sloc, IEvaluatorContext ctx){
    sloc = ctx.getHeap().resolveSourceLocation(sloc);
    Reader reader = null;
   
    try {
      Charset c = ctx.getResolverRegistry().getCharset(sloc.getURI());
      if (c != null) {
        return readFileEnc(sloc, values.string(c.name()), ctx);
      }
      sloc = ctx.getHeap().resolveSourceLocation(sloc);
      reader = ctx.getResolverRegistry().getCharacterReader(sloc.getURI());
      return consumeInputStream(sloc, reader, ctx);
    } catch(FileNotFoundException e){
      throw RuntimeExceptionFactory.pathNotFound(sloc, ctx.getCurrentAST(), null);
    }
    catch (IOException e) {
      throw RuntimeExceptionFactory.io(values.string(e.getMessage()), null, null);
    }
    finally {
      if (reader != null) {
        try {
          reader.close();
        } catch (IOException e) {
          // TODO Auto-generated catch block
        }
      }
    }
  }
 
  // REFLECT -- copy in PreludeCompiled
  public IValue readFileEnc(ISourceLocation sloc, IString charset, IEvaluatorContext ctx){
    sloc = ctx.getHeap().resolveSourceLocation(sloc);
   
    try (Reader reader = ctx.getResolverRegistry().getCharacterReader(sloc.getURI(), charset.getValue())){
      return consumeInputStream(sloc, reader, ctx);
    } catch(FileNotFoundException e){
      throw RuntimeExceptionFactory.pathNotFound(sloc, ctx.getCurrentAST(), null);
    } catch (IOException e) {
      throw RuntimeExceptionFactory.io(values.string(e.getMessage()), null, null);
    }
  }

  // REFLECT -- copy in PreludeCompiled
  private IValue consumeInputStream(ISourceLocation sloc, Reader in, IEvaluatorContext ctx) {
    try{
      java.lang.String str = null;
      if(!sloc.hasOffsetLength() || sloc.getOffset() == -1){
        StringBuilder result = new StringBuilder(1024 * 1024);
        char[] buf = new char[4096];
        int count;
 
        while((count = in.read(buf)) != -1) {
          result.append(new java.lang.String(buf, 0, count));
        }
        str = result.toString();
      }
      else {
        BufferedReader buffer = new BufferedReader(in, 4096);
        try {
          // first scan for offset
          int offset = sloc.getOffset();
          int seen = 0 ;
          while (seen < offset) {
            char c = (char)buffer.read();
            if (Character.isHighSurrogate(c)) {
              c = (char)buffer.read();
              if (!Character.isLowSurrogate(c))
                seen++;// strange string but it is possible

            }
            seen++;
          }
 
          // offset reached, start reading and possibly merging
          int targetLength = sloc.getLength();
          StringBuilder result = new StringBuilder(targetLength);
          int charsRead = 0;
          while (charsRead < targetLength) {
            int c = buffer.read();
            if (c == -1) {
              break; // EOF
            }
            charsRead++;
            result.append((char)c);
            if (Character.isHighSurrogate((char)c)) {
              c = buffer.read();
              if (c == -1) {
                break; // EOF
              }
              result.append((char)c);
              if (!Character.isLowSurrogate((char)c)) {
                // strange but in case of incorrect unicode stream
                // let's not eat the next character
                charsRead++;
              }
            }
          }
          str = result.toString();
        }
        finally {
          buffer.close();
        }
       
      }
      return values.string(str);
    }catch(FileNotFoundException fnfex){
      throw RuntimeExceptionFactory.pathNotFound(sloc, ctx.getCurrentAST(), null);
    }catch(IOException ioex){
      throw RuntimeExceptionFactory.io(values.string(ioex.getMessage()), ctx.getCurrentAST(), null);
    }finally{
      if(in != null){
        try{
          in.close();
        }catch(IOException ioex){
          throw RuntimeExceptionFactory.io(values.string(ioex.getMessage()), ctx.getCurrentAST(), null);
        }
      }
    }
  }
 
  // REFLECT -- copy in PreludeCompiled
  public IValue md5HashFile(ISourceLocation sloc, IEvaluatorContext ctx){
    StringBuilder result = new StringBuilder(1024 * 1024);
   
    InputStream in = null;
    try{
      in = ctx.getResolverRegistry().getInputStream(sloc.getURI());
      MessageDigest md = MessageDigest.getInstance("MD5");
      in = new DigestInputStream(in, md);
      byte[] buf = new byte[4096];
      int count;

      while((count = in.read(buf)) != -1){
        result.append(new java.lang.String(buf, 0, count));
      }
     
      return values.string(new String(md.digest()));
    }catch(FileNotFoundException fnfex){
      throw RuntimeExceptionFactory.pathNotFound(sloc, ctx.getCurrentAST(), null);
    }catch(IOException ioex){
      throw RuntimeExceptionFactory.io(values.string(ioex.getMessage()), ctx.getCurrentAST(), null);
    } catch (NoSuchAlgorithmException e) {
      throw RuntimeExceptionFactory.io(values.string("Cannot load MD5 digest algorithm"), ctx.getCurrentAST(), null);
    }finally{
      if(in != null){
        try{
          in.close();
        }catch(IOException ioex){
          throw RuntimeExceptionFactory.io(values.string(ioex.getMessage()), ctx.getCurrentAST(), null);
        }
      }
    }
  }

  // REFLECT -- copy in PreludeCompiled
  public void writeFile(ISourceLocation sloc, IList V, IEvaluatorContext ctx) {
    writeFile(sloc, V, false, ctx);
  }
 
  // REFLECT -- copy in PreludeCompiled
  public void writeFileEnc(ISourceLocation sloc, IString charset, IList V, IEvaluatorContext ctx) {
    writeFileEnc(sloc, charset, V, false, ctx);
  }
 
  // REFLECT -- copy in PreludeCompiled
  private void writeFile(ISourceLocation sloc, IList V, boolean append, IEvaluatorContext ctx){
    sloc = ctx.getHeap().resolveSourceLocation(sloc);
   
    IString charset = values.string("UTF8");
    if (append) {
      // in case the file already has a encoding, we have to correctly append that.
      InputStream in = null;
      Charset detected = null;
      try {
        detected = ctx.getResolverRegistry().getCharset(sloc.getURI());
        if (detected == null) {
          in = ctx.getResolverRegistry().getInputStream(sloc.getURI());
          detected = UnicodeDetector.estimateCharset(in);
        }
      }catch(FileNotFoundException fnfex){
        throw RuntimeExceptionFactory.pathNotFound(sloc, ctx.getCurrentAST(), null);
      } catch (IOException e) {
        throw RuntimeExceptionFactory.io(values.string(e.getMessage()), ctx.getCurrentAST(), null);
      }
      finally {
        if (in != null) {
          try {
            in.close();
          } catch (IOException e) {
            throw RuntimeExceptionFactory.io(values.string(e.getMessage()), ctx.getCurrentAST(), null);
          }
        }
      }
      if (detected != null)
        charset = values.string(detected.name());
      else {
        charset = values.string(Charset.defaultCharset().name());
      }
    }
    writeFileEnc(sloc, charset, V, append, ctx);
  }
 
  public IBool canEncode(IString charset) {
    return values.bool(Charset.forName(charset.getValue()).canEncode());
  }
 
  // REFLECT -- copy in PreludeCompiled
  private void writeFileEnc(ISourceLocation sloc, IString charset, IList V, boolean append, IEvaluatorContext ctx){
    sloc = ctx.getHeap().resolveSourceLocation(sloc);
   
    OutputStreamWriter out = null;
   
    if (!Charset.forName(charset.getValue()).canEncode()) {
        throw RuntimeExceptionFactory.illegalArgument(charset, null, null);
    }
   
    try{
      out = new UnicodeOutputStreamWriter(ctx.getResolverRegistry().getOutputStream(sloc.getURI(), append), charset.getValue(), append);
     
      for(IValue elem : V){
        if (elem.getType().isString()) {
          out.append(((IString) elem).getValue());
        }else if (elem.getType().isSubtypeOf(Factory.Tree)) {
          out.append(TreeAdapter.yield((IConstructor) elem));
        }else{
          out.append(elem.toString());
        }
      }
    }catch(FileNotFoundException fnfex){
      throw RuntimeExceptionFactory.pathNotFound(sloc, ctx.getCurrentAST(), null);
    }catch(IOException ioex){
      throw RuntimeExceptionFactory.io(values.string(ioex.getMessage()), ctx.getCurrentAST(), null);
    }finally{
      if(out != null){
        try{
          out.close();
        }catch(IOException ioex){
          throw RuntimeExceptionFactory.io(values.string(ioex.getMessage()), ctx.getCurrentAST(), null);
        }
      }
    }

    return;
  }
 
  // REFLECT -- copy in PreludeCompiled
 
  public void writeFileBytes(ISourceLocation sloc, IList blist, IEvaluatorContext ctx){
    sloc = ctx.getHeap().resolveSourceLocation(sloc);
    BufferedOutputStream out=null;
    try{
      OutputStream stream = ctx.getResolverRegistry().getOutputStream(sloc.getURI(), false);
      out = new BufferedOutputStream(stream);
      Iterator<IValue> iter = blist.iterator();
      while (iter.hasNext()){
        IValue ival = iter.next();
        out.write((byte) (((IInteger) ival).intValue()));
      }
      out.flush();
      out.close();
    }catch(FileNotFoundException e){
      throw RuntimeExceptionFactory.pathNotFound(sloc, ctx.getCurrentAST(), null);
    }catch(IOException e){
      throw RuntimeExceptionFactory.io(values.string(e.getMessage()), ctx.getCurrentAST(), null);
    }finally{
      if(out != null){
        try{
          out.close();
        }catch(IOException ioex){
          throw RuntimeExceptionFactory.io(values.string(ioex.getMessage()), ctx.getCurrentAST(), null);
        }
      }
    }
    return;
  }
 
  // REFLECT -- copy in PreludeCompiled
  public void appendToFile(ISourceLocation sloc, IList V, IEvaluatorContext ctx){
    writeFile(sloc, V, true, ctx);
  }
 
  // REFLECT -- copy in PreludeCompiled
  public void appendToFileEnc(ISourceLocation sloc, IString charset, IList V, IEvaluatorContext ctx){
    writeFileEnc(sloc, charset, V, true, ctx);
  }
 
  // REFLECT -- copy in PreludeCompiled
 
  public IList readFileLines(ISourceLocation sloc, IEvaluatorContext ctx){
    sloc = ctx.getHeap().resolveSourceLocation(sloc);
    Reader reader = null;
   
    try {
      Charset detected = ctx.getResolverRegistry().getCharset(sloc.getURI());
      if (detected != null) {
        return readFileLinesEnc(sloc, values.string(detected.name()), ctx);
      }
      reader = ctx.getResolverRegistry().getCharacterReader(sloc.getURI());
      return consumeInputStreamLines(sloc, reader, ctx);
    }catch(MalformedURLException e){
        throw RuntimeExceptionFactory.malformedURI(sloc.toString(), null, null);
    }catch(FileNotFoundException e){
      throw RuntimeExceptionFactory.pathNotFound(sloc, ctx.getCurrentAST(), null);
    }catch(IOException e){
      throw RuntimeExceptionFactory.io(values.string(e.getMessage()), ctx.getCurrentAST(), null);
    } finally {
      if (reader != null) {
        try {
          reader.close();
        } catch (IOException e) {
          // forgot about it
        }
      }
    }
  }
 
  // REFLECT -- copy in PreludeCompiled
  public IList readFileLinesEnc(ISourceLocation sloc, IString charset, IEvaluatorContext ctx){
    sloc = ctx.getHeap().resolveSourceLocation(sloc);
   
    try {
      return consumeInputStreamLines(sloc, ctx.getResolverRegistry().getCharacterReader(sloc.getURI(),charset.getValue()), ctx);
    }catch(MalformedURLException e){
        throw RuntimeExceptionFactory.malformedURI(sloc.toString(), null, null);
    }catch(FileNotFoundException e){
      throw RuntimeExceptionFactory.pathNotFound(sloc, ctx.getCurrentAST(), null);
    }catch(IOException e){
      throw RuntimeExceptionFactory.io(values.string(e.getMessage()), ctx.getCurrentAST(), null);
    }
  }

  // REFLECT -- copy in PreludeCompiled
  private IList consumeInputStreamLines(ISourceLocation sloc,  Reader stream, IEvaluatorContext ctx ) {
    IListWriter w = values.listWriter();
   
    BufferedReader in = null;
    try{
      in = new BufferedReader(stream);
      java.lang.String line;
     
      int i = 0;
//      int offset = sloc.getOffset();
      int beginLine = sloc.hasLineColumn() ? sloc.getBeginLine() : -1;
      int beginColumn = sloc.hasLineColumn() ? sloc.getBeginColumn() : -1;
      int endLine = sloc.hasLineColumn() ? sloc.getEndLine() : -1;
      int endColumn = sloc.hasLineColumn() ? sloc.getEndColumn() : -1;

      do{
        line = in.readLine();
        i++;
        if(line != null){
          if(!sloc.hasOffsetLength()){
            w.append(values.string(line));
          }else{
            if(!sloc.hasLineColumn()){
              endColumn = line.length();
            }
            if(i == beginLine){
              if(i == endLine){
                w.append(values.string(line.substring(beginColumn, Math.min(endColumn, line.length()))));
              }else{
                w.append(values.string(line.substring(beginColumn)));
              }
            }else if(i > beginLine){
              if(i == endLine){
                w.append(values.string(line.substring(0, Math.min(endColumn, line.length()))));
              }
              else if(i < endLine){
                w.append(values.string(line));
              }
            }
          }
        }
      }while(line != null);
    }catch(IOException e){
      throw RuntimeExceptionFactory.io(values.string(e.getMessage()), ctx.getCurrentAST(), null);
    }finally{
      if(in != null){
        try{
          in.close();
        }catch(IOException ioex){
          throw RuntimeExceptionFactory.io(values.string(ioex.getMessage()), ctx.getCurrentAST(), null);
        }
      }
    }

    return w.done();
  }
 
  // REFLECT -- copy in PreludeCompiled
  public IList readFileBytes(ISourceLocation sloc, IEvaluatorContext ctx){
    IListWriter w = values.listWriter();
    sloc = ctx.getHeap().resolveSourceLocation(sloc);
   
    BufferedInputStream in = null;
    try{
      InputStream stream = ctx.getResolverRegistry().getInputStream(sloc.getURI());
      in = new BufferedInputStream(stream);
      int read;
      final int size = 256;
      byte bytes[] = new byte[size];
     
      do{
        read = in.read(bytes);
        for (int i = 0; i < read; i++) {
          w.append(values.integer(bytes[i] & 0xff));
        }
      }while(read != -1);
    }catch(FileNotFoundException e){
      throw RuntimeExceptionFactory.pathNotFound(sloc, ctx.getCurrentAST(), null);
    }catch(IOException e){
      throw RuntimeExceptionFactory.io(values.string(e.getMessage()), ctx.getCurrentAST(), null);
    }finally{
      if(in != null){
        try{
          in.close();
        }catch(IOException ioex){
          throw RuntimeExceptionFactory.io(values.string(ioex.getMessage()), ctx.getCurrentAST(), null);
        }
      }
    }

    return w.done();
  }
 
  public IString createLink(IString title, IString target) {
    return values.string("\uE007["+title.getValue().replaceAll("\\]", "_")+"]("+target.getValue()+")");
  }
 
  /*
   * List
   */
 
  private WeakReference<IList> indexes;

 
 
  /**
   * A mini class to wrap a lessThan function
   */
  private class Less {
    private final ICallableValue less;

    Less(ICallableValue less) {
      this.less = less;
    }

    public boolean less(IValue x, IValue y) {
      return ((IBool) less.call(new Type[] { x.getType(), y.getType() },
          new IValue[] { x, y }, null).getValue()).getValue();
    }
  }
 
  private class Sorting {
    private final IValue[] array;
    private final int size;
    private final Less less;

    private void swap(int i, int j) {
      IValue tmp = array[i];
      array[i] = array[j];
      array[j] = tmp;
    }
   
    public Sorting(IValue[] array, Less less) {
      this.array = array;
      this.size = array.length;
      this.less = less;
    }
   
    /**
     * @throws IllegalArgument if comparator is illegal (i.e., if pivot equals pivot)
     */
    public Sorting sort() {
      if (size == 0) {
        return this;
      }
      if(less.less(array[0], array[0])) {
        throw RuntimeExceptionFactory.illegalArgument(less.less, null, null, "Bad comparator: Did you use less-or-equals instead of less-than?");
      }
      sort(0, size - 1);

      return this;
    }
   
    public Sorting shuffle() {
      for (int i = 0; i < size; i++) {
        swap(i, i + (int) (Math.random() * (size-i)));
      }
      return this;
    }
   
    private void sort(int low, int high) {
      IValue pivot = array[low + (high-low)/2];
      int oldLow = low;
      int oldHigh = high;
     
      while (low < high) {
        for ( ; less.less(array[low], pivot); low++);
        for ( ; less.less(pivot, array[high]); high--);

        if (low <= high) {
          swap(low, high);
          low++;
          high--;
        }
      }
     
      if (oldLow < high)
        sort(oldLow, high);
      if (low < oldHigh)
        sort(low, oldHigh);
    }
  }
 
  public IValue elementAt(IList lst, IInteger index) {
    if(lst.length() == 0)
      throw RuntimeExceptionFactory.emptyList(null, null);
    try {
      int i = index.intValue();
      if(index.intValue() < 0)
        i = i + lst.length();
      return lst.get(i);
    } catch (IndexOutOfBoundsException e){
       throw RuntimeExceptionFactory.indexOutOfBounds(index, null, null);
    }
  }
 
  public IList sort(IList l, IValue cmpv){
    IValue[] tmpArr = new IValue[l.length()];
    for(int i = 0 ; i < l.length() ; i++){
      tmpArr[i] = l.get(i);
    }

    // we randomly swap some elements to make worst case complexity unlikely
    new Sorting(tmpArr, new Less((ICallableValue) cmpv)).shuffle().sort();


    IListWriter writer = values.listWriter();
    writer.append(tmpArr);
    return writer.done();
  }
 
  public IList sort(ISet l, IValue cmpv) {
    IValue[] tmpArr = new IValue[l.size()];
    int i = 0;
   
    // we assume that the set is reasonably randomly ordered, such
    // that the worst case of quicksort is unlikely
    for (IValue elem : l){
      tmpArr[i++] = elem;
    }
   
    new Sorting(tmpArr, new Less((ICallableValue) cmpv)).sort();
   
    IListWriter writer = values.listWriter();
    for(IValue v : tmpArr){
      writer.append(v);
    }
   
    return writer.done();
  }
 
  private IList makeUpTill(int from,int len){
    IListWriter writer = values.listWriter();
    for(int i = from ; i < len; i++){
      writer.append(values.integer(i));
    }
    return writer.done();
  }
 
  public IValue delete(IList lst, IInteger n)
  // @doc{delete -- delete nth element from list}
  {
    try {
      return lst.delete(n.intValue());
    } catch (IndexOutOfBoundsException e){
       throw RuntimeExceptionFactory.indexOutOfBounds(n, null, null);
    }
  }
 
  public IValue domain(IList lst)
  //@doc{domain -- a list of all legal index values for a list}
  {
    ISetWriter w = values.setWriter();
    int len = lst.length();
    for (int i = 0; i < len; i++){
      w.insert(values.integer(i));
    }
    return w.done();
  }
 
  public IValue head(IList lst)
  // @doc{head -- get the first element of a list}
  {
     if(lst.length() > 0){
        return lst.get(0);
     }
    
     throw RuntimeExceptionFactory.emptyList(null, null);
  }

  public IValue head(IList lst, IInteger n)
    throws IndexOutOfBoundsException
  // @doc{head -- get the first n elements of a list}
  {
     try {
        return lst.sublist(0, n.intValue());
     } catch(IndexOutOfBoundsException e){
       IInteger end = values.integer(n.intValue() - 1);
        throw RuntimeExceptionFactory.indexOutOfBounds(end, null, null);
     }
  }

  public IValue getOneFrom(IList lst)
  //@doc{getOneFrom -- get an arbitrary element from a list}
  {
    int n = lst.length();
    if(n > 0){
      return lst.get(random.nextInt(n));
    }
   
    throw RuntimeExceptionFactory.emptyList(null, null);
  }

  public IValue insertAt(IList lst, IInteger n, IValue elm)
    throws IndexOutOfBoundsException
   //@doc{insertAt -- add an element at a specific position in a list}
   {
     IListWriter w = values.listWriter();
    
     int k = n.intValue();
      if(k >= 0 && k <= lst.length()){
        if(k == lst.length()){
          w.insert(elm);
        }
        for(int i = lst.length()-1; i >= 0; i--) {
          w.insert(lst.get(i));
          if(i == k){
            w.insert(elm);
          }
        }
        return w.done();
      }
     
    throw RuntimeExceptionFactory.indexOutOfBounds(n, null, null);
   }
 
  public IValue isEmpty(IList lst)
  //@doc{isEmpty -- is list empty?}
  {
    return values.bool(lst.length() == 0);
  }

  public IValue reverse(IList lst)
  //@doc{reverse -- elements of a list in reverse order}
  {
    return lst.reverse();
  }

  public IValue size(IList lst)
  //@doc{size -- number of elements in a list}
  {
     return values.integer(lst.length());
  }

   public IValue slice(IList lst, IInteger start, IInteger len)
   //@doc{slice -- sublist from start of length len}
   {
    try {
      return lst.sublist(start.intValue(), len.intValue());
    } catch (IndexOutOfBoundsException e){
      IInteger end = values.integer(start.intValue() + len.intValue());
      throw RuntimeExceptionFactory.indexOutOfBounds(end, null, null);
    }
   }

   public IValue tail(IList lst)
   //@doc{tail -- all but the first element of a list}
   {
     try {
       return lst.sublist(1, lst.length()-1);
     } catch (IndexOutOfBoundsException e){
       throw RuntimeExceptionFactory.emptyList(null, null);
     }
   }
  
    public IValue tail(IList lst, IInteger len)
   //@doc{tail -- last n elements of a list}
   {
     int lenVal = len.intValue();
     int lstLen = lst.length();
  
     try {
       return lst.sublist(lstLen - lenVal, lenVal);
     } catch (IndexOutOfBoundsException e){
       IInteger end = values.integer(lenVal - lstLen);
       throw RuntimeExceptionFactory.indexOutOfBounds(end, null, null);
     }
   }
   
  public IValue take(IInteger len, IList lst) {
     //@doc{take -- take n elements of from front of a list}
    int lenVal = len.intValue();
    int lstLen = lst.length();
    if(lenVal >= lstLen){
      return lst;
    } else {
      return lst.sublist(0, lenVal);
    }
  }

  public IValue drop(IInteger len, IList lst) {
     //@doc{drop -- remove n elements of from front of a list}
    int lenVal = len.intValue();
    int lstLen = lst.length();
    if(lenVal >= lstLen){
      return values.list();
    } else {
      return lst.sublist(lenVal, lstLen - lenVal);
    }
  }
 
  public IValue upTill(IInteger ni) {
    //@doc{Returns the list 0..n, this is slightly faster than [0,1..n], since the returned values are shared}
    int n = ni.intValue();
    if(indexes == null || indexes.get() == null) {
      IList l = makeUpTill(0, n);
      indexes = new WeakReference<IList>(l);
      return indexes.get();
    } else {
      IList l = indexes.get(); // strong ref
      if(l == null || n >= l.length()){
        l = makeUpTill(0,n);
        indexes =  new WeakReference<IList>(l);
        return l;
      }
      return l.sublist(0, n);
    }
  }
 
  public IValue prefix(IList lst) {
       //@doc{Return all but the last element of a list}
      int lstLen = lst.length();
      if(lstLen <= 1){
        return values.list();
      } else {
        return lst.sublist(0, lstLen - 1);
      }
    }


  
  public IValue takeOneFrom(IList lst)
  //@doc{takeOneFrom -- remove an arbitrary element from a list, returns the element and the modified list}
  {
     int n = lst.length();
    
     if(n > 0){
         int k = random.nextInt(n);
         IValue pick = lst.get(0);
         IListWriter w = values.listWriter();
   
        for(int i = n - 1; i >= 0; i--) {
           if(i == k){
             pick = lst.get(i);
           } else {
              w.insert(lst.get(i));
           }
        }
        return values.tuple(pick, w.done());
       }
    
     throw RuntimeExceptionFactory.emptyList(null, null);
  }
 
  private class IValueWrap {
    private final IValue ori;
    public IValueWrap(IValue ori) {
      this.ori = ori;
    }
    @Override
    public int hashCode() {
      return ori.hashCode();
    }
    @Override
    public boolean equals(Object obj) {
      if (obj == null) {
        return false;
      }
      if (obj instanceof IValueWrap) {
        return ori.isEqual(((IValueWrap)obj).ori);
      }
      return false;
    }
    public IValue getValue() {
      return ori;
    }
  }
 
  public IMap toMap(IList lst)
  // @doc{toMap -- convert a list of tuples to a map; first value in old tuples is associated with a set of second values}
  {
    Map<IValueWrap,ISetWriter> hm = new HashMap<IValueWrap,ISetWriter>();

    for (IValue v : lst) {
      ITuple t = (ITuple) v;
      IValueWrap key = new IValueWrap(t.get(0));
      IValue val = t.get(1);
      ISetWriter wValSet = hm.get(key);
      if(wValSet == null){
        wValSet = values.setWriter();
        hm.put(key, wValSet);
      }
      wValSet.insert(val);
    }
   
    IMapWriter w = values.mapWriter();
    for(IValueWrap v : hm.keySet()){
      w.put(v.getValue(), hm.get(v).done());
    }
    return w.done();
  }
 
  public IValue toMapUnique(IList lst)
  //@doc{toMapUnique -- convert a list of tuples to a map; result should be a map}
  {
     if(lst.length() == 0){
        return values.mapWriter().done();
     }
   
     IMapWriter w = values.mapWriter();
     Set<IValueWrap> seenKeys = new HashSet<IValueWrap>();
     for(IValue v : lst){
       ITuple t = (ITuple) v;
       IValueWrap key = new IValueWrap(t.get(0));
       if(seenKeys.contains(key))
        throw RuntimeExceptionFactory.MultipleKey(key.getValue(), null, null);
       seenKeys.add(key);
       w.put(key.getValue(), t.get(1));
     }
     return w.done();
  }

  public IValue toSet(IList lst)
  //@doc{toSet -- convert a list to a set}
  {
    ISetWriter w = values.setWriter();
   
    for(IValue v : lst){
      w.insert(v);
    }
   
    return w.done();
  }

  public IValue toString(IList lst)
  //@doc{toString -- convert a list to a string}
  {
    return values.string(lst.toString());
  }

  public IValue itoString(IList lst)
  //@doc{toString -- convert a list to a string}
  {
    return itoStringValue(lst);
  }

  private IValue itoStringValue(IValue T)
  //@doc{toString -- convert a node to a string}
  {
    StandardTextWriter w = new StandardTextWriter(true, 2);
    StringWriter result = new StringWriter();
    try {
      w.write(T, result);
      return values.string(result.toString());
    }
    catch (IOException e) {
      RuntimeExceptionFactory.io(values.string("Could not convert list to indented value"), null, null);
      throw new RuntimeException("previous command should always throw");
    }
  }
 
  /*
   * Map
   */
 
  public IValue domain(IMap M)
  //@doc{domain -- return the domain (keys) of a map}

  {
    ISetWriter w = values.setWriter();
    Iterator<Entry<IValue,IValue>> iter = M.entryIterator();
    while (iter.hasNext()) {
      Entry<IValue,IValue> entry = iter.next();
      w.insert(entry.getKey());
    }
    return w.done();
  }

  public IValue getOneFrom(IMap m
  //@doc{getOneFrom -- return arbitrary key of a map}
  {
     int i = 0;
     int sz = m.size();
     if(sz == 0){
        throw RuntimeExceptionFactory.emptyMap(null, null);
     }
     int k = random.nextInt(sz);
     Iterator<Entry<IValue,IValue>> iter = m.entryIterator();
   
     while(iter.hasNext()){
        if(i == k){
          return (iter.next()).getKey();
        }
        iter.next();
        i++;
     }
     return null;
  }
 
  public IValue invertUnique(IMap M)
  //@doc{invertUnique -- return map with key and value inverted; values are unique}
  {
    IMapWriter w = values.mapWriter();
    HashSet<IValue> seenValues = new HashSet<IValue>();
    Iterator<Entry<IValue,IValue>> iter = M.entryIterator();
    while (iter.hasNext()) {
      Entry<IValue,IValue> entry = iter.next();
      IValue key = entry.getKey();
      IValue val = entry.getValue();
      if(seenValues.contains(val))
          throw RuntimeExceptionFactory.MultipleKey(val, null, null);
      seenValues.add(val);
      w.put(val, key);
    }
    return w.done();
  }
 
  public IValue invert(IMap M)
  //@doc{invert -- return map with key and value inverted; values are not unique and are collected in a set}
  {
    HashMap<IValue,ISetWriter> hm = new HashMap<IValue,ISetWriter>();
    Iterator<Entry<IValue,IValue>> iter = M.entryIterator();
    while (iter.hasNext()) {
      Entry<IValue,IValue> entry = iter.next();
      IValue key = entry.getKey();
      IValue val = entry.getValue();
      ISetWriter wKeySet = hm.get(val);
      if(wKeySet == null){
        wKeySet = values.setWriter();
        hm.put(val, wKeySet);
      }
      wKeySet.insert(key);
    }
   
    IMapWriter w = values.mapWriter();
   
    iter = M.entryIterator();
    for(IValue v : hm.keySet()){
      w.put(v, hm.get(v).done());
    }
    return w.done();
  }
 
  public IValue isEmpty(IMap M)
  //@doc{isEmpty -- is map empty?}
  {
    return values.bool(M.size() == 0);
  }

  public IValue range(IMap M)
  //@doc{range -- return the range (values) of a map}
  {
    ISetWriter w = values.setWriter();
    Iterator<Entry<IValue,IValue>> iter = M.entryIterator();
    while (iter.hasNext()) {
      Entry<IValue,IValue> entry = iter.next();
      w.insert(entry.getValue());
    }
    return w.done();
  }

  public IValue size(IMap M)
  {
    return values.integer(M.size());
  }

  public IValue toList(IMap M)
  //@doc{toList -- convert a map to a list}
  {
    IListWriter w = values.listWriter();
    Iterator<Entry<IValue,IValue>> iter = M.entryIterator();
    while (iter.hasNext()) {
      Entry<IValue,IValue> entry = iter.next();
      w.insert(values.tuple(entry.getKey(), entry.getValue()));
    }
    return w.done();
  }

  public IValue toRel(IMap M)
  //@doc{toRel -- convert a map to a relation}
  {
    ISetWriter w = values.setWriter();
    Iterator<Entry<IValue,IValue>> iter = M.entryIterator();
    while (iter.hasNext()) {
      Entry<IValue,IValue> entry = iter.next();
      w.insert(values.tuple(entry.getKey(), entry.getValue()));
    }
    return w.done();
  }
   
  public IValue toString(IMap M)
  {
    return values.string(M.toString());
  }

  public IValue itoString(IMap M)
  {
    return itoStringValue(M);
  }
  /*
   * Node
   */

  public IValue arity(INode T)
  //@doc{arity -- number of children of a node}
  {
     return values.integer(T.arity());
  }

  public IValue getChildren(INode T)
  //@doc{getChildren -- get the children of a node}
  {
    IListWriter w = values.listWriter();
   
    for(IValue v : T.getChildren()){
      w.append(v);
    }
    return w.done();
  }
 
  public IValue getKeywordParameters(INode T)
  //@doc{getChildren -- get the children of a node}
  {
    IMapWriter w = values.mapWriter();
   
    if (T.mayHaveKeywordParameters()) {
      for(Entry<String, IValue> e : T.asWithKeywordParameters().getParameters().entrySet()){
        w.put(values.string(e.getKey()), e.getValue());
      }
    }
   
    return w.done();
  }

  public IValue getName(INode T)
  //@doc{getName -- get the function name of a node}
  {
    return values.string(T.getName());
  }

  public IValue makeNode(IString N, IList V, IMap kwParams)
  //@doc{makeNode -- create a node given its function name and arguments}
  {
      IList argList = V;
    IValue args[] = new IValue[argList.length()];
    int i = 0;
    for(IValue v : argList){
      args[i++] = v;
    }
   
    Map<String,IValue> map = new HashMap<>();
    for (IValue key : kwParams) {
      map.put(((IString) key).getValue(), kwParams.get(key));
    }
   
    return values.node(N.getValue(), args, map);
  }
 
  public IValue readATermFromFile(IString fileName){
  //@doc{readATermFromFile -- read an ATerm from a named file}
    ATermReader atr = new ATermReader();
    try {
      FileInputStream stream = new FileInputStream(fileName.getValue());
      IValue result = atr.read(values, stream);
      stream.close();
      return result;
    } catch (FactTypeUseException e) {
      e.printStackTrace();
      throw RuntimeExceptionFactory.io(values.string(e.getMessage()), null, null);
    } catch (IOException e) {
      e.printStackTrace();
      throw RuntimeExceptionFactory.io(values.string(e.getMessage()), null, null);

    }
  }
 
  public IValue toString(INode T)
  //@doc{toString -- convert a node to a string}
  {
    return values.string(T.toString());

  }

  public IValue itoString(INode T)
  //@doc{toString -- convert a node to a string}
  {
    return itoStringValue(T);
  }
 
  public IMap getAnnotations(INode node) {
    java.util.Map<java.lang.String,IValue> map = node.asAnnotatable().getAnnotations();
    IMapWriter w = values.mapWriter();
   
    for (Entry<java.lang.String,IValue> entry : map.entrySet()) {
      w.put(values.string(entry.getKey()), entry.getValue());
    }
   
    return w.done();
  }
 
  public INode setAnnotations(INode node, IMap annotations) {
    java.util.Map<java.lang.String,IValue> map = new HashMap<java.lang.String,IValue>();
   
    for (IValue key : annotations) {
      IValue value = annotations.get(key);
      map.put(((IString) key).getValue(), value);
    }
   
    return node.asAnnotatable().setAnnotations(map);
  }
 
  public INode delAnnotations(INode node) {
    return node.asAnnotatable().removeAnnotations();
  }
 
  public INode delAnnotation(INode node, IString label) {
    return node.asAnnotatable().removeAnnotation(label.getValue());
  }
 
  /*
   * ParseTree
   */
 
  protected final TypeReifier tr;

  // REFLECT -- copy in PreludeCompiled
  public IValue parse(IValue start, ISourceLocation input, IEvaluatorContext ctx) {
    return parse(start, values.mapWriter().done(), input, ctx);
  }
 
  // REFLECT -- copy in PreludeCompiled
  public IValue parse(IValue start, IMap robust, ISourceLocation input, IEvaluatorContext ctx) {
    Type reified = start.getType();
    IConstructor startSort = checkPreconditions(start, reified);
   
    try {
      IConstructor pt = ctx.getEvaluator().parseObject(ctx.getEvaluator().getMonitor(), startSort, robust, input.getURI());

      if (TreeAdapter.isAppl(pt)) {
        if (SymbolAdapter.isStart(TreeAdapter.getType(pt))) {
          pt = (IConstructor) TreeAdapter.getArgs(pt).get(1);
        }
      }
      return pt;
    }
    catch (ParseError pe) {
      ISourceLocation errorLoc = values.sourceLocation(pe.getLocation(), pe.getOffset(), pe.getLength(), pe.getBeginLine() + 1, pe.getEndLine() + 1, pe.getBeginColumn(), pe.getEndColumn());
      throw RuntimeExceptionFactory.parseError(errorLoc, ctx.getCurrentAST(), ctx.getStackTrace());
    }
    catch (UndeclaredNonTerminalException e){
      throw new UndeclaredNonTerminal(e.getName(), e.getClassName(), ctx.getCurrentAST());
    }
  }

  public IValue parse(IValue start, IString input, IEvaluatorContext ctx) {
    return parse(start, values.mapWriter().done(), input, ctx);
  }
 
  public IValue parse(IValue start, IMap robust, IString input, IEvaluatorContext ctx) {
    Type reified = start.getType();
    IConstructor startSort = checkPreconditions(start, reified);
    try {
      IConstructor pt = ctx.getEvaluator().parseObject(ctx.getEvaluator().getMonitor(), startSort, robust, input.getValue());

      if (TreeAdapter.isAppl(pt)) {
        if (SymbolAdapter.isStart(TreeAdapter.getType(pt))) {
          pt = (IConstructor) TreeAdapter.getArgs(pt).get(1);
        }
      }

      return pt;
    }
    catch (ParseError pe) {
      ISourceLocation errorLoc = values.sourceLocation(pe.getLocation(), pe.getOffset(), pe.getLength(), pe.getBeginLine() + 1, pe.getEndLine() + 1, pe.getBeginColumn(), pe.getEndColumn());
      throw RuntimeExceptionFactory.parseError(errorLoc, null, null);
    }
    catch (UndeclaredNonTerminalException e){
      throw new UndeclaredNonTerminal(e.getName(), e.getClassName(), ctx.getCurrentAST());
    }
  }
 
  public IValue parse(IValue start, IString input, ISourceLocation loc, IEvaluatorContext ctx) {
    return parse(start, values.mapWriter().done(), input, loc, ctx);
  }
 
  public IValue parse(IValue start, IMap robust, IString input, ISourceLocation loc, IEvaluatorContext ctx) {
    Type reified = start.getType();
    IConstructor startSort = checkPreconditions(start, reified);
    try {
      IConstructor pt = ctx.getEvaluator().parseObject(ctx.getEvaluator().getMonitor(), startSort, robust, input.getValue(), loc);

      if (TreeAdapter.isAppl(pt)) {
        if (SymbolAdapter.isStart(TreeAdapter.getType(pt))) {
          pt = (IConstructor) TreeAdapter.getArgs(pt).get(1);
        }
      }

      return pt;
    }
    catch (ParseError pe) {
      ISourceLocation errorLoc = values.sourceLocation(pe.getLocation(), pe.getOffset(), pe.getLength(), pe.getBeginLine(), pe.getEndLine(), pe.getBeginColumn(), pe.getEndColumn());
      throw RuntimeExceptionFactory.parseError(errorLoc, null, null);
    }
    catch (UndeclaredNonTerminalException e){
      throw new UndeclaredNonTerminal(e.getName(), e.getClassName(), ctx.getCurrentAST());
    }
  }
 
  public IString saveParser(ISourceLocation outFile, IEvaluatorContext ctx) {
   
    IGTD<IConstructor, IConstructor, ISourceLocation> parser = org.rascalmpl.semantics.dynamic.Import.getParser(ctx.getEvaluator(), (ModuleEnvironment) ctx.getCurrentEnvt().getRoot(), URIUtil.invalidURI(), false);
    Class<IGTD<IConstructor, IConstructor, ISourceLocation>> parserClass = (Class<IGTD<IConstructor, IConstructor, ISourceLocation>>) parser.getClass();
   
   
    try(OutputStream outStream = ctx.getResolverRegistry().getOutputStream(outFile.getURI(), false)) {
      ctx.getEvaluator().getParserGenerator().saveToJar(parserClass, outStream);
    } catch (IOException e) {
      throw RuntimeExceptionFactory.io(ctx.getValueFactory().string("Unable to save to output file '" + outFile.getURI() + "'"), ctx.getCurrentAST(), ctx.getStackTrace());
    }
    return ctx.getValueFactory().string(parserClass.getName());

  }
  public IString unparse(IConstructor tree) {
    return values.string(TreeAdapter.yield(tree));
  }
 
  // REFLECT -- copy in PreludeCompiled
  protected IConstructor makeConstructor(Type returnType, String name, IEvaluatorContext ctx,  IValue ...args) {
    IValue value = ctx.getEvaluator().call(returnType.getName(), name, args);
    Type type = value.getType();
    if (type.isAbstractData()) {
      return (IConstructor)value;
    }
    throw RuntimeExceptionFactory.implodeError("Calling of constructor " + name + " did not return a constructor", null, null);
  }
 
  private java.lang.String unescapedConsName(IConstructor tree) {
    java.lang.String x = TreeAdapter.getConstructorName(tree);
    if (x != null) {
      x = x.replaceAll("\\\\", "");
    }
    return x;
  }

  private Set<Type> findConstructors(Type type, java.lang.String constructorName, int arity,  TypeStore store) {
    Set<Type> constructors = new HashSet<Type>();
   
    for (Type constructor : store.lookupConstructor(type, constructorName)) {
      if (constructor.getArity() == arity)
        constructors.add(constructor);
    }
   
    return constructors;
  }

 
//  private Type findConstructor(Type type, java.lang.String constructorName, int arity,  TypeStore store) {
//    for (Type candidate: store.lookupConstructor(type, constructorName)) {
//      // It finds the first with suitable arity, so this is inaccurate
//      // if there are overloaded constructors with the same arity
//      if (arity == candidate.getArity()) {
//        return candidate;
//      }
//    }
//    return null;
//  }

  // REFLECT -- copy in PreludeCompiled
  public IValue implode(IValue reifiedType, IConstructor tree, IEvaluatorContext ctx) {
    TypeStore store = new TypeStore();
    Type type = tr.valueToType((IConstructor) reifiedType, store);
    try {
      IValue result = implode(store, type, tree, false, ctx);
      if (isUntypedNodeType(type) && !type.isTop() && (TreeAdapter.isList(tree) || TreeAdapter.isOpt(tree))) {
        // Ensure the result is actually a node, even though
        // the tree given to implode is a list.
        result = values.node("", result);
      }
      return result;
    }
    catch (Backtrack b) {
      throw b.exception;
    }
  }

  @SuppressWarnings("serial")
  protected static class Backtrack extends RuntimeException {
    Throw exception;
    public Backtrack(Throw exception) {
      this.exception = exception;
    }
    @Override
    public synchronized Throwable fillInStackTrace() {
      return this;
    }
  }
 
  private IValue[] implodeArgs(TypeStore store, Type type, IList args, IEvaluatorContext ctx) {
    int length = args.length();
    IValue implodedArgs[] = new IValue[length];
    for (int i = 0; i < length; i++) {
      Type argType = isUntypedNodeType(type) ? type : type.getFieldType(i);
      implodedArgs[i] = implode(store, argType, (IConstructor)args.get(i), false, ctx);
    }
    return implodedArgs;
  }
 
 
  protected IValue implode(TypeStore store, Type type, IConstructor tree, boolean splicing, IEvaluatorContext ctx) {

    // always yield if expected type is str, except if regular
    if (type.isString() && !splicing) {
      return values.string(TreeAdapter.yield(tree));
    }

    if (SymbolAdapter.isStartSort(TreeAdapter.getType(tree))) {
      IList args = TreeAdapter.getArgs(tree);
      IConstructor before = (IConstructor) args.get(0);
      IConstructor ast = (IConstructor) args.get(1);
      IConstructor after = (IConstructor) args.get(2);
      IValue result = implode(store, type, ast, splicing, ctx);
      if (result.getType().isNode()) {
        IMapWriter comments = values.mapWriter();
        comments.putAll((IMap)((INode)result).asAnnotatable().getAnnotation("comments"));
        IList beforeComments = extractComments(before);
        if (!beforeComments.isEmpty()) {
          comments.put(values.integer(-1), beforeComments);
        }
        IList afterComments = extractComments(after);
        if (!afterComments.isEmpty()) {
          comments.put(values.integer(((INode)result).arity()), afterComments);
        }
        result = ((INode)result).asAnnotatable().setAnnotation("comments", comments.done());
      }
      return result;
    }
   
    if (TreeAdapter.isLexical(tree)) {
      java.lang.String constructorName = unescapedConsName(tree);
      java.lang.String yield = TreeAdapter.yield(tree);
      if (constructorName != null) {
        // make a single argument constructor  with yield as argument
        // if there is a singleton constructor with a str argument
        if (!type.isAbstractData() && !isUntypedNodeType(type)) {
          throw RuntimeExceptionFactory.illegalArgument(tree, null, null, "Constructor (" + constructorName + ") should match with abstract data type and not with " + type);
        }
       
        if (isUntypedNodeType(type)) {
          return values.node(constructorName, values.string(yield));
        }
       
        Set<Type> conses = findConstructors(type, constructorName, 1, store);
        Iterator<Type> iter = conses.iterator();
        while (iter.hasNext()) {
          try {
            @SuppressWarnings("unused")
            Type cons = iter.next();
            ISourceLocation loc = TreeAdapter.getLocation(tree);
            IConstructor ast = makeConstructor(type, constructorName, ctx, values.string(yield));
            return ast.asAnnotatable().setAnnotation("location", loc);
          }
          catch (Backtrack b) {
            continue;
          }
        }
        throw new Backtrack(RuntimeExceptionFactory.illegalArgument(tree, null, null, "Cannot find a constructor " + type));
      }
      if (type.isInteger()) {
        return values.integer(yield);
      }
      if (type.isReal()) {
        return values.real(yield);
      }
      if (type.isBool()) {
        if (yield.equals("true")) {
          return values.bool(true);
        }
        if (yield.equals("false")) {
          return values.bool(false);
        }
        throw new Backtrack(RuntimeExceptionFactory.illegalArgument(tree, null, null, "Bool type does not match with " + yield));
      }
      if (type.isString() || isUntypedNodeType(type)) {
        // NB: in "node space" all lexicals become strings
        return values.string(yield);
      }
     
      throw RuntimeExceptionFactory.illegalArgument(tree, null, null, "Missing lexical constructor");
    }
   
    //Set implementation added here by Jurgen at 19/07/12 16:45
    if (TreeAdapter.isList(tree)) {
      if (type.isList() || splicing || isUntypedNodeType(type)) {
        // if in node space, we also make a list;
        // NB: this breaks type safety if the top-level tree
        // is itself a list.
       
        Type elementType = type;
        if (!splicing && !isUntypedNodeType(type)) {
          elementType = type.getElementType();
        }
        IListWriter w = values.listWriter();
        for (IValue arg: TreeAdapter.getListASTArgs(tree)) {
          w.append(implode(store, elementType, (IConstructor) arg, false, ctx));
        }
        return w.done();
      }
      else if (type.isSet()) {
        Type elementType = splicing ? type : type.getElementType();
        ISetWriter w = values.setWriter();
        for (IValue arg: TreeAdapter.getListASTArgs(tree)) {
          w.insert(implode(store, elementType, (IConstructor) arg, false, ctx));
        }
        return w.done();
      }
      else {
        throw new Backtrack(RuntimeExceptionFactory.illegalArgument(tree, null, null, "Cannot match list with " + type));
      }
    }
    //Changes end here
   
    if (TreeAdapter.isOpt(tree) && type.isBool()) {
      IList args = TreeAdapter.getArgs(tree);
      if (args.isEmpty()) {
        return values.bool(false);
      }
      return values.bool(true);
    }
   
    if (TreeAdapter.isOpt(tree)) {
      if (!type.isList() && !isUntypedNodeType(type)) {
        throw new Backtrack(RuntimeExceptionFactory.illegalArgument(tree, null, null, "Optional should match with a list and not " + type));
      }
      Type elementType = isUntypedNodeType(type) ? type : type.getElementType();
      IListWriter w = values.listWriter();
      for (IValue arg: TreeAdapter.getASTArgs(tree)) {
        IValue implodedArg = implode(store, elementType, (IConstructor) arg, true, ctx);
        if (implodedArg instanceof IList) {
          // splicing
          for (IValue nextArg: (IList)implodedArg) {
            w.append(nextArg);
          }
        }
        else {
          w.append(implodedArg);
        }
        // opts should have one argument (if any at all)
        break;
      }
      return w.done();
    }
   
    if (TreeAdapter.isAmb(tree)) {
      if (!type.isSet()) {
        throw new Backtrack(RuntimeExceptionFactory.illegalArgument(tree, null, null, "Ambiguous node should match with set and not " + type));
      }
      Type elementType = type.getElementType();
      ISetWriter w = values.setWriter();
      for (IValue arg: TreeAdapter.getAlternatives(tree)) {
        w.insert(implode(store, elementType, (IConstructor) arg, false, ctx));
      }
      return w.done();
    }
   
    if (ProductionAdapter.hasAttribute(TreeAdapter.getProduction(tree), Factory.Attribute_Bracket)) {
      return implode(store, type, (IConstructor) TreeAdapter.getASTArgs(tree).get(0), false, ctx);
    }
   
    if (TreeAdapter.isAppl(tree)) {
      IList args = TreeAdapter.getASTArgs(tree);
     
      int j = 0;
      IMapWriter cw = values.mapWriter();
      IListWriter aw = values.listWriter();
      for (IValue kid : TreeAdapter.getArgs(tree)) {
        if (TreeAdapter.isLayout((IConstructor) kid)) {
          IList cts = extractComments((IConstructor) kid);
          if (!cts.isEmpty()) {
            cw.put(values.integer(j), cts);
          }
          j++;
        }
        else if (!TreeAdapter.isLiteral((IConstructor) kid) &&
            !TreeAdapter.isCILiteral((IConstructor) kid) &&
            !TreeAdapter.isEmpty((IConstructor) kid)) {
          aw.append(kid);
        }
      }
      args = aw.done();
      int length = args.length();
      IMap comments = cw.done();
     
//      // this could be optimized.
//      i = 0;
//      int length = args.length();
//      while (i < length) {
//        if (TreeAdapter.isEmpty((IConstructor) args.get(i))) {
//          length--;
//          args = args.delete(i);
//        }
//        else {
//          i++;
//        }
//      }
     
     
      java.lang.String constructorName = unescapedConsName(tree);     
     
      if (constructorName == null) {
        if (length == 1) {
          // jump over injection
          return implode(store, type, (IConstructor) args.get(0), splicing, ctx);
        }
       
       
        // make a tuple if we're in node space
        if (isUntypedNodeType(type)) {
          return values.tuple(implodeArgs(store, type, args, ctx));
        }

        if (!type.isTuple()) {
          throw new Backtrack(RuntimeExceptionFactory.illegalArgument(tree, null, null, "Constructor does not match with " + type));
        }
       
        if (length != type.getArity()) {
          throw new Backtrack(RuntimeExceptionFactory.arityMismatch(type.getArity(), length, null, null));
        }

        return values.tuple(implodeArgs(store, type, args, ctx));
      }
     
      // if in node space, make untyped nodes
      if (isUntypedNodeType(type)) {
        INode ast = values.node(constructorName, implodeArgs(store, type, args, ctx));
        return ast.asAnnotatable().setAnnotation("location", TreeAdapter.getLocation(tree)).asAnnotatable().setAnnotation("comments", comments);
      }
     
      // make a typed constructor
      if (!type.isAbstractData()) {
        throw new Backtrack(RuntimeExceptionFactory.illegalArgument(tree, null, null, "Constructor (" + constructorName + ") should match with abstract data type and not with " + type));
      }

      Set<Type> conses = findConstructors(type, constructorName, length, store);
      Iterator<Type> iter = conses.iterator();
      while (iter.hasNext()) {
        try {
          Type cons = iter.next();
          ISourceLocation loc = TreeAdapter.getLocation(tree);
          IValue[] implodedArgs = implodeArgs(store, cons, args, ctx);
          IConstructor ast = makeConstructor(type, constructorName, ctx, implodedArgs);
          return ast.asAnnotatable().setAnnotation("location", loc).asAnnotatable().setAnnotation("comments", comments);
        }
        catch (Backtrack b) {
          continue;
        }
      }
     
    }
   
    throw new Backtrack(RuntimeExceptionFactory.illegalArgument(tree, null, null,
        "Cannot find a constructor for " + type));
  }
 
  private IList extractComments(IConstructor layout) {
    final IListWriter comments = values.listWriter();
    TreeVisitor<RuntimeException> visitor = new TreeVisitor<RuntimeException>() {

      @Override
      public IConstructor visitTreeAppl(IConstructor arg)
           {
        if (TreeAdapter.isComment(arg)) {
          comments.append(values.string(TreeAdapter.yield(arg)));
        }
        else {
          for (IValue t: TreeAdapter.getArgs(arg)) {
            t.accept(this);
          }
        }
        return arg;
      }

      @Override
      public IConstructor visitTreeAmb(IConstructor arg)
           {
        return arg;
      }

      @Override
      public IConstructor visitTreeChar(IConstructor arg)
           {
        return arg;
      }

      @Override
      public IConstructor visitTreeCycle(IConstructor arg)
           {
        return arg;
      }
     
    };
   
    layout.accept(visitor);
    return comments.done();
  }

  protected boolean isUntypedNodeType(Type type) {
    return (type.isNode() && !type.isConstructor() && !type.isAbstractData())
        || type.isTop();
  }
 
 
 
 
  private static IConstructor checkPreconditions(IValue start, Type reified) {
    if (!(reified instanceof ReifiedType)) {
       throw RuntimeExceptionFactory.illegalArgument(start, null, null, "A reified type is required instead of " + reified);
    }
   
    Type nt = reified.getTypeParameters().getFieldType(0);
   
    if (!(nt instanceof NonTerminalType)) {
      throw RuntimeExceptionFactory.illegalArgument(start, null, null, "A non-terminal type is required instead of  " + nt);
    }
   
    IConstructor symbol = ((NonTerminalType) nt).getSymbol();
   
    return symbol;
  }
 
  /*
   * Rational
   */

  public IValue numerator(IRational n)
  {
    return n.numerator();
  }

  public IValue denominator(IRational n)
  {
    return n.denominator();
  }

  public IValue remainder(IRational n)
  {
    return n.remainder();
  }
 
  /*
   * Relation
   */
 
  /*
   * Set
   */
  public IValue getOneFrom(ISet st)
  // @doc{getOneFrom -- pick a random element from a set}
  {
    int sz = st.size();

    if (sz == 0) {
      throw RuntimeExceptionFactory.emptySet(null, null);
    }
    int k = random.nextInt(sz);
    int i = 0;

    for (IValue v : st) {
      if (i == k) {
        return v;
      }
      i++;
    }
   
    throw RuntimeExceptionFactory.emptySet(null, null);
  }

  public IValue isEmpty(ISet st)
  //@doc{isEmpty -- is set empty?}
  {
    return values.bool(st.size() == 0);
  }
 
  public IValue size(ISet st)
  // @doc{size -- number of elements in a set}
  {
    return values.integer(st.size());
  }
 
  public IMap index(ISet s) {
    Map<IValue, ISetWriter> map = new HashMap<IValue, ISetWriter>(s.size());
   
    for (IValue t : s) {
      ITuple tuple = (ITuple) t;
      IValue key = tuple.get(0);
      IValue value = tuple.get(1);
     
      ISetWriter writer = map.get(key);
      if (writer == null) {
        writer = values.setWriter();
        map.put(key, writer);
      }
      writer.insert(value);
    }
   
    IMapWriter mapWriter = values.mapWriter();
    for (IValue key : map.keySet()) {
      mapWriter.put(key, map.get(key).done());
    }
   
    return mapWriter.done();
  }
 
  public IMap index(IList s) {
    Map<IValue, ISetWriter> map = new HashMap<IValue, ISetWriter>(s.length());
   
    for (IValue t : s) {
      ITuple tuple = (ITuple) t;
      IValue key = tuple.get(0);
      IValue value = tuple.get(1);
     
      ISetWriter writer = map.get(key);
      if (writer == null) {
        writer = values.setWriter();
        map.put(key, writer);
      }
      writer.insert(value);
    }
   
    IMapWriter mapWriter = values.mapWriter();
    for (IValue key : map.keySet()) {
      mapWriter.put(key, map.get(key).done());
    }
   
    return mapWriter.done();
  }

  public IValue takeOneFrom(ISet st)
  // @doc{takeOneFrom -- remove an arbitrary element from a set,
  //      returns the element and the modified set}
  {
    int n = st.size();

    if (n > 0) {
      int i = 0;
      int k = random.nextInt(n);
      IValue pick = null;
      ISetWriter w = values.setWriter();

      for (IValue v : st) {
        if (i == k) {
          pick = v;
        } else {
          w.insert(v);
        }
        i++;
      }
      return values.tuple(pick, w.done());
    }
    throw RuntimeExceptionFactory.emptySet(null, null);
  }

  public IValue toList(ISet st)
  // @doc{toList -- convert a set to a list}
  {
    IListWriter w = values.listWriter();

    for (IValue v : st) {
      w.insert(v);
    }

    return w.done();
  }

  public IValue toMap(ISet st)
  // @doc{toMap -- convert a set of tuples to a map; value in old map is associated with a set of keys in old map}
  {
    Map<IValueWrap,ISetWriter> hm = new HashMap<IValueWrap,ISetWriter>();

    for (IValue v : st) {
      ITuple t = (ITuple) v;
      IValueWrap key = new IValueWrap(t.get(0));
      IValue val = t.get(1);
      ISetWriter wValSet = hm.get(key);
      if(wValSet == null){
        wValSet = values.setWriter();
        hm.put(key, wValSet);
      }
      wValSet.insert(val);
    }
   
    IMapWriter w = values.mapWriter();
    for(IValueWrap v : hm.keySet()){
      w.put(v.getValue(), hm.get(v).done());
    }
    return w.done();
  }
 
  public IValue toMapUnique(ISet st)
  // @doc{toMapUnique -- convert a set of tuples to a map; keys are unique}
  {
    IMapWriter w = values.mapWriter();
    HashSet<IValueWrap> seenKeys = new HashSet<IValueWrap>();

    for (IValue v : st) {
      ITuple t = (ITuple) v;
      IValueWrap key = new IValueWrap(t.get(0));
      IValue val = t.get(1);
      if(seenKeys.contains(key)) {
        throw RuntimeExceptionFactory.MultipleKey(key.getValue(), null, null);
      }
      seenKeys.add(key);
      w.put(key.getValue(), val);
    }
    return w.done();
  }

  public IValue toString(ISet st)
  // @doc{toString -- convert a set to a string}
  {
    return values.string(st.toString());
  }

  public IValue itoString(ISet st)
  {
    return itoStringValue(st);
  }
 
  /*
   * String
   */
 
  public IBool isValidCharacter(IInteger i) {
    return values.bool(Character.isValidCodePoint(i.intValue()));
  }
 
  public IValue stringChar(IInteger i) {
    int intValue = i.intValue();
    if (Character.isValidCodePoint(intValue)) {
      return values.string(intValue);
    }
    else {
      throw RuntimeExceptionFactory.illegalArgument(i, null, null);
    }
  }
 
  public IValue stringChars(IList lst){
    int[] chars = new int[lst.length()];
   
    for (int i = 0; i < lst.length(); i ++) {
      chars[i] = ((IInteger) lst.get(i)).intValue();
      if (!Character.isValidCodePoint(chars[i])) {
        throw RuntimeExceptionFactory.illegalArgument(values.integer(chars[i]), null, null);
      }
    }
   
    return values.string(chars);
  }
 
  public IValue charAt(IString s, IInteger i) throws IndexOutOfBoundsException
  //@doc{charAt -- return the character at position i in string s.}
  {
    try {
    return values.integer(s.charAt(i.intValue()));
    }
    catch (IndexOutOfBoundsException e) {
      throw RuntimeExceptionFactory.indexOutOfBounds(i, null, null);
    }
  }

  public IValue endsWith(IString s, IString suffix)
  //@doc{endWith -- returns true if string s ends with given string suffix.}
  {
    return values.bool(s.getValue().endsWith(suffix.getValue()));
  }
 
  public IString trim(IString s) {
    return values.string(s.getValue().trim());
  }
 
  public IString squeeze(IString src, IString charSet) {
    //@{http://commons.apache.org/lang/api-2.6/index.html?org/apache/commons/lang/text/package-summary.html}
    String s = CharSetUtils.squeeze(src.getValue(), charSet.getValue());
    return values.string(s);
  }
 
  public IString capitalize(IString src) {
    StringBuilder result = new StringBuilder(src.length());
    boolean lastWhitespace= true;
    for (int cIndex =0; cIndex < src.length(); cIndex ++) {
      int cp = src.charAt(cIndex);
      if (Character.isWhitespace(cp)) {
        lastWhitespace = true;
      }
      else if (lastWhitespace) {
        lastWhitespace = false;
        cp = Character.toUpperCase(cp);
      }
      result.appendCodePoint(cp);
    }
    return values.string(result.toString());
  }
 
  public IString uncapitalize(IString src) {
    StringBuilder result = new StringBuilder(src.length());
    boolean lastWhitespace= true;
    for (int cIndex =0; cIndex < src.length(); cIndex ++) {
      int cp = src.charAt(cIndex);
      if (Character.isWhitespace(cp)) {
        lastWhitespace = true;
      }
      else if (lastWhitespace) {
        lastWhitespace = false;
        cp = Character.toLowerCase(cp);
      }
      result.appendCodePoint(cp);
    }
    return values.string(result.toString());
  }
 
  public IList split(IString sep, IString src) {
    String[] lst = src.getValue().split(Pattern.quote(sep.getValue()));
    IListWriter lw = values.listWriter();
    for (String s: lst) {
      lw.append(values.string(s));
    }
    return lw.done();
  }
 
  public IString wrap(IString src, IInteger wrapLength) {
    int wrapAt = wrapLength.intValue();
    if (wrapAt < 1) {
      wrapAt = 1;
    }
    final int iLength = src.length();

    final StringBuilder result = new StringBuilder(iLength + (iLength / wrapAt));
   
    int lineBegin = 0;
    while (iLength - lineBegin > wrapAt) {
      while (lineBegin < iLength && src.charAt(lineBegin) == ' ') {
        // skip over leading spaces
        lineBegin++;
      }
      // find wrapping point closest to border
      int lineEnd = lineBegin + wrapAt;
      while (lineEnd > lineBegin && lineEnd < iLength && src.charAt(lineEnd) != ' ') {
        lineEnd--;
      }
      if (lineEnd > lineBegin) {
        // we found a wrap point
        result.append(src.substring(lineBegin, lineEnd).getValue());
        result.append(System.lineSeparator());
        lineBegin = lineEnd + 1;
      }
      else {
        // long word, not breakable, lets search for the end
        lineEnd = lineBegin + wrapAt;
        while (lineEnd < iLength && src.charAt(lineEnd) != ' ') {
          lineEnd++;
        }
        result.append(src.substring(lineBegin, lineEnd).getValue());
        if (lineEnd < iLength) {
          result.append(System.lineSeparator());
        }
        lineBegin = lineEnd + 1;
      }
    }
    // the last part we add if there is something left
    if (lineBegin < iLength) {
      result.append(src.substring(lineBegin).getValue());
    }
    return values.string(result.toString());
  }

  public IValue format(IString s, IString dir, IInteger n, IString pad)
  //@doc{format -- return string of length n, with s placed according to dir (left/center/right) and padded with pad}
  {
      StringBuffer res = new StringBuffer();
      int sLen = s.length();
      int nVal = n.intValue();
      if(sLen > nVal){
         return s;
      }
      int padLen = pad.length();
      java.lang.String dirVal = dir.getValue();
      int start;
     
      if(dirVal.equals("right"))
         start = nVal - sLen;
      else if(dirVal.equals("center"))
         start = (nVal - sLen)/2;
      else
         start = 0;
     
      int i = 0;
      while(i < start){
           if(i + padLen < start){
             res.append(pad.getValue());
             i+= padLen;
           } else {
             res.append(pad.substring(0, start - i).getValue());
             i += start - i;
           }
      }
      res.append(s.getValue());
      i = start + sLen;
      while(i < nVal){
           if(i + padLen < nVal){
             res.append(pad.getValue());
             i += padLen;
           } else {
             res.append(pad.substring(0, nVal - i).getValue());
             i += nVal - i;
           }
      }
      return values.string(res.toString());
  }
 
  public IValue isEmpty(IString s)
  //@doc{isEmpty -- is string empty?}
  {
    return values.bool(s.getValue().length() == 0);
  }

  public IValue reverse(IString s)
  //@doc{reverse -- return string with all characters in reverse order.}
  {
     return s.reverse();
  }

  public IValue size(IString s)
  //@doc{size -- return the length of string s.}
  {
    return values.integer(s.length());
  }

  public IValue startsWith(IString s, IString prefix)
  //@doc{startsWith -- return true if string s starts with the string prefix.}
  {
    if (prefix.length() == 0) {
      return values.bool(true);
    }
    return values.bool(s.getValue().startsWith(prefix.getValue()));
  }

  public IValue substring(IString s, IInteger begin) {
    try {
      return s.substring(begin.intValue());
    } catch (IndexOutOfBoundsException e) {
      throw RuntimeExceptionFactory.indexOutOfBounds(begin, null, null);
    }
  }
 
  public IValue substring(IString s, IInteger begin, IInteger end) {
    try {
      return s.substring(begin.intValue(),end.intValue());
    } catch (IndexOutOfBoundsException e) {
      int bval = begin.intValue();
      IInteger culprit = (bval < 0 || bval >= s.length()) ? begin : end;
        throw RuntimeExceptionFactory.indexOutOfBounds(culprit, null, null);
    }
 
  }
 
  public IValue toInt(IString s)
  //@doc{toInt -- convert a string s to integer}
  {
    try {
      java.lang.String sval = s.getValue();
      boolean isNegative = false;
      int radix = 10;
     
      if (sval.equals("0")) {
        return values.integer(0);
      }
     
      if (sval.startsWith("-")) {
        isNegative = true;
        sval = sval.substring(1);
      }
      if (sval.startsWith("0x") || sval.startsWith("0X")) {
        radix = 16;
        sval = sval.substring(2);
      } else if (sval.startsWith("0")) {
        radix = 8;
        sval = sval.substring(1);
      }
      BigInteger bi = new BigInteger(isNegative ? "-" + sval : sval, radix);
      return values.integer(bi.toString());
    }
    catch (NumberFormatException e){
      throw RuntimeExceptionFactory.illegalArgument(null, null);
    }
  }
 
  public IValue toInt(IString s, IInteger r)
  {
    try {
      java.lang.String sval = s.getValue();
      boolean isNegative = false;
      int radix = r.intValue();
     
      if (sval.equals("0")) {
        return values.integer(0);
      }
     
      if (sval.startsWith("-")) {
        isNegative = true;
        sval = sval.substring(1);
      }
      BigInteger bi = new BigInteger(isNegative ? "-" + sval : sval, radix);
      return values.integer(bi.toString());
    }
    catch (NumberFormatException e){
      throw RuntimeExceptionFactory.illegalArgument(null, null);
    }
  }
 
  public IValue toReal(IString s)
  //@doc{toReal -- convert a string s to a real}
  {
    try {
      return values.real(s.getValue());
    }
    catch (NumberFormatException e){
      throw RuntimeExceptionFactory.illegalArgument(null, null);
    }
  }
 
  public IValue toReal(IRational s)
  //@doc{toReal -- convert a string s to a real}
  {
      return s.toReal();
  }
 
  public IValue toLowerCase(IString s)
  //@doc{toLowerCase -- convert all characters in string s to lowercase.}
  {
    return values.string(s.getValue().toLowerCase());
  }

  public IValue toUpperCase(IString s)
  //@doc{toUpperCase -- convert all characters in string s to uppercase.}
  {
    return values.string(s.getValue().toUpperCase());
  }
 
  private boolean match(IString subject, int i, IString pattern){
    if(i + pattern.length() > subject.length())
      return false;
    for(int k = 0; k < pattern.length(); k++){
      if(subject.charAt(i) != pattern.charAt(k))
        return false;
      i++;
    }
    return true;
  }
 
  public IValue replaceAll(IString str, IString find, IString replacement){
    StringBuilder b = new StringBuilder(str.length() * 2);
   
    int iLength = str.length();
    int fLength = find.length();
    int i = 0;
    boolean matched = false;
    while(i < iLength){
      if(match(str,i,find)){
        matched = true;
        b.append(replacement.getValue());
        i += Math.max(1, fLength);
      } else {
        b.appendCodePoint(str.charAt(i));
        i++;
      }
    }
    return (!matched) ? str : values.string(b.toString());
  }
 
  public IValue replaceFirst(IString str, IString find, IString replacement){
    StringBuilder b = new StringBuilder(str.length() * 2);

    int iLength = str.length();
    int fLength = find.length();
   
    int i = 0;
    boolean matched = false;
    while(i < iLength){
      if(!matched && match(str,i,find)){
        matched = true;
        b.append(replacement.getValue());
        i += fLength;
       
      } else {
        b.appendCodePoint(str.charAt(i));
        i++;
      }
    }
    return (!matched) ? str : values.string(b.toString());
  }
 
  public IValue replaceLast(IString str, IString find, IString replacement){
    StringBuilder b = new StringBuilder(str.length() * 2);

    int iLength = str.length();
    int fLength = find.length();
   
    int i = iLength - fLength;
    while(i >= 0){
      if(match(str,i,find)){
        b.append(str.substring(0, i).getValue());
        b.append(replacement.getValue());
        b.append(str.substring(i + fLength).getValue());
        return values.string(b.toString());
      }
      i--;
    }
    return str;
  }
 
 
  public IValue escape(IString str, IMap substitutions) {
    StringBuilder b = new StringBuilder(str.length() * 2);
   
    int sLength = str.length();
    for (int c = 0; c < sLength; c++) {
      IString chr = str.substring(c, c+1);
      IString sub = (IString)substitutions.get(chr);

      if (sub != null) {
        b.append(sub.getValue());
      }
      else {
        b.append(chr.getValue());
      }
    }
    return values.string(b.toString());
  }
 
  public IValue contains(IString str, IString find){
    return values.bool(str.getValue().indexOf(find.getValue()) >= 0);
  }
 
  public IValue findAll(IString str, IString find){
    int iLength = str.length();
    int fLength = find.length();
    IListWriter w = values.listWriter();
   
    for(int i = 0; i <= iLength - fLength; i++){
      if(match(str, i, find)){
        w.append(values.integer(i));
      }
    }
    return w.done();
  }
 
  public IValue findFirst(IString str, IString find){
    int iLength = str.length();
    int fLength = find.length();
   
    for(int i = 0; i <= iLength - fLength; i++){
      if(match(str, i, find)){
         return values.integer(i);
      }
    }
    return values.integer(-1);
  }
 
  public IValue findLast(IString str, IString find){
    int iLength = str.length();
    int fLength = find.length();
   
    for(int i = iLength - fLength; i >= 0; i--){
      if(match(str, i, find)){
         return values.integer(i);
      }
    }
    return values.integer(-1);
  }
 
  /*
   *  !!EXPERIMENTAL!!
   * Tuple
   */
 
  public IList fieldsOf(IValue v){
    if(!v.getType().isTuple())
      throw RuntimeExceptionFactory.illegalArgument(v, null, null, "argument of type tuple is required");
    ITuple tp = (ITuple) v;
    Type tt = tp.getType();
    int a = tt.getArity();
    IListWriter w = values.listWriter();
    for(int i = 0; i < a; i++){
      String fname = tt.getFieldName(i);
      if(fname == null)
        fname = "";
      w.append(values.string(fname));
    }
    return w.done();
  }
 
  /*
   * ValueIO
   */
 
  // REFLECT -- copy in PreludeCompiled
  public IInteger getFileLength(ISourceLocation g, IEvaluatorContext ctx) throws IOException {
    File f = new File(ctx.getResolverRegistry().getResourceURI(g.getURI()));
    if (!f.exists() || f.isDirectory()) throw new IOException();
    return values.integer(f.length());
  }
 
  // REFLECT -- copy in PreludeCompiled
  public IValue readBinaryValueFile(IValue type, ISourceLocation loc, IEvaluatorContext ctx){
   
//    TypeStore store = ctx.getCurrentEnvt().getStore();
    TypeStore store = new TypeStore();
   
// TODO: commented out the following lines and that seems to sove the duplicate declaration of ParseTree.
//     Why was this import here? Can someone check?
   
//    ModuleEnvironment pt = ctx.getHeap().getModule("ParseTree");
//    if(pt != null){
//      store.importStore(pt.getStore());
//    }
    Type start = tr.valueToType((IConstructor) type, store);
    loc = ctx.getHeap().resolveSourceLocation(loc);
   
    InputStream in = null;
    try{
      in = new BufferedInputStream(ctx.getResolverRegistry().getInputStream(loc.getURI()));
      return new BinaryValueReader().read(values, store, start, in);
    }catch(IOException e){
      throw RuntimeExceptionFactory.io(values.string(e.getMessage()), null, null);
    }catch(Exception e){
      e.printStackTrace();
      throw RuntimeExceptionFactory.io(values.string(e.getMessage()), null, null);
    }finally{
      if(in != null){
        try{
          in.close();
        }catch(IOException ioex){
          throw RuntimeExceptionFactory.io(values.string(ioex.getMessage()), null, null);
        }
      }
    }
  }
 
  class RascalValuesValueFactory extends AbstractValueFactoryAdapter {
    public RascalValuesValueFactory() {
      super(values);
    }
   
    @Override
    public INode node(String name, IValue... children) {
      IConstructor res = specializeType(name, children);
     
      return res != null ? res: values.node(name, children);
    }

    private IConstructor specializeType(String name, IValue... children) {
      if ("type".equals(name)
          && children.length == 2
          && children[0].getType().isSubtypeOf(Factory.Type_Reified.getFieldType(0))
          && children[1].getType().isSubtypeOf(Factory.Type_Reified.getFieldType(1))) {
        java.util.Map<Type,Type> bindings = new HashMap<Type,Type>();
        bindings.put(Factory.TypeParam, tr.symbolToType((IConstructor) children[0], (IMap) children[1]));
       
        return values.constructor(Factory.Type_Reified.instantiate(bindings), children[0], children[1]);
      }
     
      return null;
    }
   
    @Override
    public INode node(String name, Map<String, IValue> annotations,
        IValue... children) throws FactTypeUseException {
      IConstructor res = specializeType(name, children);
     
      return res != null ? res: values.node(name, annotations, children);
    }
   
    @Override
    public INode node(String name, IValue[] children,
        Map<String, IValue> keyArgValues) throws FactTypeUseException {
      IConstructor res = specializeType(name, children);
     
      return res != null ? res: values.node(name, children, keyArgValues);
    }
   
  }
 
  // REFLECT -- copy in PreludeCompiled
  public IValue readTextValueFile(IValue type, ISourceLocation loc, IEvaluatorContext ctx){
    loc = ctx.getHeap().resolveSourceLocation(loc);
   
      TypeStore store = new TypeStore();
    Type start = tr.valueToType((IConstructor) type, store);
   
    InputStream in = null;
    try{
      in = new BufferedInputStream(ctx.getResolverRegistry().getInputStream(loc.getURI()));
      return new StandardTextReader().read(new RascalValuesValueFactory(), store, start, new InputStreamReader(in, "UTF8"));
    }catch(IOException e){
      throw RuntimeExceptionFactory.io(values.string(e.getMessage()), null, null);
    }finally{
      if(in != null){
        try{
          in.close();
        }catch(IOException ioex){
          throw RuntimeExceptionFactory.io(values.string(ioex.getMessage()), null, null);
        }
      }
    }
  }
 
  // REFLECT -- copy in PreludeCompiled
  public IValue readTextValueString(IValue type, IString input, IEvaluatorContext ctx) {
//    TypeStore store = ctx.getCurrentEnvt().getStore();
    TypeStore store = new TypeStore();
    ModuleEnvironment pt = ctx.getHeap().getModule("ParseTree");
    if(pt != null){
      store.importStore(pt.getStore());
    }
    Type start = tr.valueToType((IConstructor) type, store);
   
    StringReader in = new StringReader(input.getValue());
    try {
      return new StandardTextReader().read(values, store, start, in);
    } catch (FactTypeUseException e) {
      throw RuntimeExceptionFactory.io(values.string(e.getMessage()), null, null);
    } catch (IOException e) {
      throw RuntimeExceptionFactory.io(values.string(e.getMessage()), null, null);
    }
  }
 
  // REFLECT -- copy in PreludeCompiled
  public void writeBinaryValueFile(ISourceLocation loc, IValue value, IBool compression, IEvaluatorContext ctx){
    loc = ctx.getHeap().resolveSourceLocation(loc);
   
    OutputStream out = null;
    try{
      out = ctx.getResolverRegistry().getOutputStream(loc.getURI(), false);
      new BinaryValueWriter().write(value, out, compression.getValue());
    }catch (IOException ioex){
      throw RuntimeExceptionFactory.io(values.string(ioex.getMessage()), null, null);
    }finally{
      if(out != null){
        try{
          out.close();
        }catch(IOException ioex){
          throw RuntimeExceptionFactory.io(values.string(ioex.getMessage()), null, null);
        }
      }
    }
  }
 
  // REFLECT -- copy in PreludeCompiled
  public void writeTextValueFile(ISourceLocation loc, IValue value, IEvaluatorContext ctx){
    loc = ctx.getHeap().resolveSourceLocation(loc);
   
    OutputStream out = null;
    try{
      out = ctx.getResolverRegistry().getOutputStream(loc.getURI(), false);
      new StandardTextWriter().write(value, new OutputStreamWriter(out, "UTF8"));
    }
     catch(IOException e) {
      throw RuntimeExceptionFactory.io(values.string(e.getMessage()), null, null);
    }
    finally {
      if (out != null) {
        try {
          out.flush();
          out.close();
        }
        catch(IOException ioex) {
          throw RuntimeExceptionFactory.io(values.string(ioex.getMessage()), null, null);
        }
      }
    }
  }
 
  public IBool rexpMatch(IString s, IString re) {
    if(Pattern.matches(re.getValue(), s.getValue()))
      return values.bool(true);
    else
      return values.bool(false);
  }

  // TODO: is this relevant in the compiler?
  public IList getTraversalContext(IEvaluatorContext ctx) {
    return ctx.getEvaluator().__getCurrentTraversalEvaluator().getContext();
  }
 
  public ISourceLocation uuid() {
    String uuid = UUID.randomUUID().toString();
   
    try {
      return values.sourceLocation("uuid",uuid,"");
    } catch (URISyntaxException e) {
      assert false;
      throw RuntimeExceptionFactory.malformedURI("uuid://" + uuid, null, null);
    }
  }
 
  public IInteger uuidi() {
    UUID uuid = UUID.randomUUID();
    ByteArrayOutputStream bytes = new ByteArrayOutputStream();
    DataOutputStream data = new DataOutputStream(bytes);
    try {
      data.writeLong(uuid.getMostSignificantBits());
      data.writeLong(uuid.getLeastSignificantBits());
      return values.integer(bytes.toByteArray());
    } catch (IOException e) {
      throw RuntimeExceptionFactory.io(values.string("could not generate unique number " + uuid), null, null);
    }
  }
}

// Utilities used by Graph
//TODO: Why is this code in the library? This should be done in pure Rascal.

class Distance{
  public int intval;
 
  Distance(int n){
    intval = n;
  }
}

class NodeComparator implements Comparator<IValue> {
  private final HashMap<IValue,Distance> distance;
 
  NodeComparator(HashMap<IValue,Distance> distance){
    this.distance = distance;
  }

  public int compare(IValue arg0, IValue arg1) {
    int d0 = distance.get(arg0).intval;
    int d1 = distance.get(arg1).intval;
   
    return d0 < d1 ? -1 : ((d0 == d1) ? 0 : 1);
  }
}
TOP

Related Classes of org.rascalmpl.library.Prelude$Sorting

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.