PageRenderTime 66ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 1ms

/src/org/rascalmpl/library/Prelude.java

https://github.com/jimivdw/rascal
Java | 3276 lines | 2864 code | 256 blank | 156 comment | 199 complexity | e246167e580352ac788e8e65641b2aef MD5 | raw file
  1. /*******************************************************************************
  2. * Copyright (c) 2009-2013 CWI
  3. * All rights reserved. This program and the accompanying materials
  4. * are made available under the terms of the Eclipse Public License v1.0
  5. * which accompanies this distribution, and is available at
  6. * http://www.eclipse.org/legal/epl-v10.html
  7. *
  8. * Contributors:
  9. * * Paul Klint - Paul.Klint@cwi.nl - CWI
  10. * * Jurgen J. Vinju - Jurgen.Vinju@cwi.nl - CWI
  11. * * Arnold Lankamp - Arnold.Lankamp@cwi.nl
  12. * * Davy Landman - Davy.Landman@cwi.nl
  13. * * Michael Steindorfer - Michael.Steindorfer@cwi.nl - CWI
  14. *******************************************************************************/
  15. /*******************************************************************************
  16. *
  17. * Warning this file is an experiment to determine the effect of collecting all
  18. * classes used by the Prelude in a single class. Overall effect seems to be circa 10%
  19. * reduction of import time.
  20. *
  21. * Do not edit/change this code, but use the original code instead.
  22. *
  23. */
  24. package org.rascalmpl.library;
  25. import java.io.BufferedInputStream;
  26. import java.io.BufferedReader;
  27. import java.io.FileInputStream;
  28. import java.io.FileNotFoundException;
  29. import java.io.FileReader;
  30. import java.io.IOException;
  31. import java.io.InputStream;
  32. import java.io.InputStreamReader;
  33. import java.io.OutputStream;
  34. import java.io.OutputStreamWriter;
  35. import java.io.PrintWriter;
  36. import java.io.Reader;
  37. import java.io.StringReader;
  38. import java.lang.ref.WeakReference;
  39. import java.math.BigInteger;
  40. import java.net.MalformedURLException;
  41. import java.nio.charset.Charset;
  42. import java.security.DigestInputStream;
  43. import java.security.MessageDigest;
  44. import java.security.NoSuchAlgorithmException;
  45. import java.text.ParseException;
  46. import java.util.Comparator;
  47. import java.util.HashMap;
  48. import java.util.HashSet;
  49. import java.util.Iterator;
  50. import java.util.LinkedList;
  51. import java.util.Locale;
  52. import java.util.Map;
  53. import java.util.Map.Entry;
  54. import java.util.PriorityQueue;
  55. import java.util.Random;
  56. import java.util.Set;
  57. import java.util.regex.Pattern;
  58. import org.apache.commons.lang.CharSetUtils;
  59. import org.apache.commons.lang.WordUtils;
  60. import org.eclipse.imp.pdb.facts.IBool;
  61. import org.eclipse.imp.pdb.facts.IConstructor;
  62. import org.eclipse.imp.pdb.facts.IDateTime;
  63. import org.eclipse.imp.pdb.facts.IInteger;
  64. import org.eclipse.imp.pdb.facts.IList;
  65. import org.eclipse.imp.pdb.facts.IListRelation;
  66. import org.eclipse.imp.pdb.facts.IListWriter;
  67. import org.eclipse.imp.pdb.facts.IMap;
  68. import org.eclipse.imp.pdb.facts.IMapWriter;
  69. import org.eclipse.imp.pdb.facts.INode;
  70. import org.eclipse.imp.pdb.facts.IRational;
  71. import org.eclipse.imp.pdb.facts.IRelation;
  72. import org.eclipse.imp.pdb.facts.IRelationWriter;
  73. import org.eclipse.imp.pdb.facts.ISet;
  74. import org.eclipse.imp.pdb.facts.ISetWriter;
  75. import org.eclipse.imp.pdb.facts.ISourceLocation;
  76. import org.eclipse.imp.pdb.facts.IString;
  77. import org.eclipse.imp.pdb.facts.ITuple;
  78. import org.eclipse.imp.pdb.facts.IValue;
  79. import org.eclipse.imp.pdb.facts.IValueFactory;
  80. import org.eclipse.imp.pdb.facts.exceptions.FactTypeUseException;
  81. import org.eclipse.imp.pdb.facts.io.ATermReader;
  82. import org.eclipse.imp.pdb.facts.io.BinaryValueReader;
  83. import org.eclipse.imp.pdb.facts.io.BinaryValueWriter;
  84. import org.eclipse.imp.pdb.facts.io.StandardTextReader;
  85. import org.eclipse.imp.pdb.facts.io.StandardTextWriter;
  86. import org.eclipse.imp.pdb.facts.type.Type;
  87. import org.eclipse.imp.pdb.facts.type.TypeFactory;
  88. import org.eclipse.imp.pdb.facts.type.TypeStore;
  89. import org.eclipse.imp.pdb.facts.visitors.VisitorException;
  90. import org.rascalmpl.interpreter.IEvaluatorContext;
  91. import org.rascalmpl.interpreter.TypeReifier;
  92. import org.rascalmpl.interpreter.asserts.ImplementationError;
  93. import org.rascalmpl.interpreter.control_exceptions.Throw;
  94. import org.rascalmpl.interpreter.result.ICallableValue;
  95. import org.rascalmpl.interpreter.staticErrors.UndeclaredNonTerminal;
  96. import org.rascalmpl.interpreter.types.FunctionType;
  97. import org.rascalmpl.interpreter.types.NonTerminalType;
  98. import org.rascalmpl.interpreter.types.ReifiedType;
  99. import org.rascalmpl.interpreter.utils.RuntimeExceptionFactory;
  100. import org.rascalmpl.parser.gtd.exception.ParseError;
  101. import org.rascalmpl.parser.gtd.exception.UndeclaredNonTerminalException;
  102. import org.rascalmpl.unicode.UnicodeDetector;
  103. import org.rascalmpl.unicode.UnicodeOutputStreamWriter;
  104. import org.rascalmpl.values.uptr.Factory;
  105. import org.rascalmpl.values.uptr.ProductionAdapter;
  106. import org.rascalmpl.values.uptr.SymbolAdapter;
  107. import org.rascalmpl.values.uptr.TreeAdapter;
  108. import org.rascalmpl.values.uptr.visitors.TreeVisitor;
  109. import com.ibm.icu.text.SimpleDateFormat;
  110. import com.ibm.icu.util.Calendar;
  111. import com.ibm.icu.util.TimeZone;
  112. import com.ibm.icu.util.ULocale;
  113. public class Prelude {
  114. private final TypeFactory types ;
  115. private final IValueFactory values;
  116. private final Random random;
  117. public Prelude(IValueFactory values){
  118. super();
  119. this.values = values;
  120. this.types = TypeFactory.getInstance();
  121. this.tr = new TypeReifier(values);
  122. random = new Random();
  123. }
  124. /* // Only here for test purposes:
  125. public IValue f1(IInteger x, IInteger y){
  126. return values.integer(x.intValue() + y.intValue());
  127. }
  128. public IValue f2(IInteger x, IList LS, IString y, IBool z){
  129. return values.string("x : " + x.intValue() + ", LS = " + LS + ", y ; " + y + ", z : " + z);
  130. }
  131. */
  132. /*
  133. * Boolean
  134. */
  135. public IValue arbBool() // get an arbitrary boolean value.}
  136. {
  137. return values.bool(random.nextInt(2) == 1);
  138. }
  139. /*
  140. * DateTime
  141. */
  142. public IValue now()
  143. //@doc{Get the current datetime.}
  144. {
  145. return values.datetime(Calendar.getInstance().getTimeInMillis());
  146. }
  147. public IValue createDate(IInteger year, IInteger month, IInteger day)
  148. //@doc{Create a new date.}
  149. {
  150. return values.date(year.intValue(), month.intValue(), day.intValue());
  151. }
  152. public IValue createTime(IInteger hour, IInteger minute, IInteger second,
  153. IInteger millisecond)
  154. //@doc{Create a new time.}
  155. {
  156. return values.time(hour.intValue(), minute.intValue(), second.intValue(), millisecond.intValue());
  157. }
  158. public IValue createTime(IInteger hour, IInteger minute, IInteger second,
  159. IInteger millisecond, IInteger timezoneHourOffset, IInteger timezoneMinuteOffset)
  160. //@doc{Create a new time with the given numeric timezone offset.}
  161. {
  162. return values.time(hour.intValue(), minute.intValue(), second.intValue(),
  163. millisecond.intValue(), timezoneHourOffset.intValue(), timezoneMinuteOffset.intValue());
  164. }
  165. public IValue createDateTime(IInteger year, IInteger month, IInteger day,
  166. IInteger hour, IInteger minute, IInteger second, IInteger millisecond)
  167. //@doc{Create a new datetime.}
  168. {
  169. return values.datetime(year.intValue(), month.intValue(), day.intValue(), hour.intValue(),
  170. minute.intValue(), second.intValue(), millisecond.intValue());
  171. }
  172. public IValue createDateTime(IInteger year, IInteger month, IInteger day,
  173. IInteger hour, IInteger minute, IInteger second, IInteger millisecond,
  174. IInteger timezoneHourOffset, IInteger timezoneMinuteOffset)
  175. //@doc{Create a new datetime with the given numeric timezone offset.}
  176. {
  177. return values.datetime(year.intValue(), month.intValue(), day.intValue(), hour.intValue(),
  178. minute.intValue(), second.intValue(), millisecond.intValue(), timezoneHourOffset.intValue(),
  179. timezoneMinuteOffset.intValue());
  180. }
  181. public IValue joinDateAndTime(IDateTime date, IDateTime time)
  182. //@doc{Create a new datetime by combining a date and a time.}
  183. {
  184. return values.datetime(date.getYear(), date.getMonthOfYear(), date.getDayOfMonth(),
  185. time.getHourOfDay(), time.getMinuteOfHour(), time.getSecondOfMinute(),
  186. time.getMillisecondsOfSecond(), time.getTimezoneOffsetHours(), time.getTimezoneOffsetMinutes());
  187. }
  188. public IValue splitDateTime(IDateTime dt)
  189. //@doc{Split an existing datetime into a tuple with the date and the time.}
  190. {
  191. return values.tuple(values.date(dt.getYear(), dt.getMonthOfYear(), dt.getDayOfMonth()),
  192. values.time(dt.getHourOfDay(), dt.getMinuteOfHour(), dt.getSecondOfMinute(),
  193. dt.getMillisecondsOfSecond(), dt.getTimezoneOffsetHours(), dt.getTimezoneOffsetMinutes()));
  194. }
  195. public IValue incrementYears(IDateTime dt, IInteger n)
  196. //@doc{Increment the years by a given amount.}
  197. {
  198. return incrementDate(dt, Calendar.YEAR, "years", n);
  199. }
  200. public IValue incrementMonths(IDateTime dt, IInteger n)
  201. //@doc{Increment the months by a given amount.}
  202. {
  203. return incrementDate(dt, Calendar.MONTH, "months", n);
  204. }
  205. public IValue incrementDays(IDateTime dt, IInteger n)
  206. //@doc{Increment the days by a given amount.}
  207. {
  208. return incrementDate(dt, Calendar.DAY_OF_MONTH, "days", n);
  209. }
  210. private String getTZString(int hourOffset, int minuteOffset) {
  211. String tzString = "GMT" +
  212. ((hourOffset < 0 || (0 == hourOffset && minuteOffset < 0)) ? "-" : "+") +
  213. String.format("%02d",hourOffset >= 0 ? hourOffset : hourOffset * -1) +
  214. String.format("%02d",minuteOffset >= 0 ? minuteOffset : minuteOffset * -1);
  215. return tzString;
  216. }
  217. private final int millisInAMinute = 1000 * 60;
  218. private final int millisInAnHour = millisInAMinute * 60;
  219. private IValue incrementDTField(IDateTime dt, int field, IInteger amount) {
  220. Calendar cal = null;
  221. cal = dateTimeToCalendar(dt);
  222. // Make sure lenient is true, since this allows wrapping of fields. For
  223. // instance, if you have $2012-05-15, and subtract 15 months, this is
  224. // an error if lenient is false, but gives $2012-02-15 (as expected)
  225. // if lenient is true.
  226. cal.setLenient(true);
  227. cal.add(field, amount.intValue());
  228. // Turn the calendar back into a date, time, or datetime value
  229. if (dt.isDate()) {
  230. return calendarToDate(cal);
  231. } else {
  232. if (dt.isTime()) {
  233. return calendarToTime(cal);
  234. } else {
  235. return calendarToDateTime(cal);
  236. }
  237. }
  238. }
  239. private IValue calendarToDateTime(Calendar cal) {
  240. int timezoneHours = cal.get(Calendar.ZONE_OFFSET) / millisInAnHour;
  241. int timezoneMinutes = cal.get(Calendar.ZONE_OFFSET) % millisInAnHour / millisInAMinute;
  242. return createDateTime(values.integer(cal.get(Calendar.YEAR)),
  243. values.integer(cal.get(Calendar.MONTH)+1),
  244. values.integer(cal.get(Calendar.DAY_OF_MONTH)),
  245. values.integer(cal.get(Calendar.HOUR_OF_DAY)),
  246. values.integer(cal.get(Calendar.MINUTE)),
  247. values.integer(cal.get(Calendar.SECOND)),
  248. values.integer(cal.get(Calendar.MILLISECOND)),
  249. values.integer(timezoneHours),
  250. values.integer(timezoneMinutes));
  251. }
  252. private IValue calendarToTime(Calendar cal) {
  253. int timezoneHours = cal.get(Calendar.ZONE_OFFSET) / millisInAnHour;
  254. int timezoneMinutes = cal.get(Calendar.ZONE_OFFSET) % millisInAnHour / millisInAMinute;
  255. return createTime(values.integer(cal.get(Calendar.HOUR_OF_DAY)),
  256. values.integer(cal.get(Calendar.MINUTE)),
  257. values.integer(cal.get(Calendar.SECOND)),
  258. values.integer(cal.get(Calendar.MILLISECOND)),
  259. values.integer(timezoneHours),
  260. values.integer(timezoneMinutes));
  261. }
  262. private IValue calendarToDate(Calendar cal) {
  263. return createDate(values.integer(cal.get(Calendar.YEAR)),
  264. values.integer(cal.get(Calendar.MONTH)+1),
  265. values.integer(cal.get(Calendar.DAY_OF_MONTH)));
  266. }
  267. private Calendar dateTimeToCalendar(IDateTime dt) {
  268. Calendar cal;
  269. if (dt.isDate()) {
  270. cal = Calendar.getInstance(TimeZone.getDefault(), Locale.getDefault());
  271. cal.set(dt.getYear(), dt.getMonthOfYear()-1, dt.getDayOfMonth());
  272. } else {
  273. cal = Calendar.getInstance(TimeZone.getTimeZone(getTZString(dt.getTimezoneOffsetHours(), dt.getTimezoneOffsetMinutes())),Locale.getDefault());
  274. if (dt.isTime()) {
  275. cal.set(1970, 0, 1, dt.getHourOfDay(), dt.getMinuteOfHour(), dt.getSecondOfMinute());
  276. } else {
  277. cal.set(dt.getYear(), dt.getMonthOfYear()-1, dt.getDayOfMonth(), dt.getHourOfDay(), dt.getMinuteOfHour(), dt.getSecondOfMinute());
  278. }
  279. cal.set(Calendar.MILLISECOND, dt.getMillisecondsOfSecond());
  280. }
  281. return cal;
  282. }
  283. private IValue incrementTime(IDateTime dt, int field, String fieldName, IInteger amount) {
  284. if (dt.isDate())
  285. throw RuntimeExceptionFactory.invalidUseOfDateException("Cannot increment the " + fieldName + " on a date value.", null, null);
  286. return incrementDTField(dt, field, amount);
  287. }
  288. private IValue incrementDate(IDateTime dt, int field, String fieldName, IInteger amount) {
  289. if (dt.isTime())
  290. throw RuntimeExceptionFactory.invalidUseOfDateException("Cannot increment the " + fieldName + " on a time value.", null, null);
  291. return incrementDTField(dt, field, amount);
  292. }
  293. public IValue incrementHours(IDateTime dt, IInteger n)
  294. //@doc{Increment the hours by a given amount.}
  295. {
  296. return incrementTime(dt, Calendar.HOUR_OF_DAY, "hours", n);
  297. }
  298. public IValue incrementMinutes(IDateTime dt, IInteger n)
  299. //@doc{Increment the minutes by a given amount.}
  300. {
  301. return incrementTime(dt, Calendar.MINUTE, "minutes", n);
  302. }
  303. public IValue incrementSeconds(IDateTime dt, IInteger n)
  304. //@doc{Increment the seconds by a given amount.}
  305. {
  306. return incrementTime(dt, Calendar.SECOND, "seconds", n);
  307. }
  308. public IValue incrementMilliseconds(IDateTime dt, IInteger n)
  309. //@doc{Increment the milliseconds by a given amount.}
  310. {
  311. return incrementTime(dt, Calendar.MILLISECOND, "milliseconds", n);
  312. }
  313. public IValue decrementYears(IDateTime dt, IInteger n)
  314. //@doc{Decrement the years by a given amount.}
  315. {
  316. return incrementDate(dt, Calendar.YEAR, "years", n.negate());
  317. }
  318. public IValue decrementMonths(IDateTime dt, IInteger n)
  319. //@doc{Decrement the months by a given amount.}
  320. {
  321. return incrementDate(dt, Calendar.MONTH, "months", n.negate()); }
  322. public IValue decrementDays(IDateTime dt, IInteger n)
  323. //@doc{Decrement the days by a given amount.}
  324. {
  325. return incrementDate(dt, Calendar.DAY_OF_MONTH, "days", n.negate());
  326. }
  327. public IValue decrementHours(IDateTime dt, IInteger n)
  328. //@doc{Decrement the hours by a given amount.}
  329. {
  330. return incrementTime(dt, Calendar.HOUR_OF_DAY, "hours", n.negate());
  331. }
  332. public IValue decrementMinutes(IDateTime dt, IInteger n)
  333. //@doc{Decrement the minutes by a given amount.}
  334. {
  335. return incrementTime(dt, Calendar.MINUTE, "minutes", n.negate());
  336. }
  337. public IValue decrementSeconds(IDateTime dt, IInteger n)
  338. //@doc{Decrement the seconds by a given amount.}
  339. {
  340. return incrementTime(dt, Calendar.SECOND, "seconds", n.negate());
  341. }
  342. public IValue decrementMilliseconds(IDateTime dt, IInteger n)
  343. //@doc{Decrement the milliseconds by a given amount.}
  344. {
  345. return incrementTime(dt, Calendar.MILLISECOND, "milliseconds", n.negate());
  346. }
  347. public IValue createDurationInternal(IDateTime dStart, IDateTime dEnd) {
  348. // dStart and dEnd both have to be dates, times, or datetimes
  349. Calendar startCal = Calendar.getInstance();
  350. startCal.setTimeInMillis(dStart.getInstant());
  351. Calendar endCal = Calendar.getInstance();
  352. endCal.setTimeInMillis(dEnd.getInstant());
  353. IValue duration = null;
  354. if (dStart.isDate()) {
  355. if (dEnd.isDate()) {
  356. duration = values.tuple(
  357. values.integer(startCal.fieldDifference(endCal.getTime(), Calendar.YEAR)),
  358. values.integer(startCal.fieldDifference(endCal.getTime(), Calendar.MONTH)),
  359. values.integer(startCal.fieldDifference(endCal.getTime(), Calendar.DAY_OF_MONTH)),
  360. values.integer(0), values.integer(0), values.integer(0),
  361. values.integer(0));
  362. } else if (dEnd.isTime()) {
  363. throw RuntimeExceptionFactory.invalidUseOfTimeException("Cannot determine the duration between a date with no time and a time with no date.", null, null);
  364. } else {
  365. throw RuntimeExceptionFactory.invalidUseOfDateTimeException("Cannot determine the duration between a date with no time and a datetime.", null, null);
  366. }
  367. } else if (dStart.isTime()) {
  368. if (dEnd.isTime()) {
  369. duration = values.tuple(
  370. values.integer(0),
  371. values.integer(0),
  372. values.integer(0),
  373. values.integer(startCal.fieldDifference(endCal.getTime(), Calendar.HOUR_OF_DAY)),
  374. values.integer(startCal.fieldDifference(endCal.getTime(), Calendar.MINUTE)),
  375. values.integer(startCal.fieldDifference(endCal.getTime(), Calendar.SECOND)),
  376. values.integer(startCal.fieldDifference(endCal.getTime(), Calendar.MILLISECOND)));
  377. } else if (dEnd.isDate()) {
  378. throw RuntimeExceptionFactory.invalidUseOfDateException("Cannot determine the duration between a time with no date and a date with no time.", null, null);
  379. } else {
  380. throw RuntimeExceptionFactory.invalidUseOfDateTimeException("Cannot determine the duration between a time with no date and a datetime.", null, null);
  381. }
  382. } else {
  383. if (dEnd.isDateTime()) {
  384. duration = values.tuple(
  385. values.integer(startCal.fieldDifference(endCal.getTime(), Calendar.YEAR)),
  386. values.integer(startCal.fieldDifference(endCal.getTime(), Calendar.MONTH)),
  387. values.integer(startCal.fieldDifference(endCal.getTime(), Calendar.DAY_OF_MONTH)),
  388. values.integer(startCal.fieldDifference(endCal.getTime(), Calendar.HOUR_OF_DAY)),
  389. values.integer(startCal.fieldDifference(endCal.getTime(), Calendar.MINUTE)),
  390. values.integer(startCal.fieldDifference(endCal.getTime(), Calendar.SECOND)),
  391. values.integer(startCal.fieldDifference(endCal.getTime(), Calendar.MILLISECOND)));
  392. } else if (dEnd.isDate()) {
  393. throw RuntimeExceptionFactory.invalidUseOfDateException("Cannot determine the duration between a datetime and a date with no time.", null, null);
  394. } else {
  395. throw RuntimeExceptionFactory.invalidUseOfTimeException("Cannot determine the duration between a datetime and a time with no date.", null, null);
  396. }
  397. }
  398. return duration;
  399. }
  400. public IValue parseDate(IString inputDate, IString formatString)
  401. //@doc{Parse an input date given as a string using the given format string}
  402. {
  403. try {
  404. java.text.SimpleDateFormat fmt = new java.text.SimpleDateFormat(formatString.getValue());
  405. fmt.parse(inputDate.getValue());
  406. java.util.Calendar cal = fmt.getCalendar();
  407. return values.date(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH) + 1, cal.get(Calendar.DATE));
  408. } catch (IllegalArgumentException iae) {
  409. throw RuntimeExceptionFactory.dateTimeParsingError("Cannot parse input date: " + inputDate.getValue() +
  410. " using format string: " + formatString.getValue(), null, null);
  411. } catch (ParseException e) {
  412. throw RuntimeExceptionFactory.dateTimeParsingError("Cannot parse input date: " + inputDate.getValue() +
  413. " using format string: " + formatString.getValue(), null, null);
  414. }
  415. }
  416. public IValue parseDateInLocale(IString inputDate, IString formatString, IString locale)
  417. //@doc{Parse an input date given as a string using a specific locale and format string}
  418. {
  419. try {
  420. java.text.SimpleDateFormat fmt = new java.text.SimpleDateFormat(formatString.getValue(), new Locale(locale.getValue()));
  421. fmt.parse(inputDate.getValue());
  422. java.util.Calendar cal = fmt.getCalendar();
  423. return values.date(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH) + 1, cal.get(Calendar.DATE));
  424. } catch (IllegalArgumentException iae) {
  425. throw RuntimeExceptionFactory.dateTimeParsingError("Cannot parse input date: " + inputDate.getValue() +
  426. " using format string: " + formatString.getValue() + " in locale: " + locale.getValue(), null, null);
  427. } catch (ParseException e) {
  428. throw RuntimeExceptionFactory.dateTimeParsingError("Cannot parse input date: " + inputDate.getValue() +
  429. " using format string: " + formatString.getValue() + " in locale: " + locale.getValue(), null, null);
  430. }
  431. }
  432. public IValue parseTime(IString inputTime, IString formatString)
  433. //@doc{Parse an input time given as a string using the given format string}
  434. {
  435. try {
  436. java.text.SimpleDateFormat fmt = new java.text.SimpleDateFormat(formatString.getValue());
  437. fmt.parse(inputTime.getValue());
  438. java.util.Calendar cal = fmt.getCalendar();
  439. // The value for zone offset comes back in milliseconds. The number of
  440. // hours is thus milliseconds / 1000 (to get to seconds) / 60 (to get to minutes)
  441. // / 60 (to get to hours). Minutes is this except for the last division,
  442. // but then we use mod 60 since this gives us total # of minutes, including
  443. // the hours we have already computed.
  444. int zoneHours = cal.get(Calendar.ZONE_OFFSET) / (1000 * 60 * 60);
  445. int zoneMinutes = (cal.get(Calendar.ZONE_OFFSET) / (1000 * 60)) % 60;
  446. return values.time(cal.get(Calendar.HOUR_OF_DAY), cal.get(Calendar.MINUTE), cal.get(Calendar.SECOND), cal.get(Calendar.MILLISECOND), zoneHours, zoneMinutes);
  447. } catch (IllegalArgumentException iae) {
  448. throw RuntimeExceptionFactory.dateTimeParsingError("Cannot parse input date: " + inputTime.getValue() +
  449. " using format string: " + formatString.getValue(), null, null);
  450. } catch (ParseException e) {
  451. throw RuntimeExceptionFactory.dateTimeParsingError("Cannot parse input date: " + inputTime.getValue() +
  452. " using format string: " + formatString.getValue(), null, null);
  453. }
  454. }
  455. public IValue parseTimeInLocale(IString inputTime, IString formatString, IString locale)
  456. //@doc{Parse an input time given as a string using a specific locale and format string}
  457. {
  458. try {
  459. java.text.SimpleDateFormat fmt = new java.text.SimpleDateFormat(formatString.getValue(), new Locale(locale.getValue()));
  460. fmt.parse(inputTime.getValue());
  461. java.util.Calendar cal = fmt.getCalendar();
  462. // The value for zone offset comes back in milliseconds. The number of
  463. // hours is thus milliseconds / 1000 (to get to seconds) / 60 (to get to minutes)
  464. // / 60 (to get to hours). Minutes is this except for the last division,
  465. // but then we use mod 60 since this gives us total # of minutes, including
  466. // the hours we have already computed.
  467. int zoneHours = cal.get(Calendar.ZONE_OFFSET) / (1000 * 60 * 60);
  468. int zoneMinutes = (cal.get(Calendar.ZONE_OFFSET) / (1000 * 60)) % 60;
  469. return values.time(cal.get(Calendar.HOUR_OF_DAY), cal.get(Calendar.MINUTE), cal.get(Calendar.SECOND), cal.get(Calendar.MILLISECOND), zoneHours, zoneMinutes);
  470. } catch (IllegalArgumentException iae) {
  471. throw RuntimeExceptionFactory.dateTimeParsingError("Cannot parse input time: " + inputTime.getValue() +
  472. " using format string: " + formatString.getValue() + " in locale: " + locale.getValue(), null, null);
  473. } catch (ParseException e) {
  474. throw RuntimeExceptionFactory.dateTimeParsingError("Cannot parse input time: " + inputTime.getValue() +
  475. " using format string: " + formatString.getValue() + " in locale: " + locale.getValue(), null, null);
  476. }
  477. }
  478. public IValue parseDateTime(IString inputDateTime, IString formatString)
  479. //@doc{Parse an input datetime given as a string using the given format string}
  480. {
  481. try {
  482. java.text.SimpleDateFormat fmt = new java.text.SimpleDateFormat(formatString.getValue());
  483. fmt.setLenient(false);
  484. fmt.parse(inputDateTime.getValue());
  485. java.util.Calendar cal = fmt.getCalendar();
  486. int zoneHours = cal.get(Calendar.ZONE_OFFSET) / (1000 * 60 * 60);
  487. int zoneMinutes = (cal.get(Calendar.ZONE_OFFSET) / (1000 * 60)) % 60;
  488. 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);
  489. } catch (IllegalArgumentException iae) {
  490. throw RuntimeExceptionFactory.dateTimeParsingError("Cannot parse input datetime: " + inputDateTime.getValue() +
  491. " using format string: " + formatString.getValue(), null, null);
  492. } catch (ParseException e) {
  493. throw RuntimeExceptionFactory.dateTimeParsingError("Cannot parse input datetime: " + inputDateTime.getValue() +
  494. " using format string: " + formatString.getValue(), null, null);
  495. }
  496. }
  497. public IValue parseDateTimeInLocale(IString inputDateTime, IString formatString, IString locale)
  498. //@doc{Parse an input datetime given as a string using a specific locale and format string}
  499. {
  500. try {
  501. java.text.SimpleDateFormat fmt = new java.text.SimpleDateFormat(formatString.getValue(), new Locale(locale.getValue()));
  502. fmt.parse(inputDateTime.getValue());
  503. java.util.Calendar cal = fmt.getCalendar();
  504. int zoneHours = cal.get(Calendar.ZONE_OFFSET) / (1000 * 60 * 60);
  505. int zoneMinutes = (cal.get(Calendar.ZONE_OFFSET) / (1000 * 60)) % 60;
  506. 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);
  507. } catch (IllegalArgumentException iae) {
  508. throw RuntimeExceptionFactory.dateTimeParsingError("Cannot parse input datetime: " + inputDateTime.getValue() +
  509. " using format string: " + formatString.getValue() + " in locale: " + locale.getValue(), null, null);
  510. } catch (ParseException e) {
  511. throw RuntimeExceptionFactory.dateTimeParsingError("Cannot parse input datetime: " + inputDateTime.getValue() +
  512. " using format string: " + formatString.getValue() + " in locale: " + locale.getValue(), null, null);
  513. }
  514. }
  515. private Calendar getCalendarForDate(IDateTime inputDate) {
  516. if (inputDate.isDate() || inputDate.isDateTime()) {
  517. Calendar cal = Calendar.getInstance(TimeZone.getDefault(),Locale.getDefault());
  518. cal.setLenient(false);
  519. cal.set(inputDate.getYear(), inputDate.getMonthOfYear()-1, inputDate.getDayOfMonth());
  520. return cal;
  521. } else {
  522. throw new IllegalArgumentException("Cannot get date for a datetime that only represents the time");
  523. }
  524. }
  525. private Calendar getCalendarForTime(IDateTime inputTime) {
  526. if (inputTime.isTime() || inputTime.isDateTime()) {
  527. Calendar cal = Calendar.getInstance(TimeZone.getTimeZone(getTZString(inputTime.getTimezoneOffsetHours(),inputTime.getTimezoneOffsetMinutes())),Locale.getDefault());
  528. cal.setLenient(false);
  529. cal.set(Calendar.HOUR_OF_DAY, inputTime.getHourOfDay());
  530. cal.set(Calendar.MINUTE, inputTime.getMinuteOfHour());
  531. cal.set(Calendar.SECOND, inputTime.getSecondOfMinute());
  532. cal.set(Calendar.MILLISECOND, inputTime.getMillisecondsOfSecond());
  533. return cal;
  534. } else {
  535. throw new IllegalArgumentException("Cannot get time for a datetime that only represents the date");
  536. }
  537. }
  538. private Calendar getCalendarForDateTime(IDateTime inputDateTime) {
  539. if (inputDateTime.isDateTime()) {
  540. Calendar cal = Calendar.getInstance(TimeZone.getTimeZone(getTZString(inputDateTime.getTimezoneOffsetHours(),inputDateTime.getTimezoneOffsetMinutes())),Locale.getDefault());
  541. cal.setLenient(false);
  542. cal.set(inputDateTime.getYear(), inputDateTime.getMonthOfYear()-1, inputDateTime.getDayOfMonth(), inputDateTime.getHourOfDay(), inputDateTime.getMinuteOfHour(), inputDateTime.getSecondOfMinute());
  543. cal.set(Calendar.MILLISECOND, inputDateTime.getMillisecondsOfSecond());
  544. return cal;
  545. } else {
  546. throw new IllegalArgumentException("Cannot get date and time for a datetime that only represents the date or the time");
  547. }
  548. }
  549. public IValue printDate(IDateTime inputDate, IString formatString)
  550. //@doc{Print an input date using the given format string}
  551. {
  552. try {
  553. SimpleDateFormat sd = new SimpleDateFormat(formatString.getValue());
  554. Calendar cal = getCalendarForDate(inputDate);
  555. sd.setCalendar(cal);
  556. return values.string(sd.format(cal.getTime()));
  557. } catch (IllegalArgumentException iae) {
  558. throw RuntimeExceptionFactory.dateTimePrintingError("Cannot print time with format " + formatString.getValue(), null, null);
  559. }
  560. }
  561. public IValue printDate(IDateTime inputDate)
  562. //@doc{Print an input date using a default format string}
  563. {
  564. SimpleDateFormat sd = new SimpleDateFormat("yyyy-MM-dd");
  565. Calendar cal = getCalendarForDate(inputDate);
  566. sd.setCalendar(cal);
  567. return values.string(sd.format(cal.getTime()));
  568. }
  569. public IValue printDateInLocale(IDateTime inputDate, IString formatString, IString locale)
  570. //@doc{Print an input date using a specific locale and format string}
  571. {
  572. try {
  573. SimpleDateFormat sd = new SimpleDateFormat(formatString.getValue(),new ULocale(locale.getValue()));
  574. Calendar cal = getCalendarForDate(inputDate);
  575. sd.setCalendar(cal);
  576. return values.string(sd.format(cal.getTime()));
  577. } catch (IllegalArgumentException iae) {
  578. throw RuntimeExceptionFactory.dateTimePrintingError("Cannot print time with format " + formatString.getValue() + ", in locale: " + locale.getValue(), null, null);
  579. }
  580. }
  581. public IValue printDateInLocale(IDateTime inputDate, IString locale)
  582. //@doc{Print an input date using a specific locale and a default format string}
  583. {
  584. try {
  585. SimpleDateFormat sd = new SimpleDateFormat("yyyy-MM-dd",new ULocale(locale.getValue()));
  586. Calendar cal = getCalendarForDate(inputDate);
  587. sd.setCalendar(cal);
  588. return values.string(sd.format(cal.getTime()));
  589. } catch (IllegalArgumentException iae) {
  590. throw RuntimeExceptionFactory.dateTimePrintingError("Cannot print time in locale: " + locale.getValue(), null, null);
  591. }
  592. }
  593. public IValue printTime(IDateTime inputTime, IString formatString)
  594. //@doc{Print an input time using the given format string}
  595. {
  596. try {
  597. SimpleDateFormat sd = new SimpleDateFormat(formatString.getValue());
  598. Calendar cal = getCalendarForTime(inputTime);
  599. sd.setCalendar(cal);
  600. return values.string(sd.format(cal.getTime()));
  601. } catch (IllegalArgumentException iae) {
  602. throw RuntimeExceptionFactory.dateTimePrintingError("Cannot print time with format: " + formatString.getValue(), null, null);
  603. }
  604. }
  605. public IValue printTime(IDateTime inputTime)
  606. //@doc{Print an input time using a default format string}
  607. {
  608. SimpleDateFormat sd = new SimpleDateFormat("HH:mm:ss.SSSZ");
  609. Calendar cal = getCalendarForTime(inputTime);
  610. sd.setCalendar(cal);
  611. return values.string(sd.format(cal.getTime()));
  612. }
  613. public IValue printTimeInLocale(IDateTime inputTime, IString formatString, IString locale)
  614. //@doc{Print an input time using a specific locale and format string}
  615. {
  616. try {
  617. SimpleDateFormat sd = new SimpleDateFormat(formatString.getValue(),new ULocale(locale.getValue()));
  618. Calendar cal = getCalendarForTime(inputTime);
  619. sd.setCalendar(cal);
  620. return values.string(sd.format(cal.getTime()));
  621. } catch (IllegalArgumentException iae) {
  622. throw RuntimeExceptionFactory.dateTimePrintingError("Cannot print time in locale: " + locale.getValue(), null, null);
  623. }
  624. }
  625. public IValue printTimeInLocale(IDateTime inputTime, IString locale)
  626. //@doc{Print an input time using a specific locale and a default format string}
  627. {
  628. try {
  629. SimpleDateFormat sd = new SimpleDateFormat("HH:mm:ss.SSSZ",new ULocale(locale.getValue()));
  630. Calendar cal = getCalendarForTime(inputTime);
  631. sd.setCalendar(cal);
  632. return values.string(sd.format(cal.getTime()));
  633. } catch (IllegalArgumentException iae) {
  634. throw RuntimeExceptionFactory.dateTimePrintingError("Cannot print time in locale: " + locale.getValue(), null, null);
  635. }
  636. }
  637. public IValue printDateTime(IDateTime inputDateTime, IString formatString)
  638. //@doc{Print an input datetime using the given format string}
  639. {
  640. try {
  641. SimpleDateFormat sd = new SimpleDateFormat(formatString.getValue());
  642. Calendar cal = getCalendarForDateTime(inputDateTime);
  643. sd.setCalendar(cal);
  644. return values.string(sd.format(cal.getTime()));
  645. } catch (IllegalArgumentException iae) {
  646. throw RuntimeExceptionFactory.dateTimePrintingError("Cannot print datetime using format string: " + formatString.getValue(), null, null);
  647. }
  648. }
  649. public IValue printDateTime(IDateTime inputDateTime)
  650. //@doc{Print an input datetime using a default format string}
  651. {
  652. SimpleDateFormat sd = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSZ");
  653. Calendar cal = getCalendarForDateTime(inputDateTime);
  654. sd.setCalendar(cal);
  655. return values.string(sd.format(cal.getTime()));
  656. }
  657. public IValue printDateTimeInLocale(IDateTime inputDateTime, IString formatString, IString locale)
  658. //@doc{Print an input datetime using a specific locale and format string}
  659. {
  660. try {
  661. SimpleDateFormat sd = new SimpleDateFormat(formatString.getValue(),new ULocale(locale.getValue()));
  662. Calendar cal = getCalendarForDateTime(inputDateTime);
  663. sd.setCalendar(cal);
  664. return values.string(sd.format(cal.getTime()));
  665. } catch (IllegalArgumentException iae) {
  666. throw RuntimeExceptionFactory.dateTimePrintingError("Cannot print datetime using format string: " + formatString.getValue() +
  667. " in locale: " + locale.getValue(), null, null);
  668. }
  669. }
  670. public IValue printDateTimeInLocale(IDateTime inputDateTime, IString locale)
  671. //@doc{Print an input datetime using a specific locale and a default format string}
  672. {
  673. try {
  674. SimpleDateFormat sd = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSZ",new ULocale(locale.getValue()));
  675. Calendar cal = getCalendarForDateTime(inputDateTime);
  676. sd.setCalendar(cal);
  677. return values.string(sd.format(cal.getTime()));
  678. } catch (IllegalArgumentException iae) {
  679. throw RuntimeExceptionFactory.dateTimePrintingError("Cannot print datetime in locale: " + locale.getValue(), null, null);
  680. }
  681. }
  682. /*
  683. * Graph
  684. */
  685. private HashMap<IValue,Distance> distance;
  686. private HashMap<IValue, IValue> pred;
  687. private HashSet<IValue> settled;
  688. private PriorityQueue<IValue> Q;
  689. private int MAXDISTANCE = 10000;
  690. private HashMap<IValue, LinkedList<IValue>> adjacencyList;
  691. private void buildAdjacencyListAndDistance(IRelation G){
  692. adjacencyList = new HashMap<IValue, LinkedList<IValue>> ();
  693. distance = new HashMap<IValue, Distance>();
  694. for(IValue v : G){
  695. ITuple tup = (ITuple) v;
  696. IValue from = tup.get(0);
  697. IValue to = tup.get(1);
  698. if(distance.get(from) == null)
  699. distance.put(from, new Distance(MAXDISTANCE));
  700. if(distance.get(to) == null)
  701. distance.put(to, new Distance(MAXDISTANCE));
  702. LinkedList<IValue> adjacencies = adjacencyList.get(from);
  703. if(adjacencies == null)
  704. adjacencies = new LinkedList<IValue>();
  705. adjacencies.add(to);
  706. adjacencyList.put(from, adjacencies);
  707. }
  708. }
  709. public IValue shortestPathPair(IRelation G, IValue From, IValue To){
  710. buildAdjacencyListAndDistance(G);
  711. distance.put(From, new Distance(0));
  712. pred = new HashMap<IValue, IValue>();
  713. settled = new HashSet<IValue>();
  714. Q = new PriorityQueue<IValue>(G.size(), new NodeComparator(distance));
  715. Q.add(From);
  716. while(!Q.isEmpty()){
  717. IValue u = Q.remove();
  718. if(u.isEqual(To))
  719. return extractPath(From, u);
  720. settled.add(u);
  721. relaxNeighbours(u);
  722. }
  723. return values.list();
  724. }
  725. private void relaxNeighbours(IValue u){
  726. LinkedList<IValue> adjacencies = adjacencyList.get(u);
  727. if(adjacencies != null) {
  728. for(IValue v : adjacencyList.get(u)){
  729. if(!settled.contains(v)){
  730. Distance dv = distance.get(v);
  731. Distance du = distance.get(u);
  732. if(dv.intval > du.intval + 1){ // 1 is default weight of each edge
  733. dv.intval = du.intval + 1;
  734. pred.put(v,u);
  735. Q.add(v);
  736. }
  737. }
  738. }
  739. }
  740. }
  741. private IList extractPath(IValue start, IValue u){
  742. Type listType = types.listType(start.getType());
  743. IListWriter w = listType.writer(values);
  744. if(!start.isEqual(u)){
  745. w.insert(u);
  746. while(!pred.get(u).isEqual(start)){
  747. u = pred.get(u);
  748. w.insert(u);
  749. }
  750. // TODO Check if a path was found at all; it could be that we just hit the root of the graph.
  751. }
  752. w.insert(start);
  753. return w.done();
  754. }
  755. public void print(IValue arg, IEvaluatorContext eval){
  756. PrintWriter currentOutStream = eval.getStdOut();
  757. try{
  758. if(arg.getType().isStringType()){
  759. currentOutStream.print(((IString) arg).getValue().toString());
  760. }
  761. else if(arg.getType().isSubtypeOf(Factory.Tree)){
  762. currentOutStream.print(TreeAdapter.yield((IConstructor) arg));
  763. }
  764. else if (arg.getType().isSubtypeOf(Factory.Type)) {
  765. currentOutStream.print(SymbolAdapter.toString((IConstructor) ((IConstructor) arg).get("symbol")));
  766. }
  767. else{
  768. currentOutStream.print(arg.toString());
  769. }
  770. }finally{
  771. currentOutStream.flush();
  772. }
  773. }
  774. public void iprint(IValue arg, IEvaluatorContext eval){
  775. StandardTextWriter w = new StandardTextWriter(true, 2);
  776. try {
  777. w.write(arg, eval.getStdOut());
  778. }
  779. catch (IOException e) {
  780. RuntimeExceptionFactory.io(values.string("Could not print indented value"), eval.getCurrentAST(), eval.getStackTrace());
  781. }
  782. finally{
  783. eval.getStdOut().flush();
  784. }
  785. }
  786. public void iprintln(IValue arg, IEvaluatorContext eval){
  787. StandardTextWriter w = new StandardTextWriter(true, 2);
  788. try {
  789. w.write(arg, eval.getStdOut());
  790. eval.getStdOut().println();
  791. }
  792. catch (IOException e) {
  793. RuntimeExceptionFactory.io(values.string("Could not print indented value"), eval.getCurrentAST(), eval.getStackTrace());
  794. }
  795. finally{
  796. eval.getStdOut().flush();
  797. }
  798. }
  799. public void println(IEvaluatorContext eval) {
  800. eval.getStdOut().println();
  801. eval.getStdOut().flush();
  802. }
  803. public void println(IValue arg, IEvaluatorContext eval){
  804. PrintWriter currentOutStream = eval.getStdOut();
  805. try{
  806. if(arg.getType().isStringType()){
  807. currentOutStream.print(((IString) arg).getValue());
  808. }
  809. else if(arg.getType().isSubtypeOf(Factory.Tree)){
  810. currentOutStream.print(TreeAdapter.yield((IConstructor) arg));
  811. }
  812. else if (arg.getType().isSubtypeOf(Factory.Type)) {
  813. currentOutStream.print(SymbolAdapter.toString((IConstructor) ((IConstructor) arg).get("symbol")));
  814. }
  815. else{
  816. currentOutStream.print(arg.toString());
  817. }
  818. currentOutStream.println();
  819. }finally{
  820. currentOutStream.flush();
  821. }
  822. }
  823. public void rprintln(IValue arg, IEvaluatorContext eval){
  824. PrintWriter currentOutStream = eval.getStdOut();
  825. try{
  826. currentOutStream.print(arg.toString());
  827. currentOutStream.println();
  828. }finally{
  829. currentOutStream.flush();
  830. }
  831. }
  832. public void rprint(IValue arg, IEvaluatorContext eval){
  833. PrintWriter currentOutStream = eval.getStdOut();
  834. try{
  835. currentOutStream.print(arg.toString());
  836. }finally{
  837. currentOutStream.flush();
  838. }
  839. }
  840. @Deprecated
  841. public IValue readFile(IString filename){
  842. IListWriter w = types.listType(types.stringType()).writer(values);
  843. BufferedReader in = null;
  844. try{
  845. in = new BufferedReader(new FileReader(filename.getValue()));
  846. java.lang.String line;
  847. do {
  848. line = in.readLine();
  849. if(line != null){
  850. w.append(values.string(line));
  851. }
  852. } while (line != null);
  853. }catch(FileNotFoundException fnfex){
  854. throw RuntimeExceptionFactory.pathNotFound(values.sourceLocation(filename.getValue()), null, null);
  855. }catch(IOException ioex){
  856. throw RuntimeExceptionFactory.io(values.string(ioex.getMessage()), null, null);
  857. }finally{
  858. if(in != null){
  859. try{
  860. in.close();
  861. }catch(IOException ioex){
  862. throw RuntimeExceptionFactory.io(values.string(ioex.getMessage()), null, null);
  863. }
  864. }
  865. }
  866. return w.done();
  867. }
  868. public IValue exists(ISourceLocation sloc, IEvaluatorContext ctx) {
  869. return values.bool(ctx.getResolverRegistry().exists(sloc.getURI()));
  870. }
  871. public IValue lastModified(ISourceLocation sloc, IEvaluatorContext ctx) {
  872. try {
  873. return values.datetime(ctx.getResolverRegistry().lastModified(sloc.getURI()));
  874. } catch(FileNotFoundException e){
  875. throw RuntimeExceptionFactory.pathNotFound(sloc, null, null);
  876. }
  877. catch (IOException e) {
  878. throw RuntimeExceptionFactory.io(values.string(e.getMessage()), ctx.getCurrentAST(), ctx.getStackTrace());
  879. }
  880. }
  881. public IValue isDirectory(ISourceLocation sloc, IEvaluatorContext ctx) {
  882. return values.bool(ctx.getResolverRegistry().isDirectory(sloc.getURI()));
  883. }
  884. public IValue isFile(ISourceLocation sloc, IEvaluatorContext ctx) {
  885. return values.bool(ctx.getResolverRegistry().isFile(sloc.getURI()));
  886. }
  887. public void mkDirectory(ISourceLocation sloc, IEvaluatorContext ctx) throws IOException {
  888. ctx.getResolverRegistry().mkDirectory(sloc.getURI());
  889. }
  890. public IValue listEntries(ISourceLocation sloc, IEvaluatorContext ctx) {
  891. try {
  892. java.lang.String [] entries = ctx.getResolverRegistry().listEntries(sloc.getURI());
  893. IListWriter w = values.listWriter(types.stringType());
  894. for(java.lang.String entry : entries){
  895. w.append(values.string(entry));
  896. }
  897. return w.done();
  898. } catch(FileNotFoundException e){
  899. throw RuntimeExceptionFactory.pathNotFound(sloc, ctx.getCurrentAST(), null);
  900. } catch (IOException e) {
  901. throw RuntimeExceptionFactory.io(values.string(e.getMessage()), ctx.getCurrentAST(), ctx.getStackTrace());
  902. }
  903. }
  904. public ISet charsets() {
  905. ISetWriter w = values.setWriter();
  906. for (String s : Charset.availableCharsets().keySet()) {
  907. w.insert(values.string(s));
  908. }
  909. return w.done();
  910. }
  911. public IValue readFile(ISourceLocation sloc, IEvaluatorContext ctx){
  912. try {
  913. Charset c = ctx.getResolverRegistry().getCharset(sloc.getURI());
  914. if (c != null)
  915. return readFileEnc(sloc, values.string(c.name()), ctx);
  916. return consumeInputStream(sloc, ctx.getResolverRegistry().getCharacterReader(sloc.getURI()), ctx);
  917. } catch(FileNotFoundException e){
  918. throw RuntimeExceptionFactory.pathNotFound(sloc, ctx.getCurrentAST(), null);
  919. }
  920. catch (IOException e) {
  921. throw RuntimeExceptionFactory.io(values.string(e.getMessage()), null, null);
  922. }
  923. }
  924. public IValue readFileEnc(ISourceLocation sloc, IString charset, IEvaluatorContext ctx){
  925. try {
  926. return consumeInputStream(sloc, ctx.getResolverRegistry().getCharacterReader(sloc.getURI(), charset.getValue()), ctx);
  927. } catch(FileNotFoundException e){
  928. throw RuntimeExceptionFactory.pathNotFound(sloc, ctx.getCurrentAST(), null);
  929. } catch (IOException e) {
  930. throw RuntimeExceptionFactory.io(values.string(e.getMessage()), null, null);
  931. }
  932. }
  933. private IValue consumeInputStream(ISourceLocation sloc, Reader in, IEvaluatorContext ctx) {
  934. StringBuilder result = new StringBuilder(1024 * 1024);
  935. try{
  936. char[] buf = new char[4096];
  937. int count;
  938. while((count = in.read(buf)) != -1) {
  939. result.append(new java.lang.String(buf, 0, count));
  940. }
  941. java.lang.String str = result.toString();
  942. if(sloc.hasOffsetLength() && sloc.getOffset() != -1){
  943. str = str.substring(sloc.getOffset(), sloc.getOffset() + sloc.getLength());
  944. }
  945. return values.string(str);
  946. }catch(FileNotFoundException fnfex){
  947. throw RuntimeExceptionFactory.pathNotFound(sloc, ctx.getCurrentAST(), null);
  948. }catch(IOException ioex){
  949. throw RuntimeExceptionFactory.io(values.string(ioex.getMessage()), ctx.getCurrentAST(), null);
  950. }finally{
  951. if(in != null){
  952. try{
  953. in.close();
  954. }catch(IOException ioex){
  955. throw RuntimeExceptionFactory.io(values.string(ioex.getMessage()), ctx.getCurrentAST(), null);
  956. }
  957. }
  958. }
  959. }
  960. public IValue md5HashFile(ISourceLocation sloc, IEvaluatorContext ctx){
  961. StringBuilder result = new StringBuilder(1024 * 1024);
  962. InputStream in = null;
  963. try{
  964. in = ctx.getResolverRegistry().getInputStream(sloc.getURI());
  965. MessageDigest md = MessageDigest.getInstance("MD5");
  966. in = new DigestInputStream(in, md);
  967. byte[] buf = new byte[4096];
  968. int count;
  969. while((count = in.read(buf)) != -1){
  970. result.append(new java.lang.String(buf, 0, count));
  971. }
  972. return values.string(new String(md.digest()));
  973. }catch(FileNotFoundException fnfex){
  974. throw RuntimeExceptionFactory.pathNotFound(sloc, ctx.getCurrentAST(), null);
  975. }catch(IOException ioex){
  976. throw RuntimeExceptionFactory.io(values.string(ioex.getMessage()), ctx.getCurrentAST(), null);
  977. } catch (NoSuchAlgorithmException e) {
  978. throw RuntimeExceptionFactory.io(values.string("Cannot load MD5 digest algorithm"), ctx.getCurrentAST(), null);
  979. }finally{
  980. if(in != null){
  981. try{
  982. in.close();
  983. }catch(IOException ioex){
  984. throw RuntimeExceptionFactory.io(values.string(ioex.getMessage()), ctx.getCurrentAST(), null);
  985. }
  986. }
  987. }
  988. }
  989. public void writeFile(ISourceLocation sloc, IList V, IEvaluatorContext ctx) {
  990. writeFile(sloc, V, false, ctx);
  991. }
  992. public void writeFileEnc(ISourceLocation sloc, IString charset, IList V, IEvaluatorContext ctx) {
  993. writeFileEnc(sloc, charset, V, false, ctx);
  994. }
  995. private void writeFile(ISourceLocation sloc, IList V, boolean append, IEvaluatorContext ctx){
  996. IString charset = values.string("UTF8");
  997. if (append) {
  998. // in case the file already has a encoding, we have to correctly append that.
  999. InputStream in = null;
  1000. Charset detected = null;
  1001. try {
  1002. detected = ctx.getResolverRegistry().getCharset(sloc.getURI());
  1003. if (detected == null) {
  1004. in = ctx.getResolverRegistry().getInputStream(sloc.getURI());
  1005. detected = UnicodeDetector.estimateCharset(in);
  1006. }
  1007. }catch(FileNotFoundException fnfex){
  1008. throw RuntimeExceptionFactory.pathNotFound(sloc, ctx.getCurrentAST(), null);
  1009. } catch (IOException e) {
  1010. throw RuntimeExceptionFactory.io(values.string(e.getMessage()), ctx.getCurrentAST(), null);
  1011. }
  1012. finally {
  1013. if (in != null) {
  1014. try {
  1015. in.close();
  1016. } catch (IOException e) {
  1017. throw RuntimeExceptionFactory.io(values.string(e.getMessage()), ctx.getCurrentAST(), null);
  1018. }
  1019. }
  1020. }
  1021. if (detected != null)
  1022. charset = values.string(detected.name());
  1023. else {
  1024. charset = values.string(Charset.defaultCharset().name());
  1025. }
  1026. }
  1027. writeFileEnc(sloc, charset, V, append, ctx);
  1028. }
  1029. public IBool canEncode(IString charset) {
  1030. return values.bool(Charset.forName(charset.getValue()).canEncode());
  1031. }
  1032. private void writeFileEnc(ISourceLocation sloc, IString charset, IList V, boolean append, IEvaluatorContext ctx){
  1033. OutputStreamWriter out = null;
  1034. if (!Charset.forName(charset.getValue()).canEncode()) {
  1035. throw RuntimeExceptionFactory.illegalArgument(charset, null, null);
  1036. }
  1037. try{
  1038. out = new UnicodeOutputStreamWriter(ctx.getResolverRegistry().getOutputStream(sloc.getURI(), append), charset.getValue(), append);
  1039. for(IValue elem : V){
  1040. if (elem.getType().isStringType()) {
  1041. out.append(((IString) elem).getValue());
  1042. }else if (elem.getType().isSubtypeOf(Factory.Tree)) {
  1043. out.append(TreeAdapter.yield((IConstructor) elem));
  1044. }else{
  1045. out.append(elem.toString());
  1046. }
  1047. }
  1048. }catch(FileNotFoundException fnfex){
  1049. throw RuntimeExceptionFactory.pathNotFound(sloc, ctx.getCurrentAST(), null);
  1050. }catch(IOException ioex){
  1051. throw RuntimeExceptionFactory.io(values.string(ioex.getMessage()), ctx.getCurrentAST(), null);
  1052. }finally{
  1053. if(out != null){
  1054. try{
  1055. out.close();
  1056. }catch(IOException ioex){
  1057. throw RuntimeExceptionFactory.io(values.string(ioex.getMessage()), ctx.getCurrentAST(), null);
  1058. }
  1059. }
  1060. }
  1061. return;
  1062. }
  1063. public void appendToFile(ISourceLocation sloc, IList V, IEvaluatorContext ctx){
  1064. writeFile(sloc, V, true, ctx);
  1065. }
  1066. public void appendToFileEnc(ISourceLocation sloc, IString charset, IList V, IEvaluatorContext ctx){
  1067. writeFileEnc(sloc, charset, V, true, ctx);
  1068. }
  1069. public IList readFileLines(ISourceLocation sloc, IEvaluatorContext ctx){
  1070. try {
  1071. Charset detected = ctx.getResolverRegistry().getCharset(sloc.getURI());
  1072. if (detected != null)
  1073. return readFileLinesEnc(sloc, values.string(detected.name()), ctx);
  1074. return consumeInputStreamLines(sloc, ctx.getResolverRegistry().getCharacterReader(sloc.getURI()), ctx);
  1075. }catch(MalformedURLException e){
  1076. throw RuntimeExceptionFactory.malformedURI(sloc.toString(), null, null);
  1077. }catch(FileNotFoundException e){
  1078. throw RuntimeExceptionFactory.pathNotFound(sloc, ctx.getCurrentAST(), null);
  1079. }catch(IOException e){
  1080. throw RuntimeExceptionFactory.io(values.string(e.getMessage()), ctx.getCurrentAST(), null);
  1081. }
  1082. }
  1083. public IList readFileLinesEnc(ISourceLocation sloc, IString charset, IEvaluatorContext ctx){
  1084. try {
  1085. return consumeInputStreamLines(sloc, ctx.getResolverRegistry().getCharacterReader(sloc.getURI(),charset.getValue()), ctx);
  1086. }catch(MalformedURLException e){
  1087. throw RuntimeExceptionFactory.malformedURI(sloc.toString(), null, null);
  1088. }catch(FileNotFoundException e){
  1089. throw RuntimeExceptionFactory.pathNotFound(sloc, ctx.getCurrentAST(), null);
  1090. }catch(IOException e){
  1091. throw RuntimeExceptionFactory.io(values.string(e.getMessage()), ctx.getCurrentAST(), null);
  1092. }
  1093. }
  1094. private IList consumeInputStreamLines(ISourceLocation sloc, Reader stream, IEvaluatorContext ctx ) {
  1095. IListWriter w = types.listType(types.stringType()).writer(values);
  1096. BufferedReader in = null;
  1097. try{
  1098. in = new BufferedReader(stream);
  1099. java.lang.String line;
  1100. int i = 0;
  1101. // int offset = sloc.getOffset();
  1102. int beginLine = sloc.hasLineColumn() ? sloc.getBeginLine() : -1;
  1103. int beginColumn = sloc.hasLineColumn() ? sloc.getBeginColumn() : -1;
  1104. int endLine = sloc.hasLineColumn() ? sloc.getEndLine() : -1;
  1105. int endColumn = sloc.hasLineColumn() ? sloc.getEndColumn() : -1;
  1106. do{
  1107. line = in.readLine();
  1108. i++;
  1109. if(line != null){
  1110. if(!sloc.hasOffsetLength()){
  1111. w.append(values.string(line));
  1112. }else{
  1113. if(!sloc.hasLineColumn()){
  1114. endColumn = line.length();
  1115. }
  1116. if(i == beginLine){
  1117. if(i == endLine){
  1118. w.append(values.string(line.substring(beginColumn, endColumn)));
  1119. }else{
  1120. w.append(values.string(line.substring(beginColumn)));
  1121. }
  1122. }else if(i > beginLine){
  1123. if(i == endLine){
  1124. w.append(values.string(line.substring(0, endColumn)));
  1125. }
  1126. else if(i < endLine){
  1127. w.append(values.string(line));
  1128. }
  1129. }
  1130. }
  1131. }
  1132. }while(line != null);
  1133. }catch(IOException e){
  1134. throw RuntimeExceptionFactory.io(values.string(e.getMessage()), ctx.getCurrentAST(), null);
  1135. }finally{
  1136. if(in != null){
  1137. try{
  1138. in.close();
  1139. }catch(IOException ioex){
  1140. throw RuntimeExceptionFactory.io(values.string(ioex.getMessage()), ctx.getCurrentAST(), null);
  1141. }
  1142. }
  1143. }
  1144. return w.done();
  1145. }
  1146. public IList readFileBytes(ISourceLocation sloc, IEvaluatorContext ctx){
  1147. IListWriter w = types.listType(types.integerType()).writer(values);
  1148. BufferedInputStream in = null;
  1149. try{
  1150. InputStream stream = ctx.getResolverRegistry().getInputStream(sloc.getURI());
  1151. in = new BufferedInputStream(stream);
  1152. int read;
  1153. final int size = 256;
  1154. byte bytes[] = new byte[size];
  1155. do{
  1156. read = in.read(bytes);
  1157. for (int i = 0; i < read; i++) {
  1158. w.append(values.integer(bytes[i] & 0xff));
  1159. }
  1160. }while(read != -1);
  1161. }catch(FileNotFoundException e){
  1162. throw RuntimeExceptionFactory.pathNotFound(sloc, ctx.getCurrentAST(), null);
  1163. }catch(IOException e){
  1164. throw RuntimeExceptionFactory.io(values.string(e.getMessage()), ctx.getCurrentAST(), null);
  1165. }finally{
  1166. if(in != null){
  1167. try{
  1168. in.close();
  1169. }catch(IOException ioex){
  1170. throw RuntimeExceptionFactory.io(values.string(ioex.getMessage()), ctx.getCurrentAST(), null);
  1171. }
  1172. }
  1173. }
  1174. return w.done();
  1175. }
  1176. public IString createLink(IString title, IString target) {
  1177. return values.string("\uE007["+title.getValue().replaceAll("\\]", "_")+"]("+target.getValue()+")");
  1178. }
  1179. /*
  1180. * List
  1181. */
  1182. private WeakReference<IList> indexes;
  1183. /**
  1184. * A mini class to wrap a lessThan function
  1185. */
  1186. private class Less {
  1187. private final ICallableValue less;
  1188. private final IValue[] args = new IValue[2];
  1189. private final Type[] types = new Type[2];
  1190. Less(ICallableValue less) {
  1191. this.less = less;
  1192. FunctionType func = (FunctionType) less.getType();
  1193. types[0] = func.getArgumentTypes().getFieldType(0);
  1194. types[1] = func.getArgumentTypes().getFieldType(1);
  1195. }
  1196. public boolean less(IValue x, IValue y) {
  1197. args[0] = x;
  1198. args[1] = y;
  1199. return ((IBool) less.call(types, args, null).getValue()).getValue();
  1200. }
  1201. }
  1202. private class Sorting {
  1203. private final IValue[] array;
  1204. private final int size;
  1205. private final Less less;
  1206. private void swap(int i, int j) {
  1207. IValue tmp = array[i];
  1208. array[i] = array[j];
  1209. array[j] = tmp;
  1210. }
  1211. public Sorting(IValue[] array, Less less) {
  1212. this.array = array;
  1213. this.size = array.length;
  1214. this.less = less;
  1215. }
  1216. /**
  1217. * @throws IllegalArgument if comparator is illegal (i.e., if pivot equals pivot)
  1218. */
  1219. public Sorting sort() {
  1220. if (size == 0) {
  1221. return this;
  1222. }
  1223. if(less.less(array[0], array[0])) {
  1224. throw RuntimeExceptionFactory.illegalArgument(less.less, null, null, "Bad comparator: Did you use less-or-equals instead of less-than?");
  1225. }
  1226. sort(0, size - 1);
  1227. return this;
  1228. }
  1229. public Sorting shuffle() {
  1230. for (int i = 0; i < size; i++) {
  1231. swap(i, i + (int) (Math.random() * (size-i)));
  1232. }
  1233. return this;
  1234. }
  1235. private void sort(int low, int high) {
  1236. IValue pivot = array[low + (high-low)/2];
  1237. int oldLow = low;
  1238. int oldHigh = high;
  1239. while (low < high) {
  1240. for ( ; less.less(array[low], pivot); low++);
  1241. for ( ; less.less(pivot, array[high]); high--);
  1242. if (low <= high) {
  1243. swap(low, high);
  1244. low++;
  1245. high--;
  1246. }
  1247. }
  1248. if (oldLow < high)
  1249. sort(oldLow, high);
  1250. if (low < oldHigh)
  1251. sort(low, oldHigh);
  1252. }
  1253. }
  1254. public IList sort(IList l, IValue cmpv){
  1255. IValue[] tmpArr = new IValue[l.length()];
  1256. for(int i = 0 ; i < l.length() ; i++){
  1257. tmpArr[i] = l.get(i);
  1258. }
  1259. // we randomly swap some elements to make worst case complexity unlikely
  1260. new Sorting(tmpArr, new Less((ICallableValue) cmpv)).shuffle().sort();
  1261. IListWriter writer = values.listWriter(l.getElementType());
  1262. writer.append(tmpArr);
  1263. return writer.done();
  1264. }
  1265. public IList sort(ISet l, IValue cmpv) {
  1266. IValue[] tmpArr = new IValue[l.size()];
  1267. int i = 0;
  1268. // we assume that the set is reasonably randomly ordered, such
  1269. // that the worst case of quicksort is unlikely
  1270. for (IValue elem : l){
  1271. tmpArr[i++] = elem;
  1272. }
  1273. new Sorting(tmpArr, new Less((ICallableValue) cmpv)).sort();
  1274. IListWriter writer = values.listWriter(l.getElementType());
  1275. for(IValue v : tmpArr){
  1276. writer.append(v);
  1277. }
  1278. return writer.done();
  1279. }
  1280. private IList makeUpTill(int from,int len){
  1281. IListWriter writer = values.listWriter(types.integerType());
  1282. for(int i = from ; i < len; i++){
  1283. writer.append(values.integer(i));
  1284. }
  1285. return writer.done();
  1286. }
  1287. public IValue delete(IList lst, IInteger n)
  1288. // @doc{delete -- delete nth element from list}
  1289. {
  1290. try {
  1291. return lst.delete(n.intValue());
  1292. } catch (IndexOutOfBoundsException e){
  1293. throw RuntimeExceptionFactory.indexOutOfBounds(n, null, null);
  1294. }
  1295. }
  1296. public IValue domain(IList lst)
  1297. //@doc{domain -- a list of all legal index values for a list}
  1298. {
  1299. ISetWriter w = values.setWriter(types.integerType());
  1300. int len = lst.length();
  1301. for (int i = 0; i < len; i++){
  1302. w.insert(values.integer(i));
  1303. }
  1304. return w.done();
  1305. }
  1306. public IValue head(IList lst)
  1307. // @doc{head -- get the first element of a list}
  1308. {
  1309. if(lst.length() > 0){
  1310. return lst.get(0);
  1311. }
  1312. throw RuntimeExceptionFactory.emptyList(null, null);
  1313. }
  1314. public IValue head(IList lst, IInteger n)
  1315. throws IndexOutOfBoundsException
  1316. // @doc{head -- get the first n elements of a list}
  1317. {
  1318. try {
  1319. return lst.sublist(0, n.intValue());
  1320. } catch(IndexOutOfBoundsException e){
  1321. IInteger end = values.integer(n.intValue() - 1);
  1322. throw RuntimeExceptionFactory.indexOutOfBounds(end, null, null);
  1323. }
  1324. }
  1325. public IValue getOneFrom(IList lst)
  1326. //@doc{getOneFrom -- get an arbitrary element from a list}
  1327. {
  1328. int n = lst.length();
  1329. if(n > 0){
  1330. return lst.get(random.nextInt(n));
  1331. }
  1332. throw RuntimeExceptionFactory.emptyList(null, null);
  1333. }
  1334. public IValue insertAt(IList lst, IInteger n, IValue elm)
  1335. throws IndexOutOfBoundsException
  1336. //@doc{insertAt -- add an element at a specific position in a list}
  1337. {
  1338. IListWriter w = values.listWriter(elm.getType().lub(lst.getElementType()));
  1339. int k = n.intValue();
  1340. if(k >= 0 && k <= lst.length()){
  1341. if(k == lst.length()){
  1342. w.insert(elm);
  1343. }
  1344. for(int i = lst.length()-1; i >= 0; i--) {
  1345. w.insert(lst.get(i));
  1346. if(i == k){
  1347. w.insert(elm);
  1348. }
  1349. }
  1350. return w.done();
  1351. }
  1352. throw RuntimeExceptionFactory.indexOutOfBounds(n, null, null);
  1353. }
  1354. public IValue isEmpty(IList lst)
  1355. //@doc{isEmpty -- is list empty?}
  1356. {
  1357. return values.bool(lst.length() == 0);
  1358. }
  1359. public IValue reverse(IList lst)
  1360. //@doc{reverse -- elements of a list in reverse order}
  1361. {
  1362. return lst.reverse();
  1363. }
  1364. public IValue size(IList lst)
  1365. //@doc{size -- number of elements in a list}
  1366. {
  1367. return values.integer(lst.length());
  1368. }
  1369. public IValue slice(IList lst, IInteger start, IInteger len)
  1370. //@doc{slice -- sublist from start of length len}
  1371. {
  1372. try {
  1373. return lst.sublist(start.intValue(), len.intValue());
  1374. } catch (IndexOutOfBoundsException e){
  1375. IInteger end = values.integer(start.intValue() + len.intValue());
  1376. throw RuntimeExceptionFactory.indexOutOfBounds(end, null, null);
  1377. }
  1378. }
  1379. public IValue tail(IList lst)
  1380. //@doc{tail -- all but the first element of a list}
  1381. {
  1382. try {
  1383. return lst.sublist(1, lst.length()-1);
  1384. } catch (IndexOutOfBoundsException e){
  1385. throw RuntimeExceptionFactory.emptyList(null, null);
  1386. }
  1387. }
  1388. public IValue tail(IList lst, IInteger len)
  1389. //@doc{tail -- last n elements of a list}
  1390. {
  1391. int lenVal = len.intValue();
  1392. int lstLen = lst.length();
  1393. try {
  1394. return lst.sublist(lstLen - lenVal, lenVal);
  1395. } catch (IndexOutOfBoundsException e){
  1396. IInteger end = values.integer(lenVal - lstLen);
  1397. throw RuntimeExceptionFactory.indexOutOfBounds(end, null, null);
  1398. }
  1399. }
  1400. public IValue take(IInteger len, IList lst) {
  1401. //@doc{take -- take n elements of from front of a list}
  1402. int lenVal = len.intValue();
  1403. int lstLen = lst.length();
  1404. if(lenVal >= lstLen){
  1405. return lst;
  1406. } else {
  1407. return lst.sublist(0, lenVal);
  1408. }
  1409. }
  1410. public IValue drop(IInteger len, IList lst) {
  1411. //@doc{drop -- remove n elements of from front of a list}
  1412. int lenVal = len.intValue();
  1413. int lstLen = lst.length();
  1414. if(lenVal >= lstLen){
  1415. return values.list();
  1416. } else {
  1417. return lst.sublist(lenVal, lstLen - lenVal);
  1418. }
  1419. }
  1420. public IValue upTill(IInteger ni) {
  1421. //@doc{Returns the list 0..n, this is slightly faster than [0,1..n], since the returned values are shared}
  1422. int n = ni.intValue();
  1423. if(indexes == null || indexes.get() == null) {
  1424. IList l = makeUpTill(0, n);
  1425. indexes = new WeakReference<IList>(l);
  1426. return indexes.get();
  1427. } else {
  1428. IList l = indexes.get(); // strong ref
  1429. if(l == null || n >= l.length()){
  1430. l = makeUpTill(0,n);
  1431. indexes = new WeakReference<IList>(l);
  1432. return l;
  1433. }
  1434. return l.sublist(0, n);
  1435. }
  1436. }
  1437. public IValue prefix(IList lst) {
  1438. //@doc{Return all but the last element of a list}
  1439. int lstLen = lst.length();
  1440. if(lstLen <= 1){
  1441. return values.list();
  1442. } else {
  1443. return lst.sublist(0, lstLen - 1);
  1444. }
  1445. }
  1446. public IValue takeOneFrom(IList lst)
  1447. //@doc{takeOneFrom -- remove an arbitrary element from a list, returns the element and the modified list}
  1448. {
  1449. int n = lst.length();
  1450. if(n > 0){
  1451. int k = random.nextInt(n);
  1452. IValue pick = lst.get(0);
  1453. IListWriter w = lst.getType().writer(values);
  1454. for(int i = n - 1; i >= 0; i--) {
  1455. if(i == k){
  1456. pick = lst.get(i);
  1457. } else {
  1458. w.insert(lst.get(i));
  1459. }
  1460. }
  1461. return values.tuple(pick, w.done());
  1462. }
  1463. throw RuntimeExceptionFactory.emptyList(null, null);
  1464. }
  1465. public IMap toMap(IList lst)
  1466. // @doc{toMap -- convert a list of tuples to a map; first value in old tuples is associated with a set of second values}
  1467. {
  1468. Type tuple = lst.getElementType();
  1469. Type keyType = tuple.getFieldType(0);
  1470. Type valueType = tuple.getFieldType(1);
  1471. Type valueSetType = types.setType(valueType);
  1472. HashMap<IValue,ISetWriter> hm = new HashMap<IValue,ISetWriter>();
  1473. for (IValue v : lst) {
  1474. ITuple t = (ITuple) v;
  1475. IValue key = t.get(0);
  1476. IValue val = t.get(1);
  1477. ISetWriter wValSet = hm.get(key);
  1478. if(wValSet == null){
  1479. wValSet = valueSetType.writer(values);
  1480. hm.put(key, wValSet);
  1481. }
  1482. wValSet.insert(val);
  1483. }
  1484. Type resultType = types.mapType(keyType, valueSetType);
  1485. IMapWriter w = resultType.writer(values);
  1486. for(IValue v : hm.keySet()){
  1487. w.put(v, hm.get(v).done());
  1488. }
  1489. return w.done();
  1490. }
  1491. public IValue toMapUnique(IList lst)
  1492. //@doc{toMapUnique -- convert a list of tuples to a map; result should be a map}
  1493. {
  1494. if(lst.length() == 0){
  1495. return values.map(types.voidType(), types.voidType());
  1496. }
  1497. Type tuple = lst.getElementType();
  1498. Type resultType = types.mapType(tuple.getFieldType(0), tuple.getFieldType(1));
  1499. IMapWriter w = resultType.writer(values);
  1500. HashSet<IValue> seenKeys = new HashSet<IValue>();
  1501. for(IValue v : lst){
  1502. ITuple t = (ITuple) v;
  1503. IValue key = t.get(0);
  1504. if(seenKeys.contains(key))
  1505. throw RuntimeExceptionFactory.MultipleKey(key, null, null);
  1506. seenKeys.add(key);
  1507. w.put(key, t.get(1));
  1508. }
  1509. return w.done();
  1510. }
  1511. public IValue toSet(IList lst)
  1512. //@doc{toSet -- convert a list to a set}
  1513. {
  1514. Type resultType = types.setType(lst.getElementType());
  1515. ISetWriter w = resultType.writer(values);
  1516. for(IValue v : lst){
  1517. w.insert(v);
  1518. }
  1519. return w.done();
  1520. }
  1521. public IValue toString(IList lst)
  1522. //@doc{toString -- convert a list to a string}
  1523. {
  1524. return values.string(lst.toString());
  1525. }
  1526. /*
  1527. * Map
  1528. */
  1529. public IValue domain(IMap M)
  1530. //@doc{domain -- return the domain (keys) of a map}
  1531. {
  1532. Type keyType = M.getKeyType();
  1533. Type resultType = types.setType(keyType);
  1534. ISetWriter w = resultType.writer(values);
  1535. Iterator<Entry<IValue,IValue>> iter = M.entryIterator();
  1536. while (iter.hasNext()) {
  1537. Entry<IValue,IValue> entry = iter.next();
  1538. w.insert(entry.getKey());
  1539. }
  1540. return w.done();
  1541. }
  1542. public IValue getOneFrom(IMap m)
  1543. //@doc{getOneFrom -- return arbitrary key of a map}
  1544. {
  1545. int i = 0;
  1546. int sz = m.size();
  1547. if(sz == 0){
  1548. throw RuntimeExceptionFactory.emptyMap(null, null);
  1549. }
  1550. int k = random.nextInt(sz);
  1551. Iterator<Entry<IValue,IValue>> iter = m.entryIterator();
  1552. while(iter.hasNext()){
  1553. if(i == k){
  1554. return (iter.next()).getKey();
  1555. }
  1556. iter.next();
  1557. i++;
  1558. }
  1559. return null;
  1560. }
  1561. public IValue invertUnique(IMap M)
  1562. //@doc{invertUnique -- return map with key and value inverted; values are unique}
  1563. {
  1564. Type keyType = M.getKeyType();
  1565. Type valueType = M.getValueType();
  1566. Type resultType = types.mapType(valueType, keyType);
  1567. IMapWriter w = resultType.writer(values);
  1568. HashSet<IValue> seenValues = new HashSet<IValue>();
  1569. Iterator<Entry<IValue,IValue>> iter = M.entryIterator();
  1570. while (iter.hasNext()) {
  1571. Entry<IValue,IValue> entry = iter.next();
  1572. IValue key = entry.getKey();
  1573. IValue val = entry.getValue();
  1574. if(seenValues.contains(val))
  1575. throw RuntimeExceptionFactory.MultipleKey(val, null, null);
  1576. seenValues.add(val);
  1577. w.put(val, key);
  1578. }
  1579. return w.done();
  1580. }
  1581. public IValue invert(IMap M)
  1582. //@doc{invert -- return map with key and value inverted; values are not unique and are collected in a set}
  1583. {
  1584. Type keyType = M.getKeyType();
  1585. Type valueType = M.getValueType();
  1586. Type keySetType = types.setType(keyType);
  1587. HashMap<IValue,ISetWriter> hm = new HashMap<IValue,ISetWriter>();
  1588. Iterator<Entry<IValue,IValue>> iter = M.entryIterator();
  1589. while (iter.hasNext()) {
  1590. Entry<IValue,IValue> entry = iter.next();
  1591. IValue key = entry.getKey();
  1592. IValue val = entry.getValue();
  1593. ISetWriter wKeySet = hm.get(val);
  1594. if(wKeySet == null){
  1595. wKeySet = keySetType.writer(values);
  1596. hm.put(val, wKeySet);
  1597. }
  1598. wKeySet.insert(key);
  1599. }
  1600. Type resultType = types.mapType(valueType, keySetType);
  1601. IMapWriter w = resultType.writer(values);
  1602. iter = M.entryIterator();
  1603. for(IValue v : hm.keySet()){
  1604. w.put(v, hm.get(v).done());
  1605. }
  1606. return w.done();
  1607. }
  1608. public IValue isEmpty(IMap M)
  1609. //@doc{isEmpty -- is map empty?}
  1610. {
  1611. return values.bool(M.size() == 0);
  1612. }
  1613. public IValue range(IMap M)
  1614. //@doc{range -- return the range (values) of a map}
  1615. {
  1616. Type valueType = M.getValueType();
  1617. Type resultType = types.setType(valueType);
  1618. ISetWriter w = resultType.writer(values);
  1619. Iterator<Entry<IValue,IValue>> iter = M.entryIterator();
  1620. while (iter.hasNext()) {
  1621. Entry<IValue,IValue> entry = iter.next();
  1622. w.insert(entry.getValue());
  1623. }
  1624. return w.done();
  1625. }
  1626. public IValue size(IMap M)
  1627. {
  1628. return values.integer(M.size());
  1629. }
  1630. public IValue toList(IMap M)
  1631. //@doc{toList -- convert a map to a list}
  1632. {
  1633. Type keyType = M.getKeyType();
  1634. Type valueType = M.getValueType();
  1635. Type elementType = types.tupleType(keyType,valueType);
  1636. Type resultType = types.listType(elementType);
  1637. IListWriter w = resultType.writer(values);
  1638. Iterator<Entry<IValue,IValue>> iter = M.entryIterator();
  1639. while (iter.hasNext()) {
  1640. Entry<IValue,IValue> entry = iter.next();
  1641. w.insert(values.tuple(entry.getKey(), entry.getValue()));
  1642. }
  1643. return w.done();
  1644. }
  1645. public IValue toRel(IMap M)
  1646. //@doc{toRel -- convert a map to a relation}
  1647. {
  1648. Type keyType = M.getKeyType();
  1649. Type valueType = M.getValueType();
  1650. Type resultType = types.relType(keyType, valueType);
  1651. IRelationWriter w = resultType.writer(values);
  1652. Iterator<Entry<IValue,IValue>> iter = M.entryIterator();
  1653. while (iter.hasNext()) {
  1654. Entry<IValue,IValue> entry = iter.next();
  1655. w.insert(values.tuple(entry.getKey(), entry.getValue()));
  1656. }
  1657. return w.done();
  1658. }
  1659. public IValue toString(IMap M)
  1660. {
  1661. return values.string(M.toString());
  1662. }
  1663. /*
  1664. * Node
  1665. */
  1666. public IValue arity(INode T)
  1667. //@doc{arity -- number of children of a node}
  1668. {
  1669. return values.integer(T.arity());
  1670. }
  1671. public IValue getChildren(INode T)
  1672. //@doc{getChildren -- get the children of a node}
  1673. {
  1674. Type resultType = types.listType(types.valueType());
  1675. IListWriter w = resultType.writer(values);
  1676. for(IValue v : T.getChildren()){
  1677. w.append(v);
  1678. }
  1679. return w.done();
  1680. }
  1681. public IValue getName(INode T)
  1682. //@doc{getName -- get the function name of a node}
  1683. {
  1684. return values.string(T.getName());
  1685. }
  1686. public IValue makeNode(IString N, IList V)
  1687. //@doc{makeNode -- create a node given its function name and arguments}
  1688. {
  1689. IList argList = V;
  1690. IValue args[] = new IValue[argList.length()];
  1691. int i = 0;
  1692. for(IValue v : argList){
  1693. args[i++] = v;
  1694. }
  1695. return values.node(N.getValue(), args);
  1696. }
  1697. public IValue readATermFromFile(IString fileName){
  1698. //@doc{readATermFromFile -- read an ATerm from a named file}
  1699. ATermReader atr = new ATermReader();
  1700. try {
  1701. FileInputStream stream = new FileInputStream(fileName.getValue());
  1702. IValue result = atr.read(values, stream);
  1703. stream.close();
  1704. return result;
  1705. } catch (FactTypeUseException e) {
  1706. e.printStackTrace();
  1707. throw RuntimeExceptionFactory.io(values.string(e.getMessage()), null, null);
  1708. } catch (IOException e) {
  1709. e.printStackTrace();
  1710. throw RuntimeExceptionFactory.io(values.string(e.getMessage()), null, null);
  1711. }
  1712. }
  1713. public IValue toString(INode T)
  1714. //@doc{toString -- convert a node to a string}
  1715. {
  1716. return values.string(T.toString());
  1717. }
  1718. public IMap getAnnotations(INode node) {
  1719. java.util.Map<java.lang.String,IValue> map = node.getAnnotations();
  1720. IMapWriter w = values.mapWriter(types.stringType(), types.valueType());
  1721. for (Entry<java.lang.String,IValue> entry : map.entrySet()) {
  1722. w.put(values.string(entry.getKey()), entry.getValue());
  1723. }
  1724. return w.done();
  1725. }
  1726. public INode setAnnotations(INode node, IMap annotations) {
  1727. java.util.Map<java.lang.String,IValue> map = new HashMap<java.lang.String,IValue>();
  1728. for (IValue key : annotations) {
  1729. IValue value = annotations.get(key);
  1730. map.put(((IString) key).getValue(), value);
  1731. }
  1732. return node.setAnnotations(map);
  1733. }
  1734. public INode delAnnotations(INode node) {
  1735. return node.removeAnnotations();
  1736. }
  1737. public INode delAnnotation(INode node, IString label) {
  1738. return node.removeAnnotation(label.getValue());
  1739. }
  1740. /*
  1741. * ParseTree
  1742. */
  1743. private final TypeReifier tr;
  1744. public IValue parse(IValue start, ISourceLocation input, IEvaluatorContext ctx) {
  1745. return parse(start, values.mapWriter().done(), input, ctx);
  1746. }
  1747. public IValue parse(IValue start, IMap robust, ISourceLocation input, IEvaluatorContext ctx) {
  1748. Type reified = start.getType();
  1749. IConstructor startSort = checkPreconditions(start, reified);
  1750. try {
  1751. IConstructor pt = ctx.getEvaluator().parseObject(ctx.getEvaluator().getMonitor(), startSort, robust, input.getURI());
  1752. if (TreeAdapter.isAppl(pt)) {
  1753. if (SymbolAdapter.isStart(TreeAdapter.getType(pt))) {
  1754. pt = (IConstructor) TreeAdapter.getArgs(pt).get(1);
  1755. }
  1756. }
  1757. return pt;
  1758. }
  1759. catch (ParseError pe) {
  1760. ISourceLocation errorLoc = values.sourceLocation(pe.getLocation(), pe.getOffset(), pe.getLength(), pe.getBeginLine() + 1, pe.getEndLine() + 1, pe.getBeginColumn(), pe.getEndColumn());
  1761. throw RuntimeExceptionFactory.parseError(errorLoc, ctx.getCurrentAST(), ctx.getStackTrace());
  1762. }
  1763. catch (UndeclaredNonTerminalException e){
  1764. throw new UndeclaredNonTerminal(e.getName(), e.getClassName(), ctx.getCurrentAST());
  1765. }
  1766. }
  1767. public IValue parse(IValue start, IString input, IEvaluatorContext ctx) {
  1768. return parse(start, values.mapWriter().done(), input, ctx);
  1769. }
  1770. public IValue parse(IValue start, IMap robust, IString input, IEvaluatorContext ctx) {
  1771. Type reified = start.getType();
  1772. IConstructor startSort = checkPreconditions(start, reified);
  1773. try {
  1774. IConstructor pt = ctx.getEvaluator().parseObject(ctx.getEvaluator().getMonitor(), startSort, robust, input.getValue());
  1775. if (TreeAdapter.isAppl(pt)) {
  1776. if (SymbolAdapter.isStart(TreeAdapter.getType(pt))) {
  1777. pt = (IConstructor) TreeAdapter.getArgs(pt).get(1);
  1778. }
  1779. }
  1780. return pt;
  1781. }
  1782. catch (ParseError pe) {
  1783. ISourceLocation errorLoc = values.sourceLocation(pe.getLocation(), pe.getOffset(), pe.getLength(), pe.getBeginLine() + 1, pe.getEndLine() + 1, pe.getBeginColumn(), pe.getEndColumn());
  1784. throw RuntimeExceptionFactory.parseError(errorLoc, ctx.getCurrentAST(), ctx.getStackTrace());
  1785. }
  1786. catch (UndeclaredNonTerminalException e){
  1787. throw new UndeclaredNonTerminal(e.getName(), e.getClassName(), ctx.getCurrentAST());
  1788. }
  1789. }
  1790. public IValue parse(IValue start, IString input, ISourceLocation loc, IEvaluatorContext ctx) {
  1791. return parse(start, values.mapWriter().done(), input, loc, ctx);
  1792. }
  1793. public IValue parse(IValue start, IMap robust, IString input, ISourceLocation loc, IEvaluatorContext ctx) {
  1794. Type reified = start.getType();
  1795. IConstructor startSort = checkPreconditions(start, reified);
  1796. try {
  1797. IConstructor pt = ctx.getEvaluator().parseObject(ctx.getEvaluator().getMonitor(), startSort, robust, input.getValue(), loc);
  1798. if (TreeAdapter.isAppl(pt)) {
  1799. if (SymbolAdapter.isStart(TreeAdapter.getType(pt))) {
  1800. pt = (IConstructor) TreeAdapter.getArgs(pt).get(1);
  1801. }
  1802. }
  1803. return pt;
  1804. }
  1805. catch (ParseError pe) {
  1806. ISourceLocation errorLoc = values.sourceLocation(pe.getLocation(), pe.getOffset(), pe.getLength(), pe.getBeginLine(), pe.getEndLine(), pe.getBeginColumn(), pe.getEndColumn());
  1807. throw RuntimeExceptionFactory.parseError(errorLoc, ctx.getCurrentAST(), ctx.getStackTrace());
  1808. }
  1809. catch (UndeclaredNonTerminalException e){
  1810. throw new UndeclaredNonTerminal(e.getName(), e.getClassName(), ctx.getCurrentAST());
  1811. }
  1812. }
  1813. public IString unparse(IConstructor tree) {
  1814. return values.string(TreeAdapter.yield(tree));
  1815. }
  1816. private IConstructor makeConstructor(String name, IEvaluatorContext ctx, IValue ...args) {
  1817. IValue value = ctx.getEvaluator().call(name, args);
  1818. Type type = value.getType();
  1819. if (type.isAbstractDataType()) {
  1820. return (IConstructor)value;
  1821. }
  1822. throw RuntimeExceptionFactory.implodeError("Calling of constructor " + name + " did not return a constructor",
  1823. ctx.getCurrentAST(), ctx.getStackTrace());
  1824. }
  1825. private java.lang.String unescapedConsName(IConstructor tree) {
  1826. java.lang.String x = TreeAdapter.getConstructorName(tree);
  1827. if (x != null) {
  1828. x = x.replaceAll("\\\\", "");
  1829. }
  1830. return x;
  1831. }
  1832. private Set<Type> findConstructors(Type type, java.lang.String constructorName, int arity, TypeStore store) {
  1833. Set<Type> constructors = new HashSet<Type>();
  1834. for (Type constructor : store.lookupConstructor(type, constructorName)) {
  1835. if (constructor.getArity() == arity)
  1836. constructors.add(constructor);
  1837. }
  1838. return constructors;
  1839. }
  1840. // private Type findConstructor(Type type, java.lang.String constructorName, int arity, TypeStore store) {
  1841. // for (Type candidate: store.lookupConstructor(type, constructorName)) {
  1842. // // It finds the first with suitable arity, so this is inaccurate
  1843. // // if there are overloaded constructors with the same arity
  1844. // if (arity == candidate.getArity()) {
  1845. // return candidate;
  1846. // }
  1847. // }
  1848. // return null;
  1849. // }
  1850. public IValue implode(IValue reifiedType, IConstructor tree, IEvaluatorContext ctx) {
  1851. TypeStore store = new TypeStore();
  1852. Type type = tr.valueToType((IConstructor) reifiedType, store);
  1853. try {
  1854. IValue result = implode(store, type, tree, false, ctx);
  1855. return result;
  1856. }
  1857. catch (Backtrack b) {
  1858. throw b.exception;
  1859. }
  1860. }
  1861. @SuppressWarnings("serial")
  1862. private static class Backtrack extends RuntimeException {
  1863. Throw exception;
  1864. public Backtrack(Throw exception) {
  1865. this.exception = exception;
  1866. }
  1867. @Override
  1868. public synchronized Throwable fillInStackTrace() {
  1869. return this;
  1870. }
  1871. }
  1872. private IValue[] implodeArgs(TypeStore store, Type type, IList args, IEvaluatorContext ctx) {
  1873. int length = args.length();
  1874. IValue implodedArgs[] = new IValue[length];
  1875. for (int i = 0; i < length; i++) {
  1876. Type argType = isUntypedNodeType(type) ? type : type.getFieldType(i);
  1877. implodedArgs[i] = implode(store, argType, (IConstructor)args.get(i), false, ctx);
  1878. }
  1879. return implodedArgs;
  1880. }
  1881. private IValue implode(TypeStore store, Type type, IConstructor tree, boolean splicing, IEvaluatorContext ctx) {
  1882. // always yield if expected type is str, except if regular
  1883. if (type.isStringType() && !(TreeAdapter.isList(tree) || TreeAdapter.isOpt(tree))) {
  1884. return values.string(TreeAdapter.yield(tree));
  1885. }
  1886. if (SymbolAdapter.isStartSort(TreeAdapter.getType(tree))) {
  1887. IList args = TreeAdapter.getArgs(tree);
  1888. IConstructor before = (IConstructor) args.get(0);
  1889. IConstructor ast = (IConstructor) args.get(1);
  1890. IConstructor after = (IConstructor) args.get(2);
  1891. IValue result = implode(store, type, ast, splicing, ctx);
  1892. if (result.getType().isNodeType()) {
  1893. IMapWriter comments = values.mapWriter();
  1894. comments.putAll((IMap)((INode)result).getAnnotation("comments"));
  1895. IList beforeComments = extractComments(before);
  1896. if (!beforeComments.isEmpty()) {
  1897. comments.put(values.integer(-1), beforeComments);
  1898. }
  1899. IList afterComments = extractComments(after);
  1900. if (!afterComments.isEmpty()) {
  1901. comments.put(values.integer(((INode)result).arity()), afterComments);
  1902. }
  1903. result = ((INode)result).setAnnotation("comments", comments.done());
  1904. }
  1905. return result;
  1906. }
  1907. if (TreeAdapter.isLexical(tree)) {
  1908. java.lang.String constructorName = unescapedConsName(tree);
  1909. java.lang.String yield = TreeAdapter.yield(tree);
  1910. if (constructorName != null) {
  1911. // make a single argument constructor with yield as argument
  1912. // if there is a singleton constructor with a str argument
  1913. if (!type.isAbstractDataType()) {
  1914. throw RuntimeExceptionFactory.illegalArgument(tree, null, null, "Constructor (" + constructorName + ") should match with abstract data type and not with " + type);
  1915. }
  1916. Set<Type> conses = findConstructors(type, constructorName, 1, store);
  1917. Iterator<Type> iter = conses.iterator();
  1918. while (iter.hasNext()) {
  1919. try {
  1920. @SuppressWarnings("unused")
  1921. Type cons = iter.next();
  1922. ISourceLocation loc = TreeAdapter.getLocation(tree);
  1923. IConstructor ast = makeConstructor(constructorName, ctx, values.string(yield));
  1924. return ast.setAnnotation("location", loc);
  1925. }
  1926. catch (Backtrack b) {
  1927. continue;
  1928. }
  1929. }
  1930. throw new Backtrack(RuntimeExceptionFactory.illegalArgument(tree, null, null, "Cannot find a constructor " + type));
  1931. }
  1932. if (type.isIntegerType()) {
  1933. return values.integer(yield);
  1934. }
  1935. if (type.isRealType()) {
  1936. return values.real(yield);
  1937. }
  1938. if (type.isBoolType()) {
  1939. if (yield.equals("true")) {
  1940. return values.bool(true);
  1941. }
  1942. if (yield.equals("false")) {
  1943. return values.bool(false);
  1944. }
  1945. throw new Backtrack(RuntimeExceptionFactory.illegalArgument(tree, null, null, "Bool type does not match with " + yield));
  1946. }
  1947. if (type.isStringType() || isUntypedNodeType(type)) {
  1948. // NB: in "node space" all lexicals become strings
  1949. return values.string(yield);
  1950. }
  1951. throw RuntimeExceptionFactory.illegalArgument(tree, null, null, "Missing lexical constructor");
  1952. }
  1953. //Set implementation added here by Jurgen at 19/07/12 16:45
  1954. if (TreeAdapter.isList(tree)) {
  1955. if (type.isListType() || splicing) {
  1956. Type elementType = splicing ? type : type.getElementType();
  1957. IListWriter w = values.listWriter(elementType);
  1958. for (IValue arg: TreeAdapter.getListASTArgs(tree)) {
  1959. w.append(implode(store, elementType, (IConstructor) arg, false, ctx));
  1960. }
  1961. return w.done();
  1962. }
  1963. else if (type.isSetType()) {
  1964. Type elementType = splicing ? type : type.getElementType();
  1965. ISetWriter w = values.setWriter(elementType);
  1966. for (IValue arg: TreeAdapter.getListASTArgs(tree)) {
  1967. w.insert(implode(store, elementType, (IConstructor) arg, false, ctx));
  1968. }
  1969. return w.done();
  1970. }
  1971. else {
  1972. throw new Backtrack(RuntimeExceptionFactory.illegalArgument(tree, null, null, "Cannot match list with " + type));
  1973. }
  1974. }
  1975. //Changes end here
  1976. if (TreeAdapter.isOpt(tree) && type.isBoolType()) {
  1977. IList args = TreeAdapter.getArgs(tree);
  1978. if (args.isEmpty()) {
  1979. return values.bool(false);
  1980. }
  1981. return values.bool(true);
  1982. }
  1983. if (TreeAdapter.isOpt(tree)) {
  1984. if (!type.isListType()) {
  1985. throw new Backtrack(RuntimeExceptionFactory.illegalArgument(tree, null, null, "Optional should match with a list and not " + type));
  1986. }
  1987. Type elementType = type.getElementType();
  1988. IListWriter w = values.listWriter(elementType);
  1989. for (IValue arg: TreeAdapter.getASTArgs(tree)) {
  1990. IValue implodedArg = implode(store, elementType, (IConstructor) arg, true, ctx);
  1991. if (implodedArg instanceof IList) {
  1992. // splicing
  1993. for (IValue nextArg: (IList)implodedArg) {
  1994. w.append(nextArg);
  1995. }
  1996. }
  1997. else {
  1998. w.append(implodedArg);
  1999. }
  2000. // opts should have one argument (if any at all)
  2001. break;
  2002. }
  2003. return w.done();
  2004. }
  2005. if (TreeAdapter.isAmb(tree)) {
  2006. if (!type.isSetType()) {
  2007. throw new Backtrack(RuntimeExceptionFactory.illegalArgument(tree, null, null, "Ambiguous node should match with set and not " + type));
  2008. }
  2009. Type elementType = type.getElementType();
  2010. ISetWriter w = values.setWriter(elementType);
  2011. for (IValue arg: TreeAdapter.getAlternatives(tree)) {
  2012. w.insert(implode(store, elementType, (IConstructor) arg, false, ctx));
  2013. }
  2014. return w.done();
  2015. }
  2016. if (ProductionAdapter.hasAttribute(TreeAdapter.getProduction(tree), Factory.Attribute_Bracket)) {
  2017. return implode(store, type, (IConstructor) TreeAdapter.getASTArgs(tree).get(0), false, ctx);
  2018. }
  2019. if (TreeAdapter.isAppl(tree)) {
  2020. IList args = TreeAdapter.getASTArgs(tree);
  2021. int j = 0;
  2022. IMapWriter cw = values.mapWriter(types.integerType(), types.listType(types.stringType()));
  2023. IListWriter aw = values.listWriter();
  2024. for (IValue kid : TreeAdapter.getArgs(tree)) {
  2025. if (TreeAdapter.isLayout((IConstructor) kid)) {
  2026. IList cts = extractComments((IConstructor) kid);
  2027. if (!cts.isEmpty()) {
  2028. cw.put(values.integer(j), cts);
  2029. }
  2030. j++;
  2031. }
  2032. else if (!TreeAdapter.isLiteral((IConstructor) kid) &&
  2033. !TreeAdapter.isCILiteral((IConstructor) kid) &&
  2034. !TreeAdapter.isEmpty((IConstructor) kid)) {
  2035. aw.append(kid);
  2036. }
  2037. }
  2038. args = aw.done();
  2039. int length = args.length();
  2040. IMap comments = cw.done();
  2041. // // this could be optimized.
  2042. // i = 0;
  2043. // int length = args.length();
  2044. // while (i < length) {
  2045. // if (TreeAdapter.isEmpty((IConstructor) args.get(i))) {
  2046. // length--;
  2047. // args = args.delete(i);
  2048. // }
  2049. // else {
  2050. // i++;
  2051. // }
  2052. // }
  2053. java.lang.String constructorName = unescapedConsName(tree);
  2054. if (constructorName == null) {
  2055. if (length == 1) {
  2056. // jump over injection
  2057. return implode(store, type, (IConstructor) args.get(0), splicing, ctx);
  2058. }
  2059. // make a tuple if we're in node space
  2060. if (isUntypedNodeType(type)) {
  2061. return values.tuple(implodeArgs(store, type, args, ctx));
  2062. }
  2063. if (!type.isTupleType()) {
  2064. throw new Backtrack(RuntimeExceptionFactory.illegalArgument(tree, null, null, "Constructor does not match with " + type));
  2065. }
  2066. if (length != type.getArity()) {
  2067. throw new Backtrack(RuntimeExceptionFactory.arityMismatch(type.getArity(), length, null, null));
  2068. }
  2069. return values.tuple(implodeArgs(store, type, args, ctx));
  2070. }
  2071. // if in node space, make untyped nodes
  2072. if (isUntypedNodeType(type)) {
  2073. INode ast = values.node(constructorName, implodeArgs(store, type, args, ctx));
  2074. return ast.setAnnotation("location", TreeAdapter.getLocation(tree)).setAnnotation("comments", comments);
  2075. }
  2076. // make a typed constructor
  2077. if (!type.isAbstractDataType()) {
  2078. throw new Backtrack(RuntimeExceptionFactory.illegalArgument(tree, null, null, "Constructor (" + constructorName + ") should match with abstract data type and not with " + type));
  2079. }
  2080. Set<Type> conses = findConstructors(type, constructorName, length, store);
  2081. Iterator<Type> iter = conses.iterator();
  2082. while (iter.hasNext()) {
  2083. try {
  2084. Type cons = iter.next();
  2085. ISourceLocation loc = TreeAdapter.getLocation(tree);
  2086. IValue[] implodedArgs = implodeArgs(store, cons, args, ctx);
  2087. IConstructor ast = makeConstructor(constructorName, ctx, implodedArgs);
  2088. return ast.setAnnotation("location", loc).setAnnotation("comments", comments);
  2089. }
  2090. catch (Backtrack b) {
  2091. continue;
  2092. }
  2093. }
  2094. }
  2095. throw new Backtrack(RuntimeExceptionFactory.illegalArgument(tree, null, null,
  2096. "Cannot find a constructor for " + type));
  2097. }
  2098. private IList extractComments(IConstructor layout) {
  2099. final IListWriter comments = values.listWriter();
  2100. TreeVisitor visitor = new TreeVisitor() {
  2101. @Override
  2102. public IConstructor visitTreeAppl(IConstructor arg)
  2103. throws VisitorException {
  2104. if (TreeAdapter.isComment(arg)) {
  2105. comments.append(values.string(TreeAdapter.yield(arg)));
  2106. }
  2107. else {
  2108. for (IValue t: TreeAdapter.getArgs(arg)) {
  2109. t.accept(this);
  2110. }
  2111. }
  2112. return arg;
  2113. }
  2114. @Override
  2115. public IConstructor visitTreeAmb(IConstructor arg)
  2116. throws VisitorException {
  2117. return arg;
  2118. }
  2119. @Override
  2120. public IConstructor visitTreeChar(IConstructor arg)
  2121. throws VisitorException {
  2122. return arg;
  2123. }
  2124. @Override
  2125. public IConstructor visitTreeCycle(IConstructor arg)
  2126. throws VisitorException {
  2127. return arg;
  2128. }
  2129. };
  2130. try {
  2131. layout.accept(visitor);
  2132. }
  2133. catch (VisitorException e) {
  2134. throw new ImplementationError(e.getMessage());
  2135. }
  2136. return comments.done();
  2137. }
  2138. private boolean isUntypedNodeType(Type type) {
  2139. return type.isNodeType() && !type.isConstructorType() && !type.isAbstractDataType();
  2140. }
  2141. private static IConstructor checkPreconditions(IValue start, Type reified) {
  2142. if (!(reified instanceof ReifiedType)) {
  2143. throw RuntimeExceptionFactory.illegalArgument(start, null, null, "A reified type is required instead of " + reified);
  2144. }
  2145. Type nt = reified.getTypeParameters().getFieldType(0);
  2146. if (!(nt instanceof NonTerminalType)) {
  2147. throw RuntimeExceptionFactory.illegalArgument(start, null, null, "A non-terminal type is required instead of " + nt);
  2148. }
  2149. IConstructor symbol = ((NonTerminalType) nt).getSymbol();
  2150. return symbol;
  2151. }
  2152. /*
  2153. * Rational
  2154. */
  2155. public IValue numerator(IRational n)
  2156. {
  2157. return n.numerator();
  2158. }
  2159. public IValue denominator(IRational n)
  2160. {
  2161. return n.denominator();
  2162. }
  2163. public IValue remainder(IRational n)
  2164. {
  2165. return n.remainder();
  2166. }
  2167. /*
  2168. * Relation
  2169. */
  2170. /*
  2171. * Set
  2172. */
  2173. public IValue getOneFrom(ISet st)
  2174. // @doc{getOneFrom -- pick a random element from a set}
  2175. {
  2176. int sz = st.size();
  2177. if (sz == 0) {
  2178. throw RuntimeExceptionFactory.emptySet(null, null);
  2179. }
  2180. int k = random.nextInt(sz);
  2181. int i = 0;
  2182. for (IValue v : st) {
  2183. if (i == k) {
  2184. return v;
  2185. }
  2186. i++;
  2187. }
  2188. throw RuntimeExceptionFactory.emptySet(null, null);
  2189. }
  2190. public IValue isEmpty(ISet st)
  2191. //@doc{isEmpty -- is set empty?}
  2192. {
  2193. return values.bool(st.size() == 0);
  2194. }
  2195. public IValue size(ISet st)
  2196. // @doc{size -- number of elements in a set}
  2197. {
  2198. return values.integer(st.size());
  2199. }
  2200. public IMap index(IRelation s) {
  2201. Map<IValue, ISetWriter> map = new HashMap<IValue, ISetWriter>(s.size());
  2202. for (IValue t : s) {
  2203. ITuple tuple = (ITuple) t;
  2204. IValue key = tuple.get(0);
  2205. IValue value = tuple.get(1);
  2206. ISetWriter writer = map.get(key);
  2207. if (writer == null) {
  2208. writer = values.setWriter();
  2209. map.put(key, writer);
  2210. }
  2211. writer.insert(value);
  2212. }
  2213. IMapWriter mapWriter = values.mapWriter();
  2214. for (IValue key : map.keySet()) {
  2215. mapWriter.put(key, map.get(key).done());
  2216. }
  2217. return mapWriter.done();
  2218. }
  2219. public IMap index(IListRelation s) {
  2220. Map<IValue, ISetWriter> map = new HashMap<IValue, ISetWriter>(s.length());
  2221. for (IValue t : s) {
  2222. ITuple tuple = (ITuple) t;
  2223. IValue key = tuple.get(0);
  2224. IValue value = tuple.get(1);
  2225. ISetWriter writer = map.get(key);
  2226. if (writer == null) {
  2227. writer = values.setWriter();
  2228. map.put(key, writer);
  2229. }
  2230. writer.insert(value);
  2231. }
  2232. IMapWriter mapWriter = values.mapWriter();
  2233. for (IValue key : map.keySet()) {
  2234. mapWriter.put(key, map.get(key).done());
  2235. }
  2236. return mapWriter.done();
  2237. }
  2238. public IValue takeOneFrom(ISet st)
  2239. // @doc{takeOneFrom -- remove an arbitrary element from a set,
  2240. // returns the element and the modified set}
  2241. {
  2242. int n = st.size();
  2243. if (n > 0) {
  2244. int i = 0;
  2245. int k = random.nextInt(n);
  2246. IValue pick = null;
  2247. ISetWriter w = st.getType().writer(values);
  2248. for (IValue v : st) {
  2249. if (i == k) {
  2250. pick = v;
  2251. } else {
  2252. w.insert(v);
  2253. }
  2254. i++;
  2255. }
  2256. return values.tuple(pick, w.done());
  2257. }
  2258. throw RuntimeExceptionFactory.emptySet(null, null);
  2259. }
  2260. public IValue toList(ISet st)
  2261. // @doc{toList -- convert a set to a list}
  2262. {
  2263. Type resultType = types.listType(st.getElementType());
  2264. IListWriter w = resultType.writer(values);
  2265. for (IValue v : st) {
  2266. w.insert(v);
  2267. }
  2268. return w.done();
  2269. }
  2270. public IValue toMap(IRelation st)
  2271. // @doc{toMap -- convert a set of tuples to a map; value in old map is associated with a set of keys in old map}
  2272. {
  2273. Type tuple = st.getElementType();
  2274. Type keyType = tuple.getFieldType(0);
  2275. Type valueType = tuple.getFieldType(1);
  2276. Type valueSetType = types.setType(valueType);
  2277. HashMap<IValue,ISetWriter> hm = new HashMap<IValue,ISetWriter>();
  2278. for (IValue v : st) {
  2279. ITuple t = (ITuple) v;
  2280. IValue key = t.get(0);
  2281. IValue val = t.get(1);
  2282. ISetWriter wValSet = hm.get(key);
  2283. if(wValSet == null){
  2284. wValSet = valueSetType.writer(values);
  2285. hm.put(key, wValSet);
  2286. }
  2287. wValSet.insert(val);
  2288. }
  2289. Type resultType = types.mapType(keyType, valueSetType);
  2290. IMapWriter w = resultType.writer(values);
  2291. for(IValue v : hm.keySet()){
  2292. w.put(v, hm.get(v).done());
  2293. }
  2294. return w.done();
  2295. }
  2296. public IValue toMap(IListRelation st)
  2297. // @doc{toMap -- convert a list of tuples to a map; value in old map is associated with a set of keys in old map}
  2298. {
  2299. Type tuple = st.getElementType();
  2300. Type keyType = tuple.getFieldType(0);
  2301. Type valueType = tuple.getFieldType(1);
  2302. Type valueSetType = types.setType(valueType);
  2303. HashMap<IValue,ISetWriter> hm = new HashMap<IValue,ISetWriter>();
  2304. for (IValue v : st) {
  2305. ITuple t = (ITuple) v;
  2306. IValue key = t.get(0);
  2307. IValue val = t.get(1);
  2308. ISetWriter wValSet = hm.get(key);
  2309. if(wValSet == null){
  2310. wValSet = valueSetType.writer(values);
  2311. hm.put(key, wValSet);
  2312. }
  2313. wValSet.insert(val);
  2314. }
  2315. Type resultType = types.mapType(keyType, valueSetType);
  2316. IMapWriter w = resultType.writer(values);
  2317. for(IValue v : hm.keySet()){
  2318. w.put(v, hm.get(v).done());
  2319. }
  2320. return w.done();
  2321. }
  2322. public IValue toMapUnique(IRelation st)
  2323. // @doc{toMapUnique -- convert a set of tuples to a map; keys are unique}
  2324. {
  2325. Type tuple = st.getElementType();
  2326. Type resultType = types.mapType(tuple.getFieldType(0), tuple
  2327. .getFieldType(1));
  2328. IMapWriter w = resultType.writer(values);
  2329. HashSet<IValue> seenKeys = new HashSet<IValue>();
  2330. for (IValue v : st) {
  2331. ITuple t = (ITuple) v;
  2332. IValue key = t.get(0);
  2333. IValue val = t.get(1);
  2334. if(seenKeys.contains(key))
  2335. throw RuntimeExceptionFactory.MultipleKey(key, null, null);
  2336. seenKeys.add(key);
  2337. w.put(key, val);
  2338. }
  2339. return w.done();
  2340. }
  2341. public IValue toMapUnique(IListRelation st)
  2342. // @doc{toMapUnique -- convert a set of tuples to a map; keys are unique}
  2343. {
  2344. Type tuple = st.getElementType();
  2345. Type resultType = types.mapType(tuple.getFieldType(0), tuple
  2346. .getFieldType(1));
  2347. IMapWriter w = resultType.writer(values);
  2348. HashSet<IValue> seenKeys = new HashSet<IValue>();
  2349. for (IValue v : st) {
  2350. ITuple t = (ITuple) v;
  2351. IValue key = t.get(0);
  2352. IValue val = t.get(1);
  2353. if(seenKeys.contains(key))
  2354. throw RuntimeExceptionFactory.MultipleKey(key, null, null);
  2355. seenKeys.add(key);
  2356. w.put(key, val);
  2357. }
  2358. return w.done();
  2359. }
  2360. public IValue toString(ISet st)
  2361. // @doc{toString -- convert a set to a string}
  2362. {
  2363. return values.string(st.toString());
  2364. }
  2365. /*
  2366. * String
  2367. */
  2368. public IBool isValidCharacter(IInteger i) {
  2369. return values.bool(Character.isValidCodePoint(i.intValue()));
  2370. }
  2371. public IValue stringChar(IInteger i) {
  2372. int intValue = i.intValue();
  2373. if (Character.isValidCodePoint(intValue)) {
  2374. return values.string(intValue);
  2375. }
  2376. else {
  2377. throw RuntimeExceptionFactory.illegalCharacter(i, null, null);
  2378. }
  2379. }
  2380. public IValue stringChars(IList lst){
  2381. int[] chars = new int[lst.length()];
  2382. for (int i = 0; i < lst.length(); i ++) {
  2383. chars[i] = ((IInteger) lst.get(i)).intValue();
  2384. if (!Character.isValidCodePoint(chars[i])) {
  2385. throw RuntimeExceptionFactory.illegalCharacter(values.integer(chars[i]), null, null);
  2386. }
  2387. }
  2388. return values.string(chars);
  2389. }
  2390. public IValue charAt(IString s, IInteger i) throws IndexOutOfBoundsException
  2391. //@doc{charAt -- return the character at position i in string s.}
  2392. {
  2393. try {
  2394. return values.integer(s.charAt(i.intValue()));
  2395. }
  2396. catch (IndexOutOfBoundsException e) {
  2397. throw RuntimeExceptionFactory.indexOutOfBounds(i, null, null);
  2398. }
  2399. }
  2400. public IValue endsWith(IString s, IString suffix)
  2401. //@doc{endWith -- returns true if string s ends with given string suffix.}
  2402. {
  2403. return values.bool(s.getValue().endsWith(suffix.getValue()));
  2404. }
  2405. public IString trim(IString s) {
  2406. return values.string(s.getValue().trim());
  2407. }
  2408. public IString squeeze(IString src, IString charSet) {
  2409. //@{http://commons.apache.org/lang/api-2.6/index.html?org/apache/commons/lang/text/package-summary.html}
  2410. String s = CharSetUtils.squeeze(src.getValue(), charSet.getValue());
  2411. return values.string(s);
  2412. }
  2413. public IString capitalize(IString src) {
  2414. return values.string(WordUtils.capitalize(src.getValue()));
  2415. }
  2416. public IString uncapitalize(IString src) {
  2417. return values.string(WordUtils.uncapitalize(src.getValue()));
  2418. }
  2419. public IList split(IString sep, IString src) {
  2420. String[] lst = src.getValue().split(Pattern.quote(sep.getValue()));
  2421. IListWriter lw = values.listWriter(types.stringType());
  2422. for (String s: lst) {
  2423. lw.append(values.string(s));
  2424. }
  2425. return lw.done();
  2426. }
  2427. public IString wrap(IString src, IInteger wrapLength) {
  2428. String s = WordUtils.wrap(src.getValue(), wrapLength.intValue());
  2429. return values.string(s);
  2430. }
  2431. public IValue format(IString s, IString dir, IInteger n, IString pad)
  2432. //@doc{format -- return string of length n, with s placed according to dir (left/center/right) and padded with pad}
  2433. {
  2434. StringBuffer res = new StringBuffer();
  2435. int sLen = s.getValue().length();
  2436. int nVal = n.intValue();
  2437. if(sLen > nVal){
  2438. return s;
  2439. }
  2440. int padLen = pad.getValue().length();
  2441. java.lang.String dirVal = dir.getValue();
  2442. int start;
  2443. if(dirVal.equals("right"))
  2444. start = nVal - sLen;
  2445. else if(dirVal.equals("center"))
  2446. start = (nVal - sLen)/2;
  2447. else
  2448. start = 0;
  2449. int i = 0;
  2450. while(i < start){
  2451. if(i + padLen < start){
  2452. res.append(pad.getValue());
  2453. i+= padLen;
  2454. } else {
  2455. res.append(pad.getValue().substring(0, start - i));
  2456. i += start -i;
  2457. }
  2458. }
  2459. res.append(s.getValue());
  2460. i = start + sLen;
  2461. while(i < nVal){
  2462. if(i + padLen < nVal){
  2463. res.append(pad.getValue());
  2464. i += padLen;
  2465. } else {
  2466. res.append(pad.getValue().substring(0, nVal - i));
  2467. i += nVal - i;
  2468. }
  2469. }
  2470. return values.string(res.toString());
  2471. }
  2472. public IValue isEmpty(IString s)
  2473. //@doc{isEmpty -- is string empty?}
  2474. {
  2475. return values.bool(s.getValue().length() == 0);
  2476. }
  2477. public IValue reverse(IString s)
  2478. //@doc{reverse -- return string with all characters in reverse order.}
  2479. {
  2480. return s.reverse();
  2481. }
  2482. public IValue size(IString s)
  2483. //@doc{size -- return the length of string s.}
  2484. {
  2485. return values.integer(s.length());
  2486. }
  2487. public IValue startsWith(IString s, IString prefix)
  2488. //@doc{startsWith -- return true if string s starts with the string prefix.}
  2489. {
  2490. return values.bool(s.getValue().startsWith(prefix.getValue()));
  2491. }
  2492. public IValue substring(IString s, IInteger begin) {
  2493. try {
  2494. return s.substring(begin.intValue());
  2495. } catch (IndexOutOfBoundsException e) {
  2496. throw RuntimeExceptionFactory.indexOutOfBounds(begin, null, null);
  2497. }
  2498. }
  2499. public IValue substring(IString s, IInteger begin, IInteger end) {
  2500. try {
  2501. return s.substring(begin.intValue(),end.intValue());
  2502. } catch (IndexOutOfBoundsException e) {
  2503. int bval = begin.intValue();
  2504. IInteger culprit = (bval < 0 || bval >= s.length()) ? begin : end;
  2505. throw RuntimeExceptionFactory.indexOutOfBounds(culprit, null, null);
  2506. }
  2507. }
  2508. public IValue toInt(IString s)
  2509. //@doc{toInt -- convert a string s to integer}
  2510. {
  2511. try {
  2512. java.lang.String sval = s.getValue();
  2513. boolean isNegative = false;
  2514. int radix = 10;
  2515. if (sval.equals("0")) {
  2516. return values.integer(0);
  2517. }
  2518. if (sval.startsWith("-")) {
  2519. isNegative = true;
  2520. sval = sval.substring(1);
  2521. }
  2522. if (sval.startsWith("0x") || sval.startsWith("0X")) {
  2523. radix = 16;
  2524. sval = sval.substring(2);
  2525. } else if (sval.startsWith("0")) {
  2526. radix = 8;
  2527. sval = sval.substring(1);
  2528. }
  2529. BigInteger bi = new BigInteger(isNegative ? "-" + sval : sval, radix);
  2530. return values.integer(bi.toString());
  2531. }
  2532. catch (NumberFormatException e){
  2533. throw RuntimeExceptionFactory.illegalArgument(null, null);
  2534. }
  2535. }
  2536. public IValue toInt(IString s, IInteger r)
  2537. {
  2538. try {
  2539. java.lang.String sval = s.getValue();
  2540. boolean isNegative = false;
  2541. int radix = r.intValue();
  2542. if (sval.equals("0")) {
  2543. return values.integer(0);
  2544. }
  2545. if (sval.startsWith("-")) {
  2546. isNegative = true;
  2547. sval = sval.substring(1);
  2548. }
  2549. BigInteger bi = new BigInteger(isNegative ? "-" + sval : sval, radix);
  2550. return values.integer(bi.toString());
  2551. }
  2552. catch (NumberFormatException e){
  2553. throw RuntimeExceptionFactory.illegalArgument(null, null);
  2554. }
  2555. }
  2556. public IValue toReal(IString s)
  2557. //@doc{toReal -- convert a string s to a real}
  2558. {
  2559. try {
  2560. return values.real(s.getValue());
  2561. }
  2562. catch (NumberFormatException e){
  2563. throw RuntimeExceptionFactory.illegalArgument(null, null);
  2564. }
  2565. }
  2566. public IValue toReal(IRational s)
  2567. //@doc{toReal -- convert a string s to a real}
  2568. {
  2569. return s.toReal();
  2570. }
  2571. public IValue toLowerCase(IString s)
  2572. //@doc{toLowerCase -- convert all characters in string s to lowercase.}
  2573. {
  2574. return values.string(s.getValue().toLowerCase());
  2575. }
  2576. public IValue toUpperCase(IString s)
  2577. //@doc{toUpperCase -- convert all characters in string s to uppercase.}
  2578. {
  2579. return values.string(s.getValue().toUpperCase());
  2580. }
  2581. private boolean match(char[] subject, int i, char [] pattern){
  2582. if(i + pattern.length > subject.length)
  2583. return false;
  2584. for(int k = 0; k < pattern.length; k++){
  2585. if(subject[i] != pattern[k])
  2586. return false;
  2587. i++;
  2588. }
  2589. return true;
  2590. }
  2591. public IValue replaceAll(IString str, IString find, IString replacement){
  2592. StringBuilder b = new StringBuilder(str.getValue().length() * 2);
  2593. char [] input = str.getValue().toCharArray();
  2594. char [] findChars = find.getValue().toCharArray();
  2595. char [] replChars = replacement.getValue().toCharArray();
  2596. int i = 0;
  2597. boolean matched = false;
  2598. while(i < input.length){
  2599. if(match(input,i,findChars)){
  2600. matched = true;
  2601. b.append(replChars);
  2602. i += findChars.length;
  2603. } else {
  2604. b.append(input[i]);
  2605. i++;
  2606. }
  2607. }
  2608. return (!matched) ? str : values.string(b.toString());
  2609. }
  2610. public IValue replaceFirst(IString str, IString find, IString replacement){
  2611. StringBuilder b = new StringBuilder(str.getValue().length() * 2);
  2612. char [] input = str.getValue().toCharArray();
  2613. char [] findChars = find.getValue().toCharArray();
  2614. char [] replChars = replacement.getValue().toCharArray();
  2615. int i = 0;
  2616. boolean matched = false;
  2617. while(i < input.length){
  2618. if(!matched && match(input,i,findChars)){
  2619. matched = true;
  2620. b.append(replChars);
  2621. i += findChars.length;
  2622. } else {
  2623. b.append(input[i]);
  2624. i++;
  2625. }
  2626. }
  2627. return (!matched) ? str : values.string(b.toString());
  2628. }
  2629. public IValue replaceLast(IString str, IString find, IString replacement){
  2630. StringBuilder b = new StringBuilder(str.getValue().length() * 2);
  2631. char [] input = str.getValue().toCharArray();
  2632. char [] findChars = find.getValue().toCharArray();
  2633. char [] replChars = replacement.getValue().toCharArray();
  2634. int i = input.length - findChars.length;
  2635. while(i >= 0){
  2636. if(match(input,i,findChars)){
  2637. for(int j = 0; j < i; j++)
  2638. b.append(input[j]);
  2639. b.append(replChars);
  2640. for(int j = i + findChars.length; j < input.length; j++)
  2641. b.append(input[j]);
  2642. return values.string(b.toString());
  2643. }
  2644. i--;
  2645. }
  2646. return str;
  2647. }
  2648. public IValue escape(IString str, IMap substitutions) {
  2649. StringBuilder b = new StringBuilder(str.getValue().length() * 2);
  2650. char[] input = str.getValue().toCharArray();
  2651. for (char c : input) {
  2652. IString sub = (IString) substitutions.get(values.string(Character.toString(c)));
  2653. if (sub != null) {
  2654. b.append(sub.getValue());
  2655. }
  2656. else {
  2657. b.append(c);
  2658. }
  2659. }
  2660. return values.string(b.toString());
  2661. }
  2662. public IValue contains(IString str, IString find){
  2663. return values.bool(str.getValue().indexOf(find.getValue()) >= 0);
  2664. }
  2665. public IValue findAll(IString str, IString find){
  2666. char[] input = str.getValue().toCharArray();
  2667. char [] findChars = find.getValue().toCharArray();
  2668. IListWriter w = values.listWriter(types.integerType());
  2669. for(int i = 0; i <= input.length - findChars.length; i++){
  2670. if(match(input, i, findChars)){
  2671. w.append(values.integer(i));
  2672. }
  2673. }
  2674. return w.done();
  2675. }
  2676. public IValue findFirst(IString str, IString find){
  2677. char[] input = str.getValue().toCharArray();
  2678. char [] findChars = find.getValue().toCharArray();
  2679. for(int i = 0; i <= input.length - findChars.length; i++){
  2680. if(match(input, i, findChars)){
  2681. return values.integer(i);
  2682. }
  2683. }
  2684. return values.integer(-1);
  2685. }
  2686. public IValue findLast(IString str, IString find){
  2687. char[] input = str.getValue().toCharArray();
  2688. char [] findChars = find.getValue().toCharArray();
  2689. for(int i = input.length - findChars.length; i >= 0; i--){
  2690. if(match(input, i, findChars)){
  2691. return values.integer(i);
  2692. }
  2693. }
  2694. return values.integer(-1);
  2695. }
  2696. /*
  2697. * ToString
  2698. */
  2699. public IString toString(IValue value)
  2700. {
  2701. if (value.getType() == Factory.Tree) {
  2702. return values.string(TreeAdapter.yield((IConstructor) value));
  2703. }
  2704. else if (value.getType().isSubtypeOf(Factory.Type)) {
  2705. return values.string(SymbolAdapter.toString((IConstructor) ((IConstructor) value).get("symbol")));
  2706. }
  2707. if (value.getType().isStringType()) {
  2708. return (IString) value;
  2709. }
  2710. return values.string(value.toString());
  2711. }
  2712. /*
  2713. * !!EXPERIMENTAL!!
  2714. * Tuple
  2715. */
  2716. public IList fieldsOf(IValue v){
  2717. if(!v.getType().isTupleType())
  2718. throw RuntimeExceptionFactory.illegalArgument(v, null, null, "argument of type tuple is required");
  2719. ITuple tp = (ITuple) v;
  2720. Type tt = tp.getType();
  2721. int a = tt.getArity();
  2722. Type listType = types.listType(types.stringType());
  2723. IListWriter w = listType.writer(values);
  2724. for(int i = 0; i < a; i++){
  2725. String fname = tt.getFieldName(i);
  2726. if(fname == null)
  2727. fname = "";
  2728. w.append(values.string(fname));
  2729. }
  2730. return w.done();
  2731. }
  2732. /*
  2733. * ValueIO
  2734. */
  2735. public IValue readBinaryValueFile(IValue type, ISourceLocation loc, IEvaluatorContext ctx){
  2736. TypeStore store = new TypeStore();
  2737. Type start = tr.valueToType((IConstructor) type, store);
  2738. InputStream in = null;
  2739. try{
  2740. in = ctx.getResolverRegistry().getInputStream(loc.getURI());
  2741. return new BinaryValueReader().read(values, store, start, in);
  2742. }catch(IOException e){
  2743. throw RuntimeExceptionFactory.io(values.string(e.getMessage()), null, null);
  2744. }catch(Exception e){
  2745. e.printStackTrace();
  2746. throw RuntimeExceptionFactory.io(values.string(e.getMessage()), null, null);
  2747. }finally{
  2748. if(in != null){
  2749. try{
  2750. in.close();
  2751. }catch(IOException ioex){
  2752. throw RuntimeExceptionFactory.io(values.string(ioex.getMessage()), null, null);
  2753. }
  2754. }
  2755. }
  2756. }
  2757. public IValue readTextValueFile(IValue type, ISourceLocation loc, IEvaluatorContext ctx){
  2758. TypeStore store = new TypeStore();
  2759. Type start = tr.valueToType((IConstructor) type, store);
  2760. InputStream in = null;
  2761. try{
  2762. in = ctx.getResolverRegistry().getInputStream(loc.getURI());
  2763. return new StandardTextReader().read(values, store, start, new InputStreamReader(in, "UTF8"));
  2764. }catch(IOException e){
  2765. throw RuntimeExceptionFactory.io(values.string(e.getMessage()), null, null);
  2766. }finally{
  2767. if(in != null){
  2768. try{
  2769. in.close();
  2770. }catch(IOException ioex){
  2771. throw RuntimeExceptionFactory.io(values.string(ioex.getMessage()), null, null);
  2772. }
  2773. }
  2774. }
  2775. }
  2776. public IValue readTextValueString(IValue type, IString input) {
  2777. TypeStore store = new TypeStore();
  2778. Type start = tr.valueToType((IConstructor) type, store);
  2779. StringReader in = new StringReader(input.getValue());
  2780. try {
  2781. return new StandardTextReader().read(values, store, start, in);
  2782. } catch (FactTypeUseException e) {
  2783. throw RuntimeExceptionFactory.io(values.string(e.getMessage()), null, null);
  2784. } catch (IOException e) {
  2785. throw RuntimeExceptionFactory.io(values.string(e.getMessage()), null, null);
  2786. }
  2787. }
  2788. public void writeBinaryValueFile(ISourceLocation loc, IValue value, IEvaluatorContext ctx){
  2789. OutputStream out = null;
  2790. try{
  2791. out = ctx.getResolverRegistry().getOutputStream(loc.getURI(), false);
  2792. new BinaryValueWriter().write(value, out);
  2793. }catch (IOException ioex){
  2794. throw RuntimeExceptionFactory.io(values.string(ioex.getMessage()), null, null);
  2795. }finally{
  2796. if(out != null){
  2797. try{
  2798. out.close();
  2799. }catch(IOException ioex){
  2800. throw RuntimeExceptionFactory.io(values.string(ioex.getMessage()), null, null);
  2801. }
  2802. }
  2803. }
  2804. }
  2805. public void writeTextValueFile(ISourceLocation loc, IValue value, IEvaluatorContext ctx){
  2806. OutputStream out = null;
  2807. try{
  2808. out = ctx.getResolverRegistry().getOutputStream(loc.getURI(), false);
  2809. new StandardTextWriter().write(value, new OutputStreamWriter(out, "UTF8"));
  2810. }
  2811. catch(IOException e) {
  2812. throw RuntimeExceptionFactory.io(values.string(e.getMessage()), null, null);
  2813. }
  2814. finally {
  2815. if (out != null) {
  2816. try {
  2817. out.flush();
  2818. out.close();
  2819. }
  2820. catch(IOException ioex) {
  2821. throw RuntimeExceptionFactory.io(values.string(ioex.getMessage()), ctx.getCurrentAST(), ctx.getStackTrace());
  2822. }
  2823. }
  2824. }
  2825. }
  2826. public IBool rexpMatch(IString s, IString re) {
  2827. if(Pattern.matches(re.getValue(), s.getValue()))
  2828. return values.bool(true);
  2829. else
  2830. return values.bool(false);
  2831. }
  2832. }
  2833. // Utilities used by Graph
  2834. //TODO: Why is this code in the library? This should be done in pure Rascal.
  2835. class Distance{
  2836. public int intval;
  2837. Distance(int n){
  2838. intval = n;
  2839. }
  2840. }
  2841. class NodeComparator implements Comparator<IValue> {
  2842. private final HashMap<IValue,Distance> distance;
  2843. NodeComparator(HashMap<IValue,Distance> distance){
  2844. this.distance = distance;
  2845. }
  2846. public int compare(IValue arg0, IValue arg1) {
  2847. int d0 = distance.get(arg0).intval;
  2848. int d1 = distance.get(arg1).intval;
  2849. return d0 < d1 ? -1 : ((d0 == d1) ? 0 : 1);
  2850. }
  2851. }