@awayfl/avm2
Version:
Virtual machine for executing AS3 code
88 lines (71 loc) • 2.49 kB
text/typescript
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));
}