UNPKG

@awayfl/avm2

Version:

Virtual machine for executing AS3 code

88 lines (71 loc) 2.49 kB
import { Multiname } from '../../abc/lazy/Multiname'; import { Settings } from '../../Settings'; import { CompilerState, VAR_KIND } from '../CompilerState'; import { emitInlineStack } from './emitInlineVars'; import { axCoerceNumber } from '../../run/axCoerceNumber'; import { axCoerceInt } from '../../run/axCoerceInt'; import { axCoerceUint } from '../../run/axCoerceUint'; import { axCoerceBoolean } from '../../run/axCoerceBoolean'; import { axCoerceString } from '../../run/axCoerceString'; const typeToCoerceMapping: Record<string, (x: string) => string > = { ['Number']: (x) => { if (Settings.FOLLOW_AS3_BUG) { return `sec.AXNumber.axCoerce(${x})`; } return `(+${x})`; }, ['int']: (x) => { if (Settings.FOLLOW_AS3_BUG) { return `sec.AXNumber.axCoerce(${x}) | 0`; } return `(${x}|0)`; }, ['uint']: (x) => `(${x}>>>0)`, ['Boolean']: (x) => `(!!${x})`, ['String']: (x: string) => `(${x}==null?null:''+ ${x})`, }; const staticCoerceMapping: Record<string, (v: any) => any> = { ['Number']: axCoerceNumber, ['int']: axCoerceInt, ['uint']: axCoerceUint, ['Boolean']: axCoerceBoolean, ['String']: axCoerceString, }; export function isPrimitiveType(type: Multiname): boolean { return type && type.name && (type.name in staticCoerceMapping); } /** * Emit coercion mapping for primitive values: arguments, returns, fast coercion * @param state * @param stackIndexOrName index - when it it stack, name - when is local or not stack value * @param type * @param inline Inline coerce return name without coersion instead of null */ export function emitPrimitiveCoerce ( state: CompilerState, stackIndexOrName: number | string, type: Multiname, inline = false ): string | null { if (!isPrimitiveType(type)) { // no coerce if not required if (!inline) { return null; } return typeof stackIndexOrName === 'string' ? stackIndexOrName : emitInlineStack(state, stackIndexOrName); } if (typeof stackIndexOrName === 'string') { return typeToCoerceMapping[type.name](stackIndexOrName); } const constAlias = state.getConstAliasMeta(stackIndexOrName); // coerce inline for const, const will be transformed to specific type in compiler state if (constAlias && constAlias.kind === VAR_KIND.CONST) { const res = staticCoerceMapping[type.name](constAlias.value); if (typeof res === 'string') return JSON.stringify(res); return '' + res; } return typeToCoerceMapping[type.name](emitInlineStack(state, stackIndexOrName)); }