From 96a8d7adfa7f0052622757d205b758acbe8e525f Mon Sep 17 00:00:00 2001 From: ning Date: Wed, 23 May 2018 15:27:22 +0800 Subject: [PATCH 1/2] Restrict ternary and If conditions to booleans --- src/slang/interpreter.ts | 6 ++++++ src/slang/utils/rttc.ts | 7 +++++++ 2 files changed, 13 insertions(+) diff --git a/src/slang/interpreter.ts b/src/slang/interpreter.ts index d54bd6f3b4..648748c0a3 100644 --- a/src/slang/interpreter.ts +++ b/src/slang/interpreter.ts @@ -351,6 +351,12 @@ export const evaluators: { [nodeType: string]: Evaluator } = { }, *IfStatement(node: es.IfStatement, context: Context) { const test = yield* evaluate(node.test, context) + const error = rttc.checkIfStatement(context, test) + if (error) { + handleError(context, error) + return undefined + } + if (test) { return yield* evaluate(node.consequent, context) } else if (node.alternate) { diff --git a/src/slang/utils/rttc.ts b/src/slang/utils/rttc.ts index f04820a786..4a1b194356 100644 --- a/src/slang/utils/rttc.ts +++ b/src/slang/utils/rttc.ts @@ -133,3 +133,10 @@ export const checkLogicalExpression = (context: Context, left: Value, right: Val return } } + +export const checkIfStatement = (context: Context, test: Value) => { + const node = context.runtime.nodes[0] + return isBool(test) + ? undefined + : new TypeError(node, ' as condition', 'boolean', typeOf(test)) +} From d1435731b138132542a5dbbe9f0b8de40dd4a339 Mon Sep 17 00:00:00 2001 From: ning Date: Wed, 23 May 2018 15:41:21 +0800 Subject: [PATCH 2/2] Add tests --- src/slang/utils/__tests__/rttc.ts | 32 ++++++++++++++++++++++--------- src/slang/utils/rttc.ts | 4 +--- 2 files changed, 24 insertions(+), 12 deletions(-) diff --git a/src/slang/utils/__tests__/rttc.ts b/src/slang/utils/__tests__/rttc.ts index 33213566a7..654f48072d 100644 --- a/src/slang/utils/__tests__/rttc.ts +++ b/src/slang/utils/__tests__/rttc.ts @@ -1,6 +1,6 @@ import { BinaryOperator, UnaryOperator } from 'estree' import { mockClosure, mockRuntimeContext } from '../../../mocks/context' -import { checkBinaryExpression, checkLogicalExpression, checkUnaryExpression } from '../rttc' +import * as rttc from '../rttc' const num = 0 const bool = true @@ -11,7 +11,7 @@ test('Valid unary type combinations are OK', () => { const operatorValue = [['!', bool], ['+', num], ['-', num]] const context = mockRuntimeContext() const errors = operatorValue.map(opVals => { - return checkUnaryExpression(context, opVals[0] as UnaryOperator, opVals[1]) + return rttc.checkUnaryExpression(context, opVals[0] as UnaryOperator, opVals[1]) }) errors.map(error => expect(error).toBe(undefined)) }) @@ -30,7 +30,7 @@ test('Invalid unary type combinations return TypeError', () => { ] const context = mockRuntimeContext() const errors = operatorValue.map(opVals => { - return checkUnaryExpression(context, opVals[0] as UnaryOperator, opVals[1]) + return rttc.checkUnaryExpression(context, opVals[0] as UnaryOperator, opVals[1]) }) errors.map(error => expect(error).toBeDefined()) }) @@ -47,7 +47,7 @@ test('Valid binary type combinations are OK for +', () => { ] const context = mockRuntimeContext() const errors = operatorValues.map(opVals => { - return checkBinaryExpression(context, opVals[0] as BinaryOperator, opVals[1], opVals[2]) + return rttc.checkBinaryExpression(context, opVals[0] as BinaryOperator, opVals[1], opVals[2]) }) errors.map(error => expect(error).toBe(undefined)) }) @@ -101,7 +101,7 @@ test('Invalid binary type combinations for (-|*|/|%) return TypeError', () => { ] const context = mockRuntimeContext() const errors = operatorValues.map(opVals => { - return checkBinaryExpression(context, opVals[0] as BinaryOperator, opVals[1], opVals[2]) + return rttc.checkBinaryExpression(context, opVals[0] as BinaryOperator, opVals[1], opVals[2]) }) errors.map(error => expect(error).toBeDefined()) }) @@ -119,7 +119,7 @@ test('Valid binary type combinations are OK for (===|!==)', () => { ] const context = mockRuntimeContext() const errors = operatorValues.map(opVals => { - return checkBinaryExpression(context, opVals[0] as BinaryOperator, opVals[1], opVals[2]) + return rttc.checkBinaryExpression(context, opVals[0] as BinaryOperator, opVals[1], opVals[2]) }) errors.map(error => expect(error).toBe(undefined)) }) @@ -143,7 +143,7 @@ test('Invalid binary type combinations for (<|>|<==|>==) return TypeError', () = ] const context = mockRuntimeContext() const errors = operatorValues.map(opVals => { - return checkBinaryExpression(context, opVals[0] as BinaryOperator, opVals[1], opVals[2]) + return rttc.checkBinaryExpression(context, opVals[0] as BinaryOperator, opVals[1], opVals[2]) }) errors.map(error => expect(error).toBeDefined()) }) @@ -152,7 +152,7 @@ test('Valid logical type combinations are OK', () => { const operatorValues = [[bool, bool], [bool, bool]] const context = mockRuntimeContext() const errors = operatorValues.map(opVals => { - return checkLogicalExpression(context, opVals[0], opVals[1]) + return rttc.checkLogicalExpression(context, opVals[0], opVals[1]) }) errors.map(error => expect(error).toBe(undefined)) }) @@ -169,7 +169,21 @@ test('Invalid logical type combinations return TypeError', () => { ] const context = mockRuntimeContext() const errors = operatorValues.map(opVals => { - return checkLogicalExpression(context, opVals[0], opVals[1]) + return rttc.checkLogicalExpression(context, opVals[0], opVals[1]) }) errors.map(error => expect(error).toBeDefined()) }) + +test('Valid ternary/if test expressions are OK', () => { + const operatorValues = [bool] + const context = mockRuntimeContext() + const errors = operatorValues.map(opVal => rttc.checkIfStatement(context, opVal)) + errors.map(error => expect(error).toBe(undefined)) +}) + +test('Invalid ternary/if test expressions return TypeError', () => { + const operatorValues = [num, str, func] + const context = mockRuntimeContext() + const errors = operatorValues.map(opVal => rttc.checkIfStatement(context, opVal)) + errors.map(error => expect(error).toBeDefined()) +}) diff --git a/src/slang/utils/rttc.ts b/src/slang/utils/rttc.ts index 4a1b194356..9ef32d5579 100644 --- a/src/slang/utils/rttc.ts +++ b/src/slang/utils/rttc.ts @@ -136,7 +136,5 @@ export const checkLogicalExpression = (context: Context, left: Value, right: Val export const checkIfStatement = (context: Context, test: Value) => { const node = context.runtime.nodes[0] - return isBool(test) - ? undefined - : new TypeError(node, ' as condition', 'boolean', typeOf(test)) + return isBool(test) ? undefined : new TypeError(node, ' as condition', 'boolean', typeOf(test)) }