Created
October 16, 2018 21:33
-
-
Save devsnek/c0d9a583043cabc22a9ce3b2a96154a7 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/src/abstract-ops/testing-comparison.mjs b/src/abstract-ops/testing-comparison.mjs | |
index c03de47..032d52f 100644 | |
--- a/src/abstract-ops/testing-comparison.mjs | |
+++ b/src/abstract-ops/testing-comparison.mjs | |
@@ -38,6 +38,8 @@ export function RequireObjectCoercible(argument) { | |
return surroundingAgent.Throw('TypeError', 'undefined cannot be convered to an object'); | |
case 'Null': | |
return surroundingAgent.Throw('TypeError', 'null cannot be converted to an object'); | |
+ case 'ReferenceValue': | |
+ return surroundingAgent.Throw('TypeError', 'reference cannot be converted to an object'); | |
case 'Boolean': | |
case 'Number': | |
case 'String': | |
diff --git a/src/abstract-ops/type-conversion.mjs b/src/abstract-ops/type-conversion.mjs | |
index 563e140..dd5f69b 100644 | |
--- a/src/abstract-ops/type-conversion.mjs | |
+++ b/src/abstract-ops/type-conversion.mjs | |
@@ -49,9 +49,7 @@ export function ToPrimitive(input, PreferredType) { | |
} | |
// 7.1.1.1 #sec-ordinarytoprimitive | |
-export function OrdinaryToPrimitive( | |
- O, hint, | |
-) { | |
+export function OrdinaryToPrimitive(O, hint) { | |
Assert(Type(O) === 'Object'); | |
Assert(Type(hint) === 'String' | |
&& (hint.stringValue() === 'string' || hint.stringValue() === 'number')); | |
@@ -75,6 +73,10 @@ export function OrdinaryToPrimitive( | |
// 7.1.2 #sec-toboolean | |
export function ToBoolean(argument) { | |
+ if (Type(argument) === 'ReferenceValue') { | |
+ return Value.true; | |
+ } | |
+ | |
if (Type(argument) === 'Undefined') { | |
return Value.false; | |
} | |
@@ -131,6 +133,7 @@ export function ToNumber(argument) { | |
// FIXME(devsnek): https://tc39.github.io/ecma262/#sec-runtime-semantics-mv-s | |
return new Value(+(argument.stringValue())); | |
case 'Symbol': | |
+ case 'ReferenceValue': | |
return surroundingAgent.Throw('TypeError'); | |
case 'Object': { | |
const primValue = Q(ToPrimitive(argument, 'Number')); | |
@@ -272,6 +275,7 @@ export function ToString(argument) { | |
return NumberToString(argument); | |
case 'String': | |
return argument; | |
+ case 'ReferenceValue': | |
case 'Symbol': | |
return surroundingAgent.Throw('TypeError'); | |
case 'Object': { | |
@@ -310,6 +314,8 @@ export function ToObject(argument) { | |
return surroundingAgent.Throw('TypeError', 'cannot convert undefined to object'); | |
case 'Null': | |
return surroundingAgent.Throw('TypeError', 'cannot convert null to object'); | |
+ case 'ReferenceValue': | |
+ return surroundingAgent.Throw('TypeError', 'cannot convert reference to object'); | |
case 'Boolean': { | |
const obj = ObjectCreate(surroundingAgent.intrinsic('%BooleanPrototype%')); | |
obj.BooleanData = argument; | |
diff --git a/src/api.mjs b/src/api.mjs | |
index 5e212ea..c3febad 100644 | |
--- a/src/api.mjs | |
+++ b/src/api.mjs | |
@@ -145,7 +145,19 @@ export { | |
export function Inspect(value, realm = surroundingAgent.currentRealmRecord, quote = true, indent = 0) { | |
const type = Type(value); | |
- if (type === 'Undefined') { | |
+ if (type === 'ReferenceValue') { | |
+ const { Reference } = value; | |
+ const name = Inspect(Reference.ReferencedName, realm, false, 0); | |
+ let prefix = ''; | |
+ if (Reference.BaseValue === realm.GlobalObject) { | |
+ prefix = '(global).'; | |
+ } else if (Reference.BaseValue === Value.null) { | |
+ prefix = 'unresolved '; | |
+ } else if (Reference.BaseValue instanceof Value) { | |
+ prefix = '(intermediate value).'; | |
+ } | |
+ return `[reference -> ${prefix}${name}]`; | |
+ } else if (type === 'Undefined') { | |
return 'undefined'; | |
} else if (type === 'Null') { | |
return 'null'; | |
@@ -202,5 +214,5 @@ export function Inspect(value, realm = surroundingAgent.currentRealmRecord, quot | |
} | |
} | |
} | |
- throw new RangeError(); | |
+ throw new RangeError(type); | |
} | |
diff --git a/src/parse.mjs b/src/parse.mjs | |
index e088af7..367a1d8 100644 | |
--- a/src/parse.mjs | |
+++ b/src/parse.mjs | |
@@ -4,6 +4,59 @@ const Parser = acorn.Parser.extend((P) => class Parse262 extends P { | |
constructor(options, source) { | |
super({ ...options, ecmaVersion: 2019 }, source); | |
} | |
+ | |
+ parseExprAtom(refDestructuringErrors) { | |
+ if (this.type === acorn.tokTypes.star) { | |
+ // UnaryExpression : `*` UnaryExpression | |
+ this.eat(acorn.tokTypes.star); | |
+ const node = this.startNode(); | |
+ node.operator = '*'; | |
+ node.prefix = true; | |
+ node.argument = this.parseMaybeUnary(refDestructuringErrors); | |
+ return this.finishNode(node, 'UnaryExpression'); | |
+ } else if (this.type === acorn.tokTypes.starstar) { | |
+ this.eat(acorn.tokTypes.starstar); | |
+ const outer = this.startNode(); | |
+ outer.operator = '*'; | |
+ | |
+ const inner = this.startNode(); | |
+ inner.operator = '*'; | |
+ inner.prefix = true; | |
+ inner.argument = this.parseMaybeUnary(refDestructuringErrors); | |
+ | |
+ outer.argument = this.finishNode(inner, 'UnaryExpression'); | |
+ | |
+ return this.finishNode(outer, 'UnaryExpression'); | |
+ } else if (this.type === acorn.tokTypes.bitwiseAND) { | |
+ // UnaryExpression : | |
+ // `&` MemberExpression | |
+ // `&` Identifier | |
+ this.eat(acorn.tokTypes.bitwiseAND); | |
+ const node = this.startNode(); | |
+ node.operator = '&'; | |
+ const startPos = this.start; | |
+ const startLoc = this.startLoc; | |
+ let base = this.parseIdent(false); | |
+ while (true) { | |
+ const computed = this.eat(acorn.tokTypes.bracketL); | |
+ if (!computed && !this.eat(acorn.tokTypes.dot)) { | |
+ break; | |
+ } | |
+ const inner = this.startNodeAt(startPos, startLoc); | |
+ inner.object = base; | |
+ inner.property = computed ? this.parseExpression() : this.parseIdent(true); | |
+ inner.computed = computed; | |
+ if (computed) { | |
+ this.expect(acorn.tokTypes.bracketR); | |
+ } | |
+ base = this.finishNode(inner, 'MemberExpression'); | |
+ } | |
+ this.semicolon(); | |
+ node.argument = base; | |
+ return this.finishNode(node, 'UnaryExpression'); | |
+ } | |
+ return super.parseExprAtom(refDestructuringErrors); | |
+ } | |
}); | |
function deepFreeze(obj) { | |
diff --git a/src/runtime-semantics/MemberExpression.mjs b/src/runtime-semantics/MemberExpression.mjs | |
index c746cb0..3f06f13 100644 | |
--- a/src/runtime-semantics/MemberExpression.mjs | |
+++ b/src/runtime-semantics/MemberExpression.mjs | |
@@ -47,7 +47,7 @@ function* Evaluate_MemberExpression_IdentifierName(MemberExpression, IdentifierN | |
// #sec-property-accessors-runtime-semantics-evaluation | |
// MemberExpression : | |
// MemberExpression `[` Expression `]` | |
-// MemberEXpression `.` IdentifierName | |
+// MemberExpression `.` IdentifierName | |
// CallExpression : | |
// CallExpression `[` Expression `]` | |
// CallExpression `.` IdentifierName | |
diff --git a/src/runtime-semantics/UnaryExpression.mjs b/src/runtime-semantics/UnaryExpression.mjs | |
index 1f29657..42a5ce2 100644 | |
--- a/src/runtime-semantics/UnaryExpression.mjs | |
+++ b/src/runtime-semantics/UnaryExpression.mjs | |
@@ -25,7 +25,7 @@ import { | |
} from '../abstract-ops/all.mjs'; | |
import { Evaluate_Expression } from '../evaluator.mjs'; | |
import { Q, ReturnIfAbrupt, X } from '../completion.mjs'; | |
-import { Type, Value } from '../value.mjs'; | |
+import { Type, Value, ReferenceValue } from '../value.mjs'; | |
import { outOfRange } from '../helpers.mjs'; | |
// #sec-delete-operator-runtime-semantics-evaluation | |
@@ -80,6 +80,8 @@ function* Evaluate_UnaryExpression_Typeof(UnaryExpression) { | |
const type = Type(val); | |
switch (type) { | |
+ case 'Reference': | |
+ return new Value('reference'); | |
case 'Undefined': | |
return new Value('undefined'); | |
case 'Null': | |
@@ -160,6 +162,25 @@ export function* Evaluate_UnaryExpression(UnaryExpression) { | |
case isUnaryExpressionWithBang(UnaryExpression): | |
return yield* Evaluate_UnaryExpression_Bang(UnaryExpression.argument); | |
+ case UnaryExpression.operator === '*': { | |
+ const expr = yield* Evaluate_Expression(UnaryExpression.argument); | |
+ const value = Q(GetValue(expr)); | |
+ if (Type(value) !== 'ReferenceValue') { | |
+ return surroundingAgent.Throw('TypeError', 'Only references can be dereferenced'); | |
+ } | |
+ return Q(GetValue(value.Reference)); | |
+ } | |
+ | |
+ case UnaryExpression.operator === '&': { | |
+ const ref = yield* Evaluate_Expression(UnaryExpression.argument); | |
+ ReturnIfAbrupt(ref); | |
+ Assert(Type(ref) === 'Reference'); | |
+ if (!(ref.BaseValue instanceof Value)) { | |
+ Q(GetValue(ref)); | |
+ } | |
+ return new ReferenceValue(ref); | |
+ } | |
+ | |
default: | |
throw outOfRange('Evaluate_UnaryExpression', UnaryExpression); | |
} | |
diff --git a/src/value.mjs b/src/value.mjs | |
index 4f42350..3734655 100644 | |
--- a/src/value.mjs | |
+++ b/src/value.mjs | |
@@ -68,6 +68,13 @@ export function Value(value) { | |
export class PrimitiveValue extends Value {} | |
+export class ReferenceValue extends Value { | |
+ constructor(ref) { | |
+ super(); | |
+ this.Reference = ref; | |
+ } | |
+} | |
+ | |
export class UndefinedValue extends PrimitiveValue {} | |
export class NullValue extends PrimitiveValue {} | |
@@ -974,11 +981,7 @@ export class ProxyExoticObjectValue extends ObjectValue { | |
} | |
export class Reference { | |
- constructor( | |
- BaseValue, | |
- ReferencedName, | |
- StrictReference, | |
- ) { | |
+ constructor(BaseValue, ReferencedName, StrictReference) { | |
this.BaseValue = BaseValue; | |
this.ReferencedName = ReferencedName; | |
this.StrictReference = StrictReference; | |
@@ -1026,6 +1029,10 @@ export class DataBlock extends Uint8Array { | |
} | |
export function Type(val) { | |
+ if (val instanceof ReferenceValue) { | |
+ return 'ReferenceValue'; | |
+ } | |
+ | |
if (val instanceof UndefinedValue) { | |
return 'Undefined'; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment