Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions src/slang/interpreter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,12 @@ export const evaluators: { [nodeType: string]: Evaluator<es.Node> } = {
},
*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) {
Expand Down
32 changes: 23 additions & 9 deletions src/slang/utils/__tests__/rttc.ts
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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))
})
Expand All @@ -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())
})
Expand All @@ -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))
})
Expand Down Expand Up @@ -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())
})
Expand All @@ -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))
})
Expand All @@ -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())
})
Expand All @@ -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))
})
Expand All @@ -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())
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's make this check if error is instance of TypeError

})
5 changes: 5 additions & 0 deletions src/slang/utils/rttc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,3 +133,8 @@ 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))
}