/* --------------------------------------------------------- *
* __________ D E L T A S C R I P T *
* (_________() *
* / === / - A fast, dynamic scripting language *
* | == | - Version 4.13.11.0 *
* / === / - Developed by Adam R. Nelson *
* | = = | - 2011-2013 *
* / === / - Distributed under GNU LGPL v3 *
* (________() - http://github.com/ar-nelson/deltascript *
* *
* --------------------------------------------------------- */
package com.sector91.delta.script;
import static com.sector91.delta.script.DScriptErr.*;
import static com.sector91.util.StringTemplate.$;
import java.io.*;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Scanner;
import com.sector91.delta.script.annotations.*;
import com.sector91.delta.script.module.ModuleLoader;
import com.sector91.delta.script.objects.DS_AnonymousCallable;
import com.sector91.delta.script.objects.DS_Array;
import com.sector91.delta.script.objects.DS_Blank;
import com.sector91.delta.script.objects.DS_Boolean;
import com.sector91.delta.script.objects.DS_Callable;
import com.sector91.delta.script.objects.DS_Decimal;
import com.sector91.delta.script.objects.DS_Function;
import com.sector91.delta.script.objects.DS_Integer;
import com.sector91.delta.script.objects.DS_List;
import com.sector91.delta.script.objects.DS_Map;
import com.sector91.delta.script.objects.DS_Object;
import com.sector91.delta.script.objects.DS_Range;
import com.sector91.delta.script.objects.DS_Scalar;
import com.sector91.delta.script.objects.DS_Scope;
import com.sector91.delta.script.objects.DS_Sequence;
import com.sector91.delta.script.objects.DS_Set;
import com.sector91.delta.script.objects.DS_String;
import com.sector91.delta.script.objects.DS_Tag;
import com.sector91.delta.script.objects.DS_Vector;
import com.sector91.delta.script.objects.ScalarFactory;
import com.sector91.delta.script.objects.VectorFactory;
import com.sector91.delta.script.objects.geom.DS_Path2DBuilder;
import com.sector91.delta.script.objects.geom.DS_PathBuilder;
import com.sector91.delta.script.objects.geom.DS_Shape;
import com.sector91.delta.script.objects.geom.DS_Shape2D;
import com.sector91.delta.script.objects.io.DS_ReadHandle;
import com.sector91.delta.script.objects.reflect.DS_ForeignObject;
import com.sector91.delta.script.objects.reflect.DS_JavaClass;
import com.sector91.delta.script.parser.DScriptParserException;
import com.sector91.geom.Box;
import com.sector91.geom.Circle;
import com.sector91.geom.Ellipse;
import com.sector91.geom.Line;
import com.sector91.geom.Rect;
import com.sector91.util.Sector91Version;
/**
* <p>The DeltaScript Standard library, which can be accessed from any
* DeltaScript scope with the special variable {@code $StdLib} or the {@code ..}
* operator.</p>
*
* <p>Contains a collection of static Java methods that provide various basic
* functions for DeltaScript, such as math operations, typecasting, and access
* to system time.</p>
*
* <p>This class is designed to be wrapped in a {@link DS_JavaClass}, not used
* on its own.</p>
*
* @author Adam R. Nelson
* @version 4.13.11.0
*/
public class DScriptStandardLibrary
{
static final DS_Decimal
PI = ScalarFactory.fromDouble(Math.PI),
E = ScalarFactory.fromDouble(Math.E),
POS_INF = ScalarFactory.fromDouble(Double.POSITIVE_INFINITY),
NEG_INF = ScalarFactory.fromDouble(Double.NEGATIVE_INFINITY);
private DScriptStandardLibrary() {}
// Basic Standard Library Methods
//
// These are the most basic methods needed for
// DeltaScript to do anything interesting.
// ----------------------------------------------------
/**
* <p>Prints a message to the Java console.</p>
*
* @param message The message to print.
*/
@DSName("print")
public static void print(DS_Object message)
{System.out.println(message);}
/**
* <p>Prints a message to the Java console's error stream.</p>
*
* @param message The message to print.
*/
@DSName("printErr")
public static void printErr(DS_Object message)
{System.err.println(message);}
/**
* <p>Reads user input from the Java console. This will block until the
* user presses Enter.</p>
*
* @return The input that the user typed.
*/
@DSName("userInput")
public static String userInput()
{return userInputTo("\n");}
/**
* <p>Reads user input from the Java console. This will block until the
* user enters the given delimiter.</p>
*
* @param delimiter The delimiter to read up to.
* @return The input that the user typed.
*/
@DSName("userInputTo")
public static String userInputTo(String delimiter)
{
Scanner s = new Scanner(System.in);
s.useDelimiter(delimiter);
return s.next();
}
/**
* <p>Loads and executes a DeltaScript file or package in a new scope.</p>
*
* <p>This will load any file with a {@code .ds} or {@code .dsc} extension,
* or any folder containing a {@code module.ds} file. It creates a new
* scope and executes the contents of the file(s) inside that scope; if a
* module is loaded, each file in the module becomes a subscope.</p>
*
* @param filename The path (relative or absolute) of the file to load.
* Relative paths are treated as relative to the
* @return A new scope, containing any variables, functions or scopes
* defined in the executed file(s). Its name will be the same as
* the name of the file/package, with any extension removed and any
* non-alphanumeric characters replaced with underscores.
* @throws DScriptErr If the file cannot be found or loaded, or if an
* error occurs while parsing or executing the contents of the
* file.
*/
@DSName("load")
public static DS_Scope load(String filename)
{
if (DScriptContext.get() == null)
throw new DScriptErr("No DeltaScript context is loaded.");
final File f = new File(filename);
try
{
return (DS_Scope)DeltaScript.execFile(f,DScriptContext.get(),true);
}
catch (FileNotFoundException ex)
{
throw new DScriptErr("Could not find script file: " +
filename, ex);
}
catch (IOException ex)
{
throw new DScriptErr("Error reading script file: " +
filename, ex);
}
catch (DScriptParserException ex)
{
String line;
try
{
final StringBuilder source = new StringBuilder();
final BufferedReader br = new BufferedReader(new FileReader(f));
while (br.ready())
{
source.append(br.readLine());
source.append('\n');
}
br.close();
line = "line " + DScriptErr.locateInSource(source.toString(),
ex.getLocation())._2._1;
}
catch (Exception ex2)
{line = "(unknown line)";}
throw new DScriptErr($("Error parsing file '{}' on {}: {}",
filename, line, ex.getMessage()));
}
}
/**
* <p>Loads a module as a new scope/object, using the current {@link
* ModuleLoader}. A module may be a folder of DeltaScript files, a Java
* library, or any other DeltaScript object. All modules should only ever
* be loaded once; if a module with the same name has been loaded before,
* then the already-loaded instance of the module will be returned.</p>
*
* @param moduleName The name of the module. Depending on the {@link
* ModuleLoader} implementation, this may be treated as a
* path, a class name, etc. All {@code ModuleLoader}s
* resolve names differently.
* @throws DScriptErr If no module with the given name exists, if the
* script context does not have permission to load the
* module, or if an error occurs while loading the module.
*/
@DSName("module")
public static DS_Object module(String moduleName)
{
// TODO: Support module loading.
throw new UnsupportedOperationException();
// TODO: Add proper tags to the thrown exceptions.
/*if (DScriptContext.get() == null)
throw new DScriptException("No DeltaScript context is loaded.");
ModuleLoader loader = DScriptContext.get().getModuleLoader();
if (loader == null)
throw new DScriptException("No module loader is available in" +
" this context.");
DS_Object module = loader.loadModule(moduleName);
if (module == null)
throw new DScriptException("No module named \"" + moduleName +
"\" is available.");
return module;
*/
}
/**
* <p>Opens and returns a handle to a resource in the current DeltaScript
* package or directory structure. The path will be considered relative to
* {@link DeltaScript#getCurrentWorkingDirectory()} of the current
* scope's {@link DeltaScript}, or, if the current script is being run
* from a package file, will be loaded from a path within the package file
* relative to the location of the currently executing script file.</p>
*
* @param path The path to the resource. Should be a relative path, using
* forward slashes as separators and containing no up-directory
* ({@code ..}) entries.
* @return A {@link DS_ReadHandle} to the resource at the given path.
* @throws DScriptErr If the given path is invalid, no resource exists
* at the given path, or an error occurs while reading the
* resource file.
*/
@DSName("resource")
public static DS_ReadHandle resource(String path)
{
// TODO: Add this.
throw new UnsupportedOperationException();
}
@DSName("foreign")
public static DS_JavaClass foreign(String fullClassName)
{
try
{return DS_JavaClass.fromClass(Class.forName(fullClassName));}
catch (Exception ex)
{throw new DScriptErr(ex.getMessage(), ex);}
}
/**
* <p>Throws a {@link DScriptErr} with the given message and tags. The
* equivalent of a Java {@code throw} statement.</p>
*
* @param message The message that the thrown {@link DScriptErr} will
* display.
* @param tags An array of {@link DS_Tag}s to tag the error with.
* @throws DScriptErr Always throws this error, with the given message
* and tags.
*/
@DSName("error")
public static void error(String message, DS_Tag... tags)
{throw new DScriptErr(message, tags);}
/**
* <p>Throws a {@link DScriptErr} if the {@link
* DS_Object#booleanValue()} method of the given object does not evaluate to
* {@code true}. The error thrown will always have the message "Assertion
* failed." and the tag {@code 'Assertion}.</p>
*
* <p>This is the equivalent of a Java {@code assert} statement, but
* named differently because {@code assert} is a reserved word in
* Java. In DeltaScript, it is still called {@code assert}.</p>
*
* @param value The object (usually the result of an expression) to assert
* the truth value of.
* @throws DScriptErr If the given object does not evaluate to
* {@code true}.
*/
@DSName("assert")
public static void _assert(DS_Object value)
{
if (!value.booleanValue())
throw new DScriptErr("Assertion failed.", T_ASSERTION);
}
/**
* <p>Returns a new callable that adds the given tag to a {@link
* DScriptErr} and then rethrows the error. Intended to be used as the
* {@code error} method of a scope.</p>
*
* @param tag The tag to add to any errors passed to the returned callable.
* @return A new callable that adds the given tag to any error passed to it
* and then rethrows the error.
*/
@DSName("tagAndRelease")
public static DS_Callable tagAndRelease(final DS_Tag tag)
{
return new DS_AnonymousCallable(1) {
public DS_Object call(DS_Object... args)
{
DS_String message = (DS_String)args[0];
DS_Object[] tagObjs = ((DS_Array)args[1]).unbox();
final DS_Tag[] tags = new DS_Tag[tagObjs.length+1];
System.arraycopy(tagObjs, 0, tags, 0, tagObjs.length);
tags[tagObjs.length] = tag;
throw new DScriptErr(message.unbox(), tags);
}
};
}
@DSName("clone")
public static DS_Object clone(DS_Object obj)
{
try
{return obj.clone();}
catch (CloneNotSupportedException ex)
{
throw new DScriptErr("Cannot clone an object of type " +
obj.getTypeName() + ".", ex);
}
}
/**
* <p>Returns a string representing the type of the given {@link DS_Object}.
* This string is retrieved using {@link DS_Object#getTypeName()}.</p>
*
* @param var The object to get the type of.
* @return A string representing the type of the object.
*/
@DSName("typeName")
public static String typeName(DS_Object var)
{return var.getTypeName();}
/**
* <p>Returns a set containing the names of all of the members of the
* given object. This set represents all of the valid values for
* {@link DS_Object#dotGet(DS_Tag)} for the given object.</p>
*
* @param var The object to get the members of.
* @return A set of the names of the object's members.
*/
@DSName("members")
public static DS_Set members(DS_Object var)
{return new DS_Set(var.getMembers());}
// Math
//
// As a game scripting language, DeltaScript is very
// math-focused. Most math-related functions are
// available both here and as member functions of the
// Integer, Decimal, Range and Vector types.
// ----------------------------------------------------
/**
* <p>Calculates the sine of the given angle.</p>
*
* @param radians The angle to take the sine of, in radians.
* @return The sine of the given angle.
*/
@DSName("sin")
public static DS_Decimal sin(DS_Scalar radians)
{return radians.sin();}
/**
* <p>Calculates the cosine of the given angle.</p>
*
* @param radians The angle to take the cosine of, in radians.
* @return The cosine of the given angle.
*/
@DSName("cos")
public static DS_Decimal cos(DS_Scalar radians)
{return radians.cos();}
/**
* <p>Calculates the tangent of the given angle.</p>
*
* @param radians The angle to take the tangent of, in radians.
* @return The tangent of the given angle.
*/
@DSName("tan")
public static DS_Decimal tan(DS_Scalar radians)
{return radians.tan();}
/**
* <p>Calculates the inverse sine of the given value.</p>
*
* @param value The sine value to take the inverse of.
* @return The angle with a sine of {@code value}, in radians.
*/
@DSName("asin")
public static DS_Decimal asin(DS_Scalar value)
{return value.asin();}
/**
* <p>Calculates the inverse cosine of the given value.</p>
*
* @param value The cosine value to take the inverse of.
* @return The angle with a cosine of {@code value}, in radians.
*/
@DSName("acos")
public static DS_Decimal acos(DS_Scalar value)
{return value.acos();}
/**
* <p>Calculates the inverse tangent of the given value.</p>
*
* @param value The tangent value to take the inverse of.
* @return The angle with a tangent of {@code value}, in radians.
*/
@DSName("atan")
public static DS_Decimal atan(DS_Scalar value)
{return value.atan();}
/**
* <p>Calculates the inverse tangent of {@code y/x}.</p>
*
* @param y The numerator of the fraction to take the inverse tangent of.
* @param x The denominator of the fraction to take the inverse tangent of.
* @return The angle with a tangent of {@code y/x}, in radians.
*/
@DSName("atan2")
public static DS_Decimal atan2(DS_Scalar y, DS_Scalar x)
{
return ScalarFactory.fromDouble(Math.atan2(y.doubleValue(),
x.doubleValue()));
}
/**
* <p>Returns a number (1, 0, or -1) representing the sign of the given
* number.</p>
*
* @param num The number to get the sign of.
* @return 1 if the given number is positive, 0 if the given number is 0,
* or -1 if the given number is negative.
*/
@DSName({"sgn", "signum"})
public static long sgn(DS_Scalar num)
{return num.signum();}
/**
* <p>Returns the smallest item in the given sequence, based on the items'
* {@link DS_Object#compareTo(DS_Object)} methods.</p>
*
* @param seq The sequence to evaluate.
* @return The smallest item in the sequence, the first item if they
* evaluate as equivalent, or {@link DS_Blank#BLANK} if the
* sequence is empty.
* @see #max(DS_Sequence)
*/
@DSName("min")
public static DS_Object min(DS_Object... seq)
{
DS_Object smallest = DS_Blank.BLANK;
for (DS_Object o : seq)
{
if (smallest == DS_Blank.BLANK || o.compare(smallest) < 0)
smallest = o;
}
return smallest;
}
/**
* <p>Returns the largest item in the given sequence, based on the items'
* {@link DS_Object#compareTo(DS_Object)} methods.</p>
*
* @param seq The sequence to evaluate.
* @return The largest item in the sequence, the first item if they
* evaluate as equivalent, or {@link DS_Blank#BLANK} if the
* sequence is empty.
* @see #min(DS_Sequence)
*/
@DSName("max")
public static DS_Object max(DS_Object... seq)
{
DS_Object largest = DS_Blank.BLANK;
for (DS_Object o : seq)
{
if (largest == DS_Blank.BLANK || o.compare(largest) > 0)
largest = o;
}
return largest;
}
/**
* <p>Calculates a 2-dimensional determinant, which is equal to the
* following:</p>
*
* <p>{@code a*d - b*c}</p>
*
* @param a The top left entry in the determinant.
* @param b The top right entry in the determinant.
* @param c The bottom left entry in the determinant.
* @param d The bottom right entry in the determinant.
* @return {@code a*d - b*c}
* @since 3.12.2.0
*/
@DSName("det2")
public static DS_Scalar det2(DS_Scalar a, DS_Scalar b,
DS_Scalar c, DS_Scalar d)
{
final int nType = a.getNumberType() | b.getNumberType()
| c.getNumberType() | d.getNumberType();
return ScalarFactory.sub(ScalarFactory.mul(a, d, nType),
ScalarFactory.mul(b, c, nType), nType);
}
/**
* <p>Calculates an <i>N</i>-dimensional determinant, by using the array
* of {@link DS_Vector}s passed to the method as the rows of a determinant
* matrix. Note that, if you are calculating a 2-dimensional determinant,
* {@link #det2(DS_Scalar, DS_Scalar, DS_Scalar, DS_Scalar)} is
* <em>significantly</em> faster!</p>
*
* @param rowVectors An array of {@link DS_Vector}s representing the rows
* of the determinant. This array must contain only
* vectors, and the number of dimensions of each vector
* must be equal to the size of this array.
* @return The result of the determinant calculation.
* @since 3.12.2.0
*/
@DSName({"det", "determinant"})
public static DS_Scalar determinant(DS_Vector... rowVectors)
{
int size = rowVectors.length;
DS_Scalar[][] matrix = new DS_Scalar[size][size];
int nType = 0;
for (int y=0; y<rowVectors.length; y++)
{
DS_Vector v = rowVectors[y];
if (v.dimensions() != size)
throw new IllegalArgumentException("The number of dimensions" +
" of each vector passed to ..determinant must be the" +
" same as the number of vectors.");
nType |= v.getNumberType();
for (int x=0; x<size; x++)
matrix[x][y] = v.scalarComponent(x);
}
return determinant(matrix, nType);
}
@DSInaccessible
public static DS_Scalar determinant(DS_Scalar[][] matrix, int nType)
{
int size = matrix.length;
if (size == 2)
return det2(matrix[0][0],matrix[1][0],matrix[0][1],matrix[1][1]);
DS_Scalar total = ScalarFactory.fromNumber(0, nType);
boolean pos = true;
for (int dim=0; dim<size; dim++)
{
DS_Scalar[][] subMatrix = new DS_Scalar[size-1][size-1];
int realx = 0;
for (int x=0; x<size-1; x++)
{
if (realx == dim) realx++;
for (int y=0; y<size-1; y++)
subMatrix[x][y] = matrix[realx][y+1];
realx++;
}
total = ScalarFactory.mul(
pos ? matrix[dim][0] : matrix[dim][0].negate(),
determinant(subMatrix, nType),
nType);
pos = !pos;
}
return total;
}
@DSName("hash")
public static DS_Integer hash(DS_Object obj)
{return ScalarFactory.fromInt(obj.hashCode());}
// Fields and Constants
//
// These are a combination of mathematical constants
// and non-constant values (such as system time) that
// make more sense as a property than as a function.
// ----------------------------------------------------
@DSName("version") @DSDynamicField
public static DS_Array version()
{
Sector91Version v = DeltaScript.VERSION;
if (v.letterSuffix() != null && !v.letterSuffix().isEmpty())
{
return new DS_Array(new DS_Object[] {
ScalarFactory.fromInt(v.majorVersion()),
ScalarFactory.fromInt(v.year()),
ScalarFactory.fromInt(v.month()),
ScalarFactory.fromInt(v.minorVersion()),
new DS_String(v.letterSuffix())
});
}
else
{
return new DS_Array(new DS_Object[] {
ScalarFactory.fromInt(v.majorVersion()),
ScalarFactory.fromInt(v.year()),
ScalarFactory.fromInt(v.month()),
ScalarFactory.fromInt(v.minorVersion())
});
}
}
@DSName("time") @DSDynamicField
public static DS_Integer time()
{return ScalarFactory.fromLong(System.currentTimeMillis());}
@DSName("pi") @DSDynamicField
public static DS_Decimal pi()
{return PI;}
@DSName("e") @DSDynamicField
public static DS_Decimal e()
{return E;}
@DSName({"infinity", "inf"}) @DSDynamicField
public static DS_Decimal infinity()
{return POS_INF;}
@DSName({"negativeInfinity", "neginf"}) @DSDynamicField
public static DS_Decimal negativeInfinity()
{return NEG_INF;}
// Casts
//
// DeltaScript is dynamically typed, but all objects
// still have static Java types under the hood. Because
// of this, casts are still sometimes necessary.
// ----------------------------------------------------
private static DS_Integer intCast(DS_Object var, int nType)
{
if (var instanceof DS_String)
{
try
{
return (DS_Integer)ScalarFactory.fromString(
(String)var.unbox(), nType);
}
catch (NumberFormatException ex)
{throw new DScriptErr(ex.getMessage(), ex);}
}
else if (var instanceof DS_Scalar)
{return (DS_Integer)((DS_Scalar)var).castTo(nType);}
else
throw new DScriptErr($("Cannot convert {} to {}.",
var.getTypeName(), DS_Integer.TYPE_NAME),
T_INVALID_TYPE);
}
/**
* <p>Casts the given object to a {@link DS_Integer} with the number type
* {@link NumberTypes#SHORT_INT}.</p>
*
* @param var The object to cast.
* @return A {@link DS_Integer} that best represents the given object.
* @throws DScriptErr If no cast exists for the given object's type.
*/
@DSName({"to" + NumberTypes.SUFFIX_SHORT_INT})
public static DS_Integer toShortInt(DS_Object var)
{return intCast(var, NumberTypes.SHORT_INT);}
/**
* <p>Casts the given object to a {@link DS_Integer} with the number type
* {@link NumberTypes#LONG_INT}.</p>
*
* @param var The object to cast.
* @return A {@link DS_Integer} that best represents the given object.
* @throws DScriptErr If no cast exists for the given object's type.
*/
@DSName({"to" + NumberTypes.SUFFIX_LONG_INT})
public static DS_Integer toLongInt(DS_Object var)
{return intCast(var, NumberTypes.LONG_INT);}
/**
* <p>Casts the given object to a {@link DS_Integer} with the number type
* {@link NumberTypes#REAL_INT}.</p>
*
* @param var The object to cast.
* @return A {@link DS_Integer} that best represents the given object.
* @throws DScriptErr If no cast exists for the given object's type.
*/
@DSName({"to" + NumberTypes.SUFFIX_REAL_INT})
public static DS_Integer toRealInt(DS_Object var)
{return intCast(var, NumberTypes.REAL_INT);}
private static DS_Decimal decCast(DS_Object var, int nType)
{
if (var instanceof DS_String)
{
try
{
return (DS_Decimal)ScalarFactory.fromString(
(String)var.unbox(), nType);
}
catch (NumberFormatException ex)
{throw new DScriptErr(ex.getMessage(), ex);}
}
else if (var instanceof DS_Scalar)
{return (DS_Decimal)((DS_Scalar)var).castTo(nType);}
else
throw new DScriptErr($("Cannot convert {} to {}.",
var.getTypeName(), DS_Scalar.TYPE_NAME),
T_INVALID_TYPE);
}
/**
* <p>Casts the given object to a {@link DS_Decimal} with the number type
* {@link NumberTypes#SHORT_FLOAT}.</p>
*
* @param var The object to cast.
* @return A {@link DS_Decimal} that best represents the given object.
* @throws DScriptErr If no cast exists for the given object's type.
*/
@DSName({"to" + NumberTypes.SUFFIX_SHORT_FLOAT})
public static DS_Decimal toShortFloat(DS_Object var)
{return decCast(var, NumberTypes.SHORT_FLOAT);}
/**
* <p>Casts the given object to a {@link DS_Decimal} with the number type
* {@link NumberTypes#LONG_FLOAT}.</p>
*
* @param var The object to cast.
* @return A {@link DS_Decimal} that best represents the given object.
* @throws DScriptErr If no cast exists for the given object's type.
*/
@DSName({"to" + NumberTypes.SUFFIX_LONG_FLOAT})
public static DS_Decimal toLongFloat(DS_Object var)
{return decCast(var, NumberTypes.LONG_FLOAT);}
/**
* <p>Casts the given object to a {@link DS_Decimal} with the number type
* {@link NumberTypes#REAL_DECIMAL}.</p>
*
* @param var The object to cast.
* @return A {@link DS_Decimal} that best represents the given object.
* @throws DScriptErr If no cast exists for the given object's type.
*/
@DSName({"to" + NumberTypes.SUFFIX_REAL_DECIMAL})
public static DS_Decimal toRealDecimal(DS_Object var)
{return decCast(var, NumberTypes.REAL_DECIMAL);}
@DSName("str")
public static DS_String toStr(DS_Object obj)
{return new DS_String(obj.toString());}
@DSName("tag")
public static DS_Tag toTag(DS_Object obj)
{
if (obj instanceof DS_Tag)
return (DS_Tag)obj;
return DS_Tag.tag(obj.toString());
}
@DSName("int")
public static DS_Integer toInt(DS_Object o)
{
if (o instanceof DS_Scalar)
return ((DS_Scalar)o).floor();
else if (o instanceof DS_String)
try
{return ScalarFactory.fromLong(Long.parseLong(o.toString()));}
catch (NumberFormatException ex)
{return ScalarFactory.fromBigInteger(new BigInteger(o.toString()));}
else
throw new DScriptErr("Cannot convert object of type " +
o.getTypeName() + " to type Integer.");
}
@DSName("dec")
public static DS_Decimal toDec(DS_Object o)
{
if (o instanceof DS_Scalar)
{
final DS_Scalar s = (DS_Scalar)o;
if (s instanceof DS_Decimal) return ((DS_Decimal)s);
else return (DS_Decimal)s.castTo(s.getNumberType() |
NumberTypes.SHORT_FLOAT);
}
else if (o instanceof DS_String)
try
{return ScalarFactory.fromDouble(Double.parseDouble(o.toString()));}
catch (NumberFormatException ex)
{return ScalarFactory.fromBigDecimal(new BigDecimal(o.toString()));}
else
throw new DScriptErr("Cannot convert object of type " +
o.getTypeName() + " to type Decimal.");
}
@DSName({"array", "arrayOfSize"})
public static DS_Array arrayOfSize(int size)
{return new DS_Array(size);}
@DSName("list")
public static DS_List list(DS_Object... items)
{return new DS_List(items);}
@DSName("set")
public static DS_Set set(DS_Object... items)
{return new DS_Set(items);}
@DSName("map")
public static DS_Map map(DS_Sequence... items)
{
final DS_Map newMap = new DS_Map();
for (DS_Sequence seq : items)
newMap.put(seq.get(0), seq.get(1));
return newMap;
}
// Type Objects
//
// Objects that represent the core DeltaScript types.
// Used exclusively for typechecking with the 'is'
// operator.
// ----------------------------------------------------
/** DeltaScript class for {@link DS_String}. */
@DSName(DS_String.TYPE_NAME) @DSDynamicField
public static DS_JavaClass stringClass()
{return DS_JavaClass.fromClass(DS_String.class);}
/** DeltaScript class for {@link DS_Tag}. */
@DSName(DS_Tag.TYPE_NAME) @DSDynamicField
public static DS_JavaClass tagClass()
{return DS_JavaClass.fromClass(DS_Tag.class);}
/** DeltaScript class for {@link DS_Scalar}. */
@DSName(DS_Scalar.TYPE_NAME) @DSDynamicField
public static DS_JavaClass scalarClass()
{return DS_JavaClass.fromClass(DS_Scalar.class);}
/** DeltaScript class for {@link DS_Boolean}. */
@DSName(DS_Boolean.TYPE_NAME) @DSDynamicField
public static DS_JavaClass booleanClass()
{return DS_JavaClass.fromClass(DS_Boolean.class);}
/** DeltaScript class for {@link DS_Integer}. */
@DSName(DS_Integer.TYPE_NAME) @DSDynamicField
public static DS_JavaClass integerClass()
{return DS_JavaClass.fromClass(DS_Integer.class);}
/** DeltaScript class for {@link DS_Decimal}. */
@DSName(DS_Decimal.TYPE_NAME) @DSDynamicField
public static DS_JavaClass decimalClass()
{return DS_JavaClass.fromClass(DS_Decimal.class);}
/** DeltaScript class for {@link DS_Vector}. */
@DSName(DS_Vector.TYPE_NAME) @DSDynamicField
public static DS_JavaClass vectorClass()
{return DS_JavaClass.fromClass(DS_Vector.class);}
/** DeltaScript class for {@link DS_Range}. */
@DSName(DS_Range.TYPE_NAME) @DSDynamicField
public static DS_JavaClass rangeClass()
{return DS_JavaClass.fromClass(DS_Range.class);}
/** DeltaScript class for {@link DS_Array}. */
@DSName(DS_Array.TYPE_NAME) @DSDynamicField
public static DS_JavaClass arrayClass()
{return DS_JavaClass.fromClass(DS_Array.class);}
/** DeltaScript class for {@link DS_List}. */
@DSName(DS_List.TYPE_NAME) @DSDynamicField
public static DS_JavaClass listClass()
{return DS_JavaClass.fromClass(DS_List.class);}
/** DeltaScript class for {@link DS_Set}. */
@DSName(DS_Set.TYPE_NAME) @DSDynamicField
public static DS_JavaClass setClass()
{return DS_JavaClass.fromClass(DS_Set.class);}
/** DeltaScript class for {@link DS_Map}. */
@DSName(DS_Map.TYPE_NAME) @DSDynamicField
public static DS_JavaClass mapClass()
{return DS_JavaClass.fromClass(DS_Map.class);}
/** DeltaScript class for {@link DS_Function}. */
@DSName(DS_Function.TYPE_NAME) @DSDynamicField
public static DS_JavaClass functionClass()
{return DS_JavaClass.fromClass(DS_Function.class);}
/** DeltaScript class for {@link DS_Scope}. */
@DSName(DS_Scope.TYPE_NAME) @DSDynamicField
public static DS_JavaClass scopeClass()
{return DS_JavaClass.fromClass(DS_Scope.class);}
/** DeltaScript class for {@link DS_ForeignObject}. */
@DSName("ForeignObject") @DSDynamicField
public static DS_JavaClass foreignObjectClass()
{return DS_JavaClass.fromClass(DS_ForeignObject.class);}
// TODO: Geometric shape classes.
// Fun with Iterators
//
// Utility methods that use DeltaScript's varargs and
// comprehension features to perform powerful iteration
// operations.
// ----------------------------------------------------
@DSName("count")
public static DS_Integer count(DS_Object... items)
{return ScalarFactory.fromInt(items.length);}
@DSName("fold")
public static DS_Object fold(DS_Callable func, DS_Object... items)
{
if (items.length == 0)
return DS_Blank.BLANK;
DS_Object result = items[0];
for (int i=1; i<items.length; i++)
result = func.call(result, items[i]);
return result;
}
@DSName("sum")
public static DS_Object sum(DS_Object... items)
{
if (items.length == 0)
return DS_Blank.BLANK;
DS_Object result = items[0];
for (int i=1; i<items.length; i++)
result = result.operator(Operator.ADD, items[i]);
return result;
}
// Geometry and Shapes
//
// Because DeltaScript is primarily a game scripting
// language, the geometry module is built in. These
// methods are constructors for a variety of geometric
// shapes. The geometry library is independent of AWT,
// so as to function on any platform.
// ----------------------------------------------------
@DSName("line")
public static Line line(DS_Vector p1, DS_Vector p2)
{return DScriptContext.getContextGeometry().line(p1, p2);}
@DSName("box")
public static Box box(DS_Vector origin, DS_Vector span)
{return DScriptContext.getContextGeometry().box(origin, span);}
@DSName("obox")
public static Box obox(DS_Vector span)
{
return box(VectorFactory.zero(
NumberTypes.SHORT_FLOAT, span.dimensions()), span);
}
@DSName("vbox")
public static Box vbox(DS_Vector p1, DS_Vector p2)
{return box(p1, p2.sub(p1));}
@DSName("rect")
public static Rect rect(DS_Vector origin, DS_Vector span)
{return DScriptContext.getContextGeometry().rect(origin, span);}
@DSName("orect")
public static Rect orect(DS_Vector span)
{return rect(VectorFactory.zero(NumberTypes.SHORT_FLOAT, 2), span);}
@DSName("vrect")
public static Rect vrect(DS_Vector p1, DS_Vector p2)
{return rect(p1, p2.sub(p1));}
@DSName("circle")
public static Circle circle(DS_Vector pos, DS_Scalar r)
{return DScriptContext.getContextGeometry().circle(pos, r.floatValue());}
@DSName("ocircle")
public static Circle ocircle(DS_Scalar r)
{return circle(VectorFactory.zero(NumberTypes.SHORT_FLOAT, 2), r);}
@DSName("vcircle")
public static Circle vcircle(DS_Vector p1, DS_Vector p2)
{return circle(p1, p2.sub(p1).scalarMagnitude());}
@DSName("ellipse")
public static Ellipse ellipse(DS_Vector pos, DS_Scalar rx, DS_Scalar ry)
{
return DScriptContext.getContextGeometry().ellipse(pos,
rx.floatValue(), ry.floatValue());
}
@DSName("oellipse")
public static Ellipse oellipse(DS_Scalar rx, DS_Scalar ry)
{return ellipse(VectorFactory.zero(NumberTypes.SHORT_FLOAT, 2), rx, ry);}
@DSName("vellipse")
public static Ellipse vellipse(DS_Vector p1, DS_Vector p2)
{
DS_Vector diff = p2.sub(p1);
return ellipse(p1, diff.scalarComponent(0), diff.scalarComponent(1));
}
@DSName("polygon")
public static DS_Shape2D polygon(DS_Vector... pts)
{return DScriptContext.getContextGeometry().polygon(pts);}
@DSName("polyline")
public static DS_Shape2D polyline(DS_Vector... pts)
{return DScriptContext.getContextGeometry().polyline(pts);}
// TODO: Constructor methods for QuadCurve, CubicCurve, CurveND
@DSName("path")
public static DS_Path2DBuilder path()
{return DScriptContext.getContextGeometry().path();}
@DSName("path")
public static DS_PathBuilder<?> path(DS_Integer dimensions)
{return DScriptContext.getContextGeometry().path(dimensions.intValue());}
public static DS_Shape emptyShape(DS_Integer dimensions)
{
return DScriptContext.getContextGeometry().emptyShape(
dimensions.intValue());
}
}