001/*
002 * Copyright (c) 2012-2018 Institut National des Sciences Appliquées de Lyon (INSA Lyon) and others
003 *
004 * This program and the accompanying materials are made available under the
005 * terms of the Eclipse Public License 2.0 which is available at
006 * http://www.eclipse.org/legal/epl-2.0.
007 *
008 * SPDX-License-Identifier: EPL-2.0
009 */
010package gololang;
011
012import org.eclipse.golo.runtime.AmbiguousFunctionReferenceException;
013
014import java.io.File;
015import java.io.IOException;
016import java.lang.invoke.MethodHandleProxies;
017import java.lang.invoke.MethodHandles;
018import java.lang.reflect.Method;
019import java.lang.reflect.Parameter;
020import java.math.BigInteger;
021import java.math.BigDecimal;
022import java.nio.charset.Charset;
023import java.nio.file.Path;
024import java.util.*;
025import java.util.function.Predicate;
026import java.util.stream.Stream;
027import org.objectweb.asm.Type;
028import org.eclipse.golo.runtime.Extractors;
029import org.eclipse.golo.runtime.Loader;
030import org.eclipse.golo.runtime.WithCaller;
031
032import static java.lang.invoke.MethodHandles.dropArguments;
033import static java.lang.reflect.Modifier.isStatic;
034import static org.eclipse.golo.runtime.DecoratorsHelper.isMethodDecorated;
035import static org.eclipse.golo.runtime.DecoratorsHelper.getDecoratedMethodHandle;
036import static java.util.stream.Collectors.toList;
037
038/**
039 * <code>Predefined</code> provides the module of predefined functions in Golo. The provided module is imported by
040 * default.
041 */
042public final class Predefined {
043
044  private Predefined() {
045    throw new UnsupportedOperationException("Why on earth are you trying to instantiate this class?");
046  }
047
048  // ...................................................................................................................
049  /**
050   * Raises a <code>RuntimeException</code> with a message.
051   *
052   * @param message the exception description.
053   * @throws RuntimeException (always)
054   */
055  public static void raise(Object message) {
056    require(message instanceof String, "raise requires a message as a String");
057    throw new RuntimeException((String) message);
058  }
059
060  /**
061   * Raises a <code>RuntimeException</code> with a message and a cause.
062   *
063   * @param message the exception description.
064   * @param cause   the exception cause.
065   * @throws RuntimeException (always)
066   */
067  public static void raise(Object message, Object cause) {
068    require(message instanceof String, "raise requires a message as a String");
069    require(cause instanceof Throwable, "raise requires a cause as a Throwable");
070    throw new RuntimeException((String) message, (Throwable) cause);
071  }
072
073  // ...................................................................................................................
074  /**
075   * Prints to the standard console.
076   *
077   * @param obj the object to be printed.
078   */
079  public static void print(Object obj) {
080    System.out.print(obj);
081  }
082
083  /**
084   * Prints to the standard console, including a newline.
085   *
086   * @param obj obj the object to be printed.
087   */
088  public static void println(Object obj) {
089    System.out.println(obj);
090  }
091
092  /**
093   * Reads the next line of characters from the console.
094   *
095   * @return a String.
096   *
097   * @deprecated Since 3.3, use {@link gololang.IO#readln()}. Will be removed in 4.0
098   */
099  @Deprecated
100  public static String readln() throws IOException {
101    // TODO: remove in 4.0
102    return gololang.IO.readln();
103  }
104
105  /**
106   * Reads the next line of characters from the console.
107   *
108   * @param message displays a prompt message.
109   * @return a String.
110   *
111   * @deprecated Since 3.3, use {@link gololang.IO#readln(String)}. Will be removed in 4.0
112   */
113  @Deprecated
114  public static String readln(String message) throws IOException {
115    // TODO: remove in 4.0
116    return gololang.IO.readln(message);
117  }
118
119  /**
120   * Reads a password from the console with echoing disabled.
121   *
122   * @return a String.
123   *
124   * @deprecated Since 3.3, use {@link gololang.IO#readPassword()}. Will be removed in 4.0
125   */
126  @Deprecated
127  public static String readPassword() throws IOException {
128    // TODO: remove in 4.0
129    return gololang.IO.readPassword();
130  }
131
132  /**
133   * Reads a password from the console with echoing disabled.
134   *
135   * @param message displays a prompt message.
136   * @return a String.
137   *
138   * @deprecated Since 3.3, use {@link gololang.IO#readPassword(String)}. Will be removed in 4.0
139   */
140  @Deprecated
141  public static String readPassword(String message) throws IOException {
142    // TODO: remove in 4.0
143    return gololang.IO.readPassword(message);
144  }
145
146  /**
147   * Reads a password from the console with echoing disabled, returning an {@code char[]} array.
148   *
149   * @return a character array.
150   *
151   * @deprecated Since 3.3, use {@link gololang.IO#secureReadPassword()}. Will be removed in 4.0
152   */
153  @Deprecated
154  public static char[] secureReadPassword() throws IOException {
155    // TODO: remove in 4.0
156    return gololang.IO.secureReadPassword();
157  }
158
159  /**
160   * Reads a password from the console with echoing disabled, returning an {@code char[]} array.
161   *
162   * @param message displays a prompt message.
163   * @return a character array.
164   *
165   * @deprecated Since 3.3, use {@link gololang.IO#secureReadPassword(String)}. Will be removed in 4.0
166   */
167  @Deprecated
168  public static char[] secureReadPassword(String message) throws IOException {
169    // TODO: remove in 4.0
170    return gololang.IO.secureReadPassword(message);
171  }
172
173  // ...................................................................................................................
174  /**
175   * Requires that an object is not the <code>null</code> reference.
176   *
177   * @param obj the object to test against <code>null</code>.
178   * @throws AssertionError if <code>obj</code> is <code>null</code>.
179   */
180  public static void requireNotNull(Object obj) throws AssertionError {
181    if (obj != null) {
182      return;
183    }
184    throw new AssertionError("null reference encountered");
185  }
186
187  /**
188   * Requires that a condition be <code>true</code>.
189   *
190   * @param condition    the condition, must be a <code>Boolean</code>.
191   * @param errorMessage the error message, must be a <code>String</code>.
192   * @throws IllegalArgumentException if the arguments are of the wrong type.
193   * @throws AssertionError           if <code>condition</code> is <code>false</code>.
194   */
195  public static void require(Object condition, Object errorMessage) throws IllegalArgumentException, AssertionError {
196    requireNotNull(condition);
197    requireNotNull(errorMessage);
198    if ((condition instanceof Boolean) && (errorMessage instanceof String)) {
199      if ((Boolean) condition) {
200        return;
201      }
202      throw new AssertionError(errorMessage);
203    } else {
204      throw new IllegalArgumentException(
205          new StringBuilder()
206          .append("Wrong parameters for require: expected (Boolean, String) but got (")
207          .append(condition.getClass().getName())
208          .append(", ")
209          .append(errorMessage.getClass().getName())
210          .append(")")
211          .toString());
212    }
213  }
214
215  // ...................................................................................................................
216  /**
217   * Makes a new typed JVM array.
218   *
219   * This function simply forwards to {@code java.lang.reflect.Array.newInstance}.
220   *
221   * @param type   the array type.
222   * @param length the array length.
223   * @return a new typed array.
224   */
225  public static Object newTypedArray(Class<?> type, int length) {
226    return java.lang.reflect.Array.newInstance(type, length);
227  }
228
229  // ...................................................................................................................
230  private static void checkRangeTypes(Object value, String name) {
231    require((value instanceof Integer)
232        || (value instanceof Long)
233        || (value instanceof Character)
234        || (value instanceof BigInteger),
235        name + " must either be an Integer, Long, Character or BigInteger");
236  }
237
238  /**
239   * Makes an range object between two bounds. Range objects implement
240   * <code>java.lang.Collection</code> (immutable), so they can be used in Golo <code>foreach</code>
241   * loops.
242   *
243   * @param from the lower-bound (inclusive) as an {@code Integer}, {@code Long}, {@code Character} or {@code BigInteger}.
244   * @param to   the upper-bound (exclusive) as an {@code Integer}, {@code Long}, {@code Character} or {@code BigInteger}.
245   * @return a range object.
246   * @see java.util.Collection
247   */
248  public static Object range(Object from, Object to) {
249    checkRangeTypes(from, "from");
250    checkRangeTypes(to, "to");
251    if ((from instanceof Character && !(to instanceof Character))
252        || (to instanceof Character && !(from instanceof Character))) {
253      throw new IllegalArgumentException("both bounds must be char for a char range");
254    }
255    if (to instanceof Character && from instanceof Character) {
256      return new CharRange((Character) from, (Character) to);
257    }
258    if (to instanceof Integer && from instanceof Integer) {
259      return new IntRange((Integer) from, (Integer) to);
260    }
261    if (to instanceof Long && from instanceof Long) {
262      return new LongRange((Long) from, (Long) to);
263    }
264    if (from instanceof BigInteger || to instanceof BigInteger) {
265      return new BigIntegerRange(bigIntegerValue(from), bigIntegerValue(to));
266    }
267    if (from instanceof Long) {
268      return new LongRange((Long) from, (Integer) to);
269    }
270    return new LongRange((Integer) from, (Long) to);
271  }
272
273  /**
274   * Makes an range object starting from the default value.
275   * <p>
276   * The default value is 0 for numbers and 'A' for chars.
277   *
278   * @param to the upper-bound (exclusive) as an {@code Integer}, {@code Long}, {@code Character} or {@code BigInteger}.
279   * @return a range object.
280   * @see gololang.Predefined#range
281   */
282  public static Object range(Object to) {
283    checkRangeTypes(to, "to");
284    if (to instanceof Integer) {
285      return new IntRange((Integer) to);
286    }
287    if (to instanceof Long) {
288      return new LongRange((Long) to);
289    }
290    if (to instanceof BigInteger) {
291      return new BigIntegerRange((BigInteger) to);
292    }
293    return new CharRange((Character) to);
294  }
295
296  /**
297   * Makes an decreasing range object between two bounds. Range objects implement <code>java.lang.Collection</code>, so
298   * they can be used in Golo <code>foreach</code> loops.
299   *
300   * @param from the upper-bound (inclusive) as an {@code Integer}, {@code Long}, {@code Character} or {@code BigInteger}.
301   * @param to   the lower-bound (exclusive) as an {@code Integer}, {@code Long}, {@code Character} or {@code BigInteger}.
302   * @return a range object.
303   * @see gololang.Predefined#range
304   */
305  public static Object reversedRange(Object from, Object to) {
306    return ((Range<?>) range(from, to)).incrementBy(-1);
307  }
308
309  /**
310   * Makes an decreasing range object up to the default value.
311   * <p>
312   * The default value is 0 for numbers and 'A' for chars.
313   *
314   * @param from the upper-bound (inclusive) as an {@code Integer}, {@code Long}, {@code Character} or {@code BigInteger}.
315   * @return a range object.
316   * @see gololang.Predefined#reversedRange
317   * @see gololang.Predefined#range
318   */
319  public static Object reversedRange(Object from) {
320    return ((Range<?>) range(from)).reversed();
321  }
322
323  // ...................................................................................................................
324  /**
325   * Makes a key / value pair.
326   *
327   * @param key   the key.
328   * @param value the value.
329   * @return an instance of <code>AbstractMap.SimpleEntry</code>
330   * @see java.util.AbstractMap.SimpleEntry
331   */
332  public static Object mapEntry(Object key, Object value) {
333    return new AbstractMap.SimpleEntry<>(key, value);
334  }
335
336  // ...................................................................................................................
337  /**
338   * Turns a function reference into an instance of a single-method interface.
339   *
340   * @param interfaceClass the target single-method interface class.
341   * @param target         the implementation function reference.
342   * @return an instance of {@code interfaceClass}.
343   * @see java.lang.invoke.MethodHandleProxies#asInterfaceInstance(Class, java.lang.invoke.MethodHandle)
344   */
345  public static Object asInterfaceInstance(Object interfaceClass, Object target) {
346    require(interfaceClass instanceof Class, "interfaceClass must be a Class");
347    require(target instanceof FunctionReference, "target must be a FunctionReference");
348    return MethodHandleProxies.asInterfaceInstance((Class<?>) interfaceClass, ((FunctionReference) target).handle());
349  }
350
351  /**
352   * Turns a function reference into an instance of a Java 8 functional interface.
353   *
354   * The implementation delegates to Golo adapter fabrics.
355   *
356   * @param type the functional interface class.
357   * @param func the implementation function.
358   * @return an instance of {@code type}.
359   * @throws Throwable if the adaptation fails.
360   * @see gololang.GoloAdapter
361   */
362  public static Object asFunctionalInterface(Object type, Object func) throws Throwable {
363    require(type instanceof Class, "type must be a Class");
364    require(func instanceof FunctionReference, "func must be a FunctionReference");
365    Class<?> theType = (Class<?>) type;
366    for (Method method : theType.getMethods()) {
367      if (!method.isDefault() && !isStatic(method.getModifiers())) {
368        Map<String, Object> configuration = new HashMap<>();
369        configuration.put("interfaces", new Tuple(theType.getCanonicalName()));
370        Map<String, FunctionReference> implementations = new HashMap<>();
371        implementations.put(
372            method.getName(),
373            new FunctionReference(
374                dropArguments(((FunctionReference) func).handle(), 0, Object.class),
375                Arrays.stream(method.getParameters())
376                .map(Parameter::getName)
377                .toArray(String[]::new)));
378        configuration.put("implements", implementations);
379        return new AdapterFabric().maker(configuration).newInstance();
380      }
381    }
382    throw new RuntimeException("Could not convert " + func + " to a functional interface of type " + type);
383  }
384
385  /**
386   * Test whether an object is a closure or not.
387   *
388   * @param object the object.
389   * @return {@code true} if {@code object} is an instance of {@link gololang.FunctionReference} {@code false} otherwise.
390   */
391  public static boolean isClosure(Object object) {
392    return object instanceof FunctionReference;
393  }
394
395  // ...................................................................................................................
396  /**
397   * Obtains a reference to a function.
398   *
399   * @param name   the function name.
400   * @param module the function enclosing module (a Java class).
401   * @param arity  the function arity, where a negative value means that any arity will do.
402   * @param varargs if the functions has variable arity.
403   * @return a function reference to the matched function.
404   * @throws NoSuchMethodException    if the target function could not be found.
405   * @throws IllegalArgumentException if the argument types are not of types <code>(String, Class, Integer)</code>.
406   * @throws Throwable                if an error occurs.
407   */
408  @WithCaller
409  public static FunctionReference fun(Class<?> caller, Object name, Object module, Object arity, Object varargs) throws Throwable {
410    require(name instanceof String, "name must be a String");
411    require(module instanceof Class, "module must be a module (e.g., foo.bar.Some.module)");
412    require(arity instanceof Integer, "name must be an Integer");
413    require(varargs instanceof Boolean, "varargs must be a Boolean");
414    final Class<?> moduleClass = (Class<?>) module;
415    final String functionName = (String) name;
416    final int functionArity = (Integer) arity;
417    final boolean isVarargs = (Boolean) varargs;
418    Method targetMethod = null;
419    Predicate<Method> candidate = Extractors.matchFunctionReference(functionName, functionArity, isVarargs);
420    final List<Method> validCandidates = Extractors.getMethods(moduleClass)
421        .filter(candidate)
422        .collect(toList());
423    if (validCandidates.size() == 1) {
424      targetMethod = validCandidates.get(0);
425      if (module == caller || caller == null) {
426        targetMethod.setAccessible(true);
427      }
428      return toFunctionReference(targetMethod, functionArity);
429    }
430    if (validCandidates.size() > 1) {
431      // TODO: return the first method, printing a warning
432      throw new AmbiguousFunctionReferenceException(("The reference to " + name + " in " + module
433          + ((functionArity < 0) ? "" : (" with arity " + functionArity))
434          + " is ambiguous"));
435    }
436    Optional<Method> target = getImportedFunctions(moduleClass).filter(candidate).findFirst();
437    if (target.isPresent()) {
438      return toFunctionReference(target.get(), functionArity);
439    }
440    throw new NoSuchMethodException((name + " in " + module
441        + (functionArity < 0 ? "" : (" with arity " + functionArity))));
442  }
443
444  /**
445   * Obtains the first reference to a function.
446   * <p>
447   * This is the same as calling {@code fun(name, module, arity, false)}.
448   *
449   * @see #fun(Class, Object, Object, Object, Object)
450   */
451  @WithCaller
452  public static FunctionReference fun(Class<?> caller, Object name, Object module, Object arity) throws Throwable {
453    return fun(caller, name, module, arity, false);
454  }
455
456  /**
457   * Obtains the first reference to a function.
458   * <p>
459   * This is the same as calling {@code fun(name, module, -1)}.
460   *
461   * @see #fun(Class, Object, Object, Object)
462   */
463  @WithCaller
464  public static FunctionReference fun(Class<?> caller, Object name, Object module) throws Throwable {
465    return fun(caller, name, module, -1);
466  }
467
468  public static FunctionReference toFunctionReference(Method targetMethod, int functionArity) throws Throwable {
469    String[] parameterNames = Arrays.stream(targetMethod.getParameters())
470        .map(Parameter::getName)
471        .toArray(String[]::new);
472    if (isMethodDecorated(targetMethod)) {
473      return new FunctionReference(getDecoratedMethodHandle(targetMethod, functionArity), parameterNames);
474    }
475    return new FunctionReference(MethodHandles.publicLookup().unreflect(targetMethod), parameterNames);
476  }
477
478  private static Stream<Method> getImportedFunctions(Class<?> source) {
479    return Extractors.getImportedNames(source)
480        .map(Loader.forClass(source))
481        .filter(Objects::nonNull)
482        .flatMap(Extractors::getMethods)
483        .filter(Extractors::isPublic);
484  }
485
486  // ...................................................................................................................
487  /**
488   * Reads the content of a text file.
489   *
490   * @param file     the file to read from as an instance of either {@link String}, {@link File} or {@link Path}.
491   * @param encoding the file encoding as a {@link String} or {@link Charset}.
492   * @return the content as a {@link String}.
493   *
494   * @deprecated Since 3.3, use {@link gololang.IO#fileToText(Object, Object)}. Will be removed in 4.0
495   */
496  @Deprecated
497  public static Object fileToText(Object file, Object encoding) throws Throwable {
498    // TODO: remove in 4.0
499    return gololang.IO.fileToText(file, encoding);
500  }
501
502  /**
503   * Writes some text to a file.
504   *
505   * The file and parents directories are created if they does not exist. The file is overwritten if it already exists. If the file is {@code "-"}, the content is written to standard output.
506   *
507   * @param text the text to write.
508   * @param file the file to write to as an instance of either {@link String}, {@link File} or {@link Path}.
509   *
510   * @deprecated Since 3.3, use {@link gololang.IO#textToFile(Object, Object)}. Will be removed in 4.0
511   */
512  @Deprecated
513  public static void textToFile(Object text, Object file) throws Throwable {
514    // TODO: remove in 4.0
515    gololang.IO.textToFile(text, file);
516  }
517
518  /**
519   * Writes some text to a file using the given {@link Charset}.
520   *
521   * The file and parents directories are created if they does not exist. The file is overwritten if it already exists. If the file is {@code "-"}, the content is written to standard output.
522   *
523   * @param text the text to write.
524   * @param file the file to write to as an instance of either {@link String}, {@link File} or {@link Path}.
525   * @param charset the charset to encode the text in.
526   * @deprecated Since 3.3, use {@link gololang.IO#textToFile(Object, Object, Object)}. Will be removed in 4.0
527   */
528  @Deprecated
529  public static void textToFile(Object text, Object file, Object charset) throws Throwable {
530    // TODO: remove in 4.0
531    gololang.IO.textToFile(text, file, charset);
532  }
533
534  /**
535   * Check if a file exists.
536   *
537   * @param file the file to read from as an instance of either {@link String}, {@link File} or {@link Path}.
538   * @return true if the file exists, false if it doesn't
539   *
540   * @deprecated Since 3.3, use {@link gololang.IO#fileExists(Object)}. Will be removed in 4.0
541   */
542  @Deprecated
543  public static boolean fileExists(Object file) {
544    // TODO: remove in 4.0
545    return gololang.IO.fileExists(file);
546  }
547
548  /**
549   * Return current path of execution.
550   *
551   * @return current path of execution
552   */
553  public static String currentDir() throws Throwable {
554    return new File(".").getCanonicalPath();
555  }
556
557  /**
558   * Sleep on the current thread.
559   *
560   * @param ms time in milliseconds.
561   * @throws InterruptedException in case the thread gets interrupted.
562   */
563  public static void sleep(long ms) throws InterruptedException {
564    java.lang.Thread.sleep(ms);
565  }
566
567  /**
568   * Return a universally unique identifier as String.
569   *
570   * @return a universally unique identifier as String
571   */
572  public static String uuid() {
573    return java.util.UUID.randomUUID().toString();
574  }
575
576  // ...................................................................................................................
577  /**
578   * Checks if an object is a (JVM) array or not.
579   *
580   * @param object the object to check.
581   * @return {@code true} if {@code object} is an array, {@code false} otherwise or if {@code null}.
582   */
583  public static boolean isArray(Object object) {
584    return (object != null) && object.getClass().isArray();
585  }
586
587  /**
588   * Function to obtain the {@code Object[].class} reference.
589   *
590   * @return {@code Object[].class}
591   */
592  public static Class<?> objectArrayType() {
593    return Object[].class;
594  }
595
596  /**
597   * Returns an array class given a type class.
598   *
599   * @param klass the array type.
600   * @return the class of the array of type {@code klass}, i.e., {@code klass[]}.
601   * @throws ClassNotFoundException if the type could not be found.
602   */
603  public static Class<?> arrayTypeOf(Object klass) throws ClassNotFoundException {
604    require(klass instanceof Class<?>, "klass must be a class");
605    Class<?> type = (Class<?>) klass;
606    return Class.forName("[" + intertnalDescriptorFormClass(type), true, type.getClassLoader());
607  }
608
609  private static String intertnalDescriptorFormClass(Class<?> clazz) {
610    return Type.getDescriptor(clazz).replaceAll("/", ".");
611  }
612
613  // ...................................................................................................................
614  // These are generated methods, see src/main/ruby/generate_type_conversions.rb
615  /**
616   * Gives the Character value of some number or String object.
617   *
618   * @param obj a boxed number or String value.
619   * @return the Character value.
620   * @throws IllegalArgumentException if {@code obj} is not a number or a String.
621   */
622  public static Object charValue(Object obj) throws IllegalArgumentException {
623    if (obj instanceof Character) {
624      return obj;
625    }
626    if (obj instanceof Integer) {
627      int value = (Integer) obj;
628      return (char) value;
629    }
630    if (obj instanceof Long) {
631      long value = (Long) obj;
632      return (char) value;
633    }
634    if (obj instanceof Double) {
635      double value = (Double) obj;
636      return (char) value;
637    }
638    if (obj instanceof Float) {
639      float value = (Float) obj;
640      return (char) value;
641    }
642    if (obj instanceof Number) {
643      return (char) ((Number) obj).doubleValue();
644    }
645    if (obj instanceof String) {
646      return ((String) obj).charAt(0);
647    }
648    throw new IllegalArgumentException("Expected a number or a string, but got: " + obj);
649  }
650
651  /**
652   * Gives the Integer value of some number or String object.
653   *
654   * @param obj a boxed number or String value.
655   * @return the Integer value.
656   * @throws IllegalArgumentException if {@code obj} is not a number or a String.
657   */
658  public static Object intValue(Object obj) throws IllegalArgumentException {
659    if (obj instanceof Integer) {
660      return obj;
661    }
662    if (obj instanceof Character) {
663      char value = (Character) obj;
664      return (int) value;
665    }
666    if (obj instanceof Long) {
667      long value = (Long) obj;
668      return (int) value;
669    }
670    if (obj instanceof Double) {
671      double value = (Double) obj;
672      return (int) value;
673    }
674    if (obj instanceof Float) {
675      float value = (Float) obj;
676      return (int) value;
677    }
678    if (obj instanceof Number) {
679      return ((Number) obj).intValue();
680    }
681    if (obj instanceof String) {
682      return Integer.valueOf((String) obj);
683    }
684    throw new IllegalArgumentException("Expected a number or a string, but got: " + obj);
685  }
686
687  /**
688   * Gives the Long value of some number or String object.
689   *
690   * @param obj a boxed number or String value.
691   * @return the Long value.
692   * @throws IllegalArgumentException if {@code obj} is not a number or a String.
693   */
694  public static Object longValue(Object obj) throws IllegalArgumentException {
695    if (obj instanceof Long) {
696      return obj;
697    }
698    if (obj instanceof Character) {
699      char value = (Character) obj;
700      return (long) value;
701    }
702    if (obj instanceof Integer) {
703      int value = (Integer) obj;
704      return (long) value;
705    }
706    if (obj instanceof Double) {
707      double value = (Double) obj;
708      return (long) value;
709    }
710    if (obj instanceof Float) {
711      float value = (Float) obj;
712      return (long) value;
713    }
714    if (obj instanceof Number) {
715      return ((Number) obj).longValue();
716    }
717    if (obj instanceof String) {
718      return Long.valueOf((String) obj);
719    }
720    throw new IllegalArgumentException("Expected a number or a string, but got: " + obj);
721  }
722
723  /**
724   * Gives the Double value of some number or String object.
725   *
726   * @param obj a boxed number or String value.
727   * @return the Double value.
728   * @throws IllegalArgumentException if {@code obj} is not a number or a String.
729   */
730  public static Object doubleValue(Object obj) throws IllegalArgumentException {
731    if (obj instanceof Double) {
732      return obj;
733    }
734    if (obj instanceof Character) {
735      char value = (Character) obj;
736      return (double) value;
737    }
738    if (obj instanceof Integer) {
739      int value = (Integer) obj;
740      return (double) value;
741    }
742    if (obj instanceof Long) {
743      long value = (Long) obj;
744      return (double) value;
745    }
746    if (obj instanceof Float) {
747      float value = (Float) obj;
748      return (double) value;
749    }
750    if (obj instanceof Number) {
751      return ((Number) obj).doubleValue();
752    }
753    if (obj instanceof String) {
754      return Double.valueOf((String) obj);
755    }
756    throw new IllegalArgumentException("Expected a number or a string, but got: " + obj);
757  }
758
759  /**
760   * Gives the Float value of some number or String object.
761   *
762   * @param obj a boxed number or String value.
763   * @return the Float value.
764   * @throws IllegalArgumentException if {@code obj} is not a number or a String.
765   */
766  public static Object floatValue(Object obj) throws IllegalArgumentException {
767    if (obj instanceof Float) {
768      return obj;
769    }
770    if (obj instanceof Character) {
771      char value = (Character) obj;
772      return (float) value;
773    }
774    if (obj instanceof Integer) {
775      int value = (Integer) obj;
776      return (float) value;
777    }
778    if (obj instanceof Long) {
779      long value = (Long) obj;
780      return (float) value;
781    }
782    if (obj instanceof Double) {
783      double value = (Double) obj;
784      return (float) value;
785    }
786    if (obj instanceof Number) {
787      return ((Number) obj).floatValue();
788    }
789    if (obj instanceof String) {
790      return Float.valueOf((String) obj);
791    }
792    throw new IllegalArgumentException("Expected a number or a string, but got: " + obj);
793  }
794  // END GENERATED .....................................................................................................
795
796  /**
797   * Gives the BigDecimal value of some number or String object.
798   *
799   * @param obj a boxed number or String value.
800   * @return the Float value.
801   * @throws IllegalArgumentException if {@code obj} is not a number or a String.
802   */
803  public static BigDecimal bigDecimalValue(Object obj) throws IllegalArgumentException {
804    if (obj instanceof BigDecimal) {
805      return (BigDecimal) obj;
806    }
807    if (obj instanceof BigInteger) {
808      return new BigDecimal((BigInteger) obj);
809    }
810    if (obj instanceof Number) {
811      return BigDecimal.valueOf(((Number) obj).doubleValue());
812    }
813    if (obj instanceof Character) {
814      char value = (Character) obj;
815      return BigDecimal.valueOf((long) value);
816    }
817    if (obj instanceof String) {
818      return new BigDecimal((String) obj);
819    }
820    throw new IllegalArgumentException("Expected a number or a string, but got: " + obj);
821  }
822
823  /**
824   * Gives the BigInteger value of some number or String object.
825   *
826   * @param obj a boxed number or String value.
827   * @return the Float value.
828   * @throws IllegalArgumentException if {@code obj} is not a number or a String.
829   */
830  public static BigInteger bigIntegerValue(Object obj) throws IllegalArgumentException {
831    if (obj instanceof BigInteger) {
832      return (BigInteger) obj;
833    }
834    if (obj instanceof BigDecimal) {
835      return ((BigDecimal) obj).toBigInteger();
836    }
837    if (obj instanceof Number) {
838      return BigInteger.valueOf(((Number) obj).longValue());
839    }
840    if (obj instanceof Character) {
841      char value = (Character) obj;
842      return BigInteger.valueOf((long) value);
843    }
844    if (obj instanceof String) {
845      return new BigInteger((String) obj);
846    }
847    throw new IllegalArgumentException("Expected a number or a string, but got: " + obj);
848  }
849
850  // ...................................................................................................................
851  /**
852   * Create a {@code String} by concatenating all arguments.
853   * <p>
854   * For instance:
855   * <pre class="listing"><code class="lang-golo" data-lang="golo">
856   * let s = str("The answer", " is ", 2 * 21)
857   * </code></pre>
858   * This is functionally equivalent to:
859   * <pre class="listing"><code class="lang-golo" data-lang="golo">
860   * let s = ["The answer", " is ", 2 * 21]: join("")
861   * </code></pre>
862   */
863  public static String str(Object... args) {
864    if (args == null || args.length == 0) {
865      return "";
866    }
867    if (args.length == 1) {
868      return String.valueOf(args[0]);
869    }
870    StringBuilder sb = new StringBuilder();
871    for (Object o : args) {
872      sb.append(o);
873    }
874    return sb.toString();
875  }
876
877  /**
878   * Removes an element of a List by index.
879   *
880   * @param lst the list to remove the element from.
881   * @param idx an Integer representing the index of the element to remove.
882   * @return the element that was removed.
883   * @throws IndexOutOfBoundsException if {@code idx}
884   */
885  public static Object removeByIndex(List<?> lst, Integer idx) {
886    return lst.remove(idx.intValue());
887  }
888
889  /**
890   * Returns a box containing the given object.
891   * <p>
892   * Useful whenever an explicit reference is needed, for instance to create a closure with internal
893   * mutable state:
894   * <pre class="listing"><code class="lang-golo" data-lang="golo">
895   *    function counter = |init| {
896   *      let current = box(init)
897   *      return -> current: getAndSet(current: get() + 1)
898   *    }
899   *
900   *    let c = counter(3)
901   *    c() # 3
902   *    c() # 4
903   *    c() # 5
904   * </code></pre>
905   *
906   * @param obj the object to reference.
907   * @return a {@code java.util.concurrent.atomic.AtomicReference} instance wrapping the object
908   */
909  public static Object box(Object obj) {
910    return new java.util.concurrent.atomic.AtomicReference<>(obj);
911  }
912
913  // ...................................................................................................................
914  /**
915   * Varargs version of a list constructor.
916   *
917   * @return a list of the given values.
918   */
919  public static List<Object> list(Object... values) {
920    return new LinkedList<>(Arrays.asList(values));
921  }
922
923  /**
924   * Varargs version of a set constructor.
925   *
926   * @return a set of the given values.
927   */
928  public static Set<Object> set(Object... values) {
929    return new LinkedHashSet<>(Arrays.asList(values));
930  }
931
932  /**
933   * array constructor.
934   *
935   * @return an array of the given values.
936   */
937  public static Object[] array(Object... values) {
938    return values;
939  }
940
941  /**
942   * Varargs version of a vector constructor.
943   *
944   * @return a vector of the give values.
945   */
946  public static List<Object> vector(Object... values) {
947    return new ArrayList<>(Arrays.asList(values));
948  }
949
950  /**
951   * Tuple constructor.
952   *
953   * @return a tuple of the given values.
954   */
955  public static Tuple tuple(Object... values) {
956    return new Tuple(values);
957  }
958
959  /**
960   * Varargs version of a map constructor.
961   *
962   * @param items tuples containing the key and the value.
963   * @return a map corresponding to the given key/value pairs.
964   */
965  public static Map<Object, Object> map(Tuple... items) {
966    Map<Object, Object> m = new LinkedHashMap<>();
967    for (Tuple t : items) {
968      m.put(t.get(0), t.get(1));
969    }
970    return m;
971  }
972}