package com.oracle.truffle.js.nodes.intl;
import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.object.DynamicObject;
import com.oracle.truffle.js.nodes.JSGuards;
import com.oracle.truffle.js.nodes.JavaScriptBaseNode;
import com.oracle.truffle.js.nodes.access.CreateObjectNode.CreateObjectWithPrototypeNode;
import com.oracle.truffle.js.nodes.cast.JSToObjectNode;
import com.oracle.truffle.js.runtime.Errors;
import com.oracle.truffle.js.runtime.JSContext;
import com.oracle.truffle.js.runtime.JSRuntime;
import com.oracle.truffle.js.runtime.builtins.JSOrdinary;
import com.oracle.truffle.js.runtime.objects.JSObject;
import com.oracle.truffle.js.runtime.objects.Undefined;
public abstract class ToDateTimeOptionsNode extends JavaScriptBaseNode {
@Child JSToObjectNode toObjectNode;
final JSContext context;
public JSContext getContext() {
return context;
}
public ToDateTimeOptionsNode(JSContext context) {
super();
this.context = context;
}
public abstract DynamicObject execute(Object opts, String required, String defaults);
@SuppressWarnings("unused")
@Specialization(guards = "isUndefined(opts)")
public DynamicObject fromUndefined(Object opts, String required, String defaults) {
return setDefaultsIfNeeded(JSOrdinary.createWithNullPrototype(getContext()), required, defaults);
}
@Specialization(guards = "!isUndefined(opts)")
public DynamicObject fromOtherThenUndefined(Object opts, String required, String defaults,
@Cached("createOrdinaryWithPrototype(context)") CreateObjectWithPrototypeNode createObjectNode) {
DynamicObject options = createObjectNode.execute(toDynamicObject(opts));
return setDefaultsIfNeeded(options, required, defaults);
}
private static DynamicObject setDefaultsIfNeeded(DynamicObject options, String required, String defaults) {
boolean needDefaults = true;
if (required != null) {
if (required.equals("date") || required.equals("any")) {
needDefaults &= JSGuards.isUndefined(JSObject.get(options, "weekday"));
needDefaults &= JSGuards.isUndefined(JSObject.get(options, "year"));
needDefaults &= JSGuards.isUndefined(JSObject.get(options, "month"));
needDefaults &= JSGuards.isUndefined(JSObject.get(options, "day"));
}
if (required.equals("time") || required.equals("any")) {
needDefaults &= JSGuards.isUndefined(JSObject.get(options, "hour"));
needDefaults &= JSGuards.isUndefined(JSObject.get(options, "minute"));
needDefaults &= JSGuards.isUndefined(JSObject.get(options, "second"));
}
}
Object dateStyle = JSObject.get(options, "dateStyle");
Object timeStyle = JSObject.get(options, "timeStyle");
if (dateStyle != Undefined.instance || timeStyle != Undefined.instance) {
needDefaults = false;
}
if ("date".equals(required) && timeStyle != Undefined.instance) {
throw Errors.createTypeError("timeStyle option is not allowed here");
}
if ("time".equals(required) && dateStyle != Undefined.instance) {
throw Errors.createTypeError("dateStyle option is not allowed here");
}
if (defaults != null) {
if (needDefaults && (defaults.equals("date") || defaults.equals("all"))) {
JSRuntime.createDataPropertyOrThrow(options, "year", "numeric");
JSRuntime.createDataPropertyOrThrow(options, "month", "numeric");
JSRuntime.createDataPropertyOrThrow(options, "day", "numeric");
}
if (needDefaults && (defaults.equals("time") || defaults.equals("all"))) {
JSRuntime.createDataPropertyOrThrow(options, "hour", "numeric");
JSRuntime.createDataPropertyOrThrow(options, "minute", "numeric");
JSRuntime.createDataPropertyOrThrow(options, "second", "numeric");
}
}
return options;
}
private DynamicObject toDynamicObject(Object o) {
if (toObjectNode == null) {
CompilerDirectives.transferToInterpreterAndInvalidate();
toObjectNode = insert(JSToObjectNode.createToObject(getContext()));
}
return (DynamicObject) toObjectNode.execute(o);
}
}