mirror of
https://github.com/facebookarchive/prepack.git
synced 2024-09-11 14:46:37 +03:00
Make some builtin functions aware of abstract strings.
Summary: Builtin functions that are side-effect free can trivially be modified to return abstract values if one or more of their arguments are abstract. This pull request provides such behavior for the Error constructor, Error.prototype.toString and String.prototype.split and slice. Closes https://github.com/facebook/prepack/pull/1110 Differential Revision: D6182526 Pulled By: hermanventer fbshipit-source-id: d95c8045ff75c35f1b55dc668c080aa394ccb43d
This commit is contained in:
parent
0948e13141
commit
44aae027b7
@ -12,7 +12,13 @@
|
||||
import type { Realm } from "../../realm.js";
|
||||
import type { LexicalEnvironment } from "../../environment.js";
|
||||
import { ObjectValue, FunctionValue, NativeFunctionValue, StringValue } from "../../values/index.js";
|
||||
import { OrdinaryCreateFromConstructor, ToStringPartial, Get, DefinePropertyOrThrow } from "../../methods/index.js";
|
||||
import {
|
||||
DefinePropertyOrThrow,
|
||||
Get,
|
||||
OrdinaryCreateFromConstructor,
|
||||
ToStringPartial,
|
||||
ToStringValue,
|
||||
} from "../../methods/index.js";
|
||||
import invariant from "../../invariant.js";
|
||||
import type { BabelNodeSourceLocation } from "babel-types";
|
||||
|
||||
@ -115,11 +121,11 @@ export function build(name: string, realm: Realm, inheritError?: boolean = true)
|
||||
// 3. If message is not undefined, then
|
||||
if (!message.mightBeUndefined()) {
|
||||
// a. Let msg be ? ToString(message).
|
||||
let msg = ToStringPartial(realm, message);
|
||||
let msg = message.getType() === StringValue ? message : ToStringValue(realm, message);
|
||||
|
||||
// b. Let msgDesc be the PropertyDescriptor{[[Value]]: msg, [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: true}.
|
||||
let msgDesc = {
|
||||
value: new StringValue(realm, msg),
|
||||
value: msg,
|
||||
writable: true,
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
|
@ -10,13 +10,17 @@
|
||||
/* @flow */
|
||||
|
||||
import type { Realm } from "../../realm.js";
|
||||
import { ObjectValue, StringValue, UndefinedValue } from "../../values/index.js";
|
||||
import { AbstractValue, ObjectValue, StringValue, UndefinedValue } from "../../values/index.js";
|
||||
import { ToStringPartial, Get } from "../../methods/index.js";
|
||||
import buildExpressionTemplate from "../../utils/builder.js";
|
||||
|
||||
export default function(realm: Realm, obj: ObjectValue): void {
|
||||
return build("Error", realm, obj);
|
||||
}
|
||||
|
||||
const tsTemplateSrc = "(A).toString()";
|
||||
const tsTemplate = buildExpressionTemplate(tsTemplateSrc);
|
||||
|
||||
export function build(name: string, realm: Realm, obj: ObjectValue): void {
|
||||
// ECMA262 19.5.3.2
|
||||
obj.defineNativeProperty("message", realm.intrinsics.emptyString);
|
||||
@ -36,12 +40,18 @@ export function build(name: string, realm: Realm, obj: ObjectValue): void {
|
||||
|
||||
// 3. Let name be ? Get(O, "name").
|
||||
let nameValue = Get(realm, O, "name");
|
||||
if (nameValue instanceof AbstractValue) {
|
||||
return AbstractValue.createFromTemplate(realm, tsTemplate, StringValue, [O], tsTemplateSrc);
|
||||
}
|
||||
|
||||
// 4. If name is undefined, let name be "Error"; otherwise let name be ? ToString(name).
|
||||
let nameString = nameValue instanceof UndefinedValue ? "Error" : ToStringPartial(realm, nameValue);
|
||||
|
||||
// 5. Let msg be ? Get(O, "message").
|
||||
let msg = Get(realm, O, "message");
|
||||
if (msg instanceof AbstractValue) {
|
||||
return AbstractValue.createFromTemplate(realm, tsTemplate, StringValue, [O], tsTemplateSrc);
|
||||
}
|
||||
|
||||
// 6. If msg is undefined, let msg be the empty String; otherwise let msg be ? ToString(msg).
|
||||
msg = msg instanceof UndefinedValue ? "" : ToStringPartial(realm, msg);
|
||||
|
@ -29,6 +29,12 @@ import {
|
||||
import { SplitMatch, RequireObjectCoercible } from "../../methods/abstract.js";
|
||||
import { HasSomeCompatibleType } from "../../methods/has.js";
|
||||
import invariant from "../../invariant.js";
|
||||
import buildExpressionTemplate from "../../utils/builder.js";
|
||||
|
||||
const sliceTemplateSrc = "(A).slice(B,C)";
|
||||
const sliceTemplate = buildExpressionTemplate(sliceTemplateSrc);
|
||||
const splitTemplateSrc = "(A).split(B,C)";
|
||||
const splitTemplate = buildExpressionTemplate(splitTemplateSrc);
|
||||
|
||||
export default function(realm: Realm, obj: ObjectValue): ObjectValue {
|
||||
// ECMA262 21.1.3
|
||||
@ -579,6 +585,10 @@ export default function(realm: Realm, obj: ObjectValue): ObjectValue {
|
||||
// 1. Let O be ? RequireObjectCoercible(this value).
|
||||
let O = RequireObjectCoercible(realm, context);
|
||||
|
||||
if (O instanceof AbstractValue && O.getType() === StringValue) {
|
||||
return AbstractValue.createFromTemplate(realm, sliceTemplate, StringValue, [O, start, end], sliceTemplateSrc);
|
||||
}
|
||||
|
||||
// 2. Let S be ? ToString(O).
|
||||
let S = ToString(realm, O.throwIfNotConcrete());
|
||||
|
||||
@ -609,6 +619,16 @@ export default function(realm: Realm, obj: ObjectValue): ObjectValue {
|
||||
// 1. Let O be ? RequireObjectCoercible(this value).
|
||||
let O = RequireObjectCoercible(realm, context);
|
||||
|
||||
if (O instanceof AbstractValue && O.getType() === StringValue) {
|
||||
return AbstractValue.createFromTemplate(
|
||||
realm,
|
||||
splitTemplate,
|
||||
StringValue,
|
||||
[O, separator, limit],
|
||||
splitTemplateSrc
|
||||
);
|
||||
}
|
||||
|
||||
// 2. If separator is neither undefined nor null, then
|
||||
if (!HasSomeCompatibleType(separator, UndefinedValue, NullValue)) {
|
||||
// a. Let splitter be ? GetMethod(separator, @@split).
|
||||
|
@ -679,6 +679,31 @@ export function ToStringPartial(realm: Realm, val: string | Value): string {
|
||||
return ToString(realm, typeof val === "string" ? val : val.throwIfNotConcrete());
|
||||
}
|
||||
|
||||
export function ToStringValue(realm: Realm, val: Value): Value {
|
||||
if (val.getType() === StringValue) return val;
|
||||
let str;
|
||||
if (typeof val === "string") {
|
||||
str = val;
|
||||
} else if (val instanceof NumberValue) {
|
||||
str = val.value + "";
|
||||
} else if (val instanceof UndefinedValue) {
|
||||
str = "undefined";
|
||||
} else if (val instanceof NullValue) {
|
||||
str = "null";
|
||||
} else if (val instanceof SymbolValue) {
|
||||
throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError);
|
||||
} else if (val instanceof BooleanValue) {
|
||||
str = val.value ? "true" : "false";
|
||||
} else if (val instanceof ObjectValue) {
|
||||
let primValue = ToPrimitiveOrAbstract(realm, val, "string");
|
||||
if (primValue.getType() === StringValue) return primValue;
|
||||
str = ToStringPartial(realm, primValue);
|
||||
} else {
|
||||
throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError, "unknown value type, can't coerce to string");
|
||||
}
|
||||
return new StringValue(realm, str);
|
||||
}
|
||||
|
||||
// ECMA262 7.1.2
|
||||
export function ToBoolean(realm: Realm, val: ConcreteValue): boolean {
|
||||
if (val instanceof BooleanValue) {
|
||||
|
6
test/serializer/abstract/Error.js
Normal file
6
test/serializer/abstract/Error.js
Normal file
@ -0,0 +1,6 @@
|
||||
let x = global.__abstract ? __abstract("string", "('abc')") : 'abc';
|
||||
let err1 = new Error(x);
|
||||
err1.name = x;
|
||||
let err2 = new Error(err1);
|
||||
|
||||
inspect = function() { return "" + err2; }
|
5
test/serializer/abstract/String.js
Normal file
5
test/serializer/abstract/String.js
Normal file
@ -0,0 +1,5 @@
|
||||
let x = global.__abstract ? __abstract("string", "('a,b,c,d,e')") : 'a,b,c,d,e';
|
||||
let sliced = x.slice(2, 3);
|
||||
let split = x.split(',', 2);
|
||||
|
||||
inspect = function() { return sliced + split.join(':'); }
|
Loading…
Reference in New Issue
Block a user