@nirguna/plugin-fasm 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +48 -0
- package/lib/add-label-prefix/index.js +50 -0
- package/lib/apply-equality/index.js +8 -0
- package/lib/apply-inc/index.js +8 -0
- package/lib/apply-include/index.js +17 -0
- package/lib/apply-registers/index.js +44 -0
- package/lib/apply-types/index.js +79 -0
- package/lib/convert-args-to-regs/index.js +170 -0
- package/lib/convert-assign-to-add/index.js +5 -0
- package/lib/convert-assign-to-and/index.js +5 -0
- package/lib/convert-assign-to-member/index.js +5 -0
- package/lib/convert-assign-to-mov/index.js +53 -0
- package/lib/convert-assign-to-or/index.js +5 -0
- package/lib/convert-assign-to-shl/index.js +5 -0
- package/lib/convert-assign-to-sub/index.js +5 -0
- package/lib/convert-assign-to-xor/index.js +5 -0
- package/lib/convert-await-to-call/index.js +53 -0
- package/lib/convert-bios-clear-screen-to-int-10/index.js +8 -0
- package/lib/convert-bios-print-line-to-int-10/index.js +52 -0
- package/lib/convert-bios-read-char-to-int-16/index.js +18 -0
- package/lib/convert-bios-read-sector-to-int-13/index.js +80 -0
- package/lib/convert-bios-reboot-to-jmp-far/index.js +5 -0
- package/lib/convert-bios-scroll-to-int-10/index.js +16 -0
- package/lib/convert-const-to-equ/index.js +15 -0
- package/lib/convert-dec-to-hex/index.js +19 -0
- package/lib/convert-declaration-to-mov/index.js +23 -0
- package/lib/convert-do-while-to-jnz/index.js +155 -0
- package/lib/convert-equ-call-to-member/index.js +30 -0
- package/lib/convert-function-to-label/index.js +114 -0
- package/lib/convert-if-to-jmp/index.js +166 -0
- package/lib/convert-if-to-jmp/operator.js +27 -0
- package/lib/convert-linux-exit-to-syscall/index.js +15 -0
- package/lib/convert-linux-write-to-syscall/index.js +48 -0
- package/lib/convert-mov-to-add/index.js +5 -0
- package/lib/convert-return-to-eax/index.js +76 -0
- package/lib/convert-strncmp-to-repe-cmpsb/index.js +23 -0
- package/lib/convert-ternary-to-if/index.js +5 -0
- package/lib/convert-ureg-to-reg/index.js +108 -0
- package/lib/convert-while-to-jz/index.js +158 -0
- package/lib/extract-labeled-block/index.js +68 -0
- package/lib/index.js +93 -0
- package/lib/remove-useless-braces/index.js +5 -0
- package/lib/remove-useless-declarations/index.js +7 -0
- package/lib/remove-useless-promise/index.js +5 -0
- package/lib/split-assign-await-with-assign-eax/index.js +41 -0
- package/lib/split-binary-expression/index.js +31 -0
- package/lib/split-stack-operations/index.js +50 -0
- package/lib/switch-cmp-operands/index.js +19 -0
- package/package.json +56 -0
package/README.md
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
## putout-plugin-fasm
|
|
2
|
+
|
|
3
|
+
Transforms:
|
|
4
|
+
|
|
5
|
+
- ✅[`add-label-refix`](https://putout.cloudcmd.io/#/gist/2123b2e3a71354a60f65e11e5f809c24/19c063b0fd95f2198f76daf43c466c3ad846e37a);
|
|
6
|
+
- ✅[`apply-cmp`](https://putout.cloudcmd.io/#/gist/d1520a4277ef2149bfc98d777108d400/99853b56f55c65c8e965d06740127d78288f5aa7);
|
|
7
|
+
- ✅[`apply-include`](https://putout.cloudcmd.io/#/gist/ad5ac3ef4892c5d8365163fb6adc8547/e186cc7911b5b407bf824ea850074950c15a9e19);
|
|
8
|
+
- ✅[`apply-registers`](https://putout.cloudcmd.io/#/gist/7219eaf624623d9a80d3e8f90bb3a498/8f2606c8f5ef483ed9ec5cecbaaa041e6e327455);
|
|
9
|
+
- ✅[`move-vars-to-bottom`](https://putout.cloudcmd.io/#/gist/3e3b83e6e23650d819e56b88f961051c/89ef3eafd926e14736ddc244d044de47709c8b69);
|
|
10
|
+
- ✅[`move-equ-to-bottom`](https://putout.cloudcmd.io/#/gist/de37a39902edaa97b981d7484dd67052/70c423b9d177774482bd4dacbafd8723defb2f3a);
|
|
11
|
+
- ✅[`convert-equ-call-to-member`](https://putout.cloudcmd.io/#/gist/94c8110db310e6979c2fdc1c9311337a/6a17fab68cdf7adbd17952b7fead658599489c9c);
|
|
12
|
+
- ✅[`convert-assign-to-member`](https://putout.cloudcmd.io/#/gist/7624d8ad5507586ba4ba25f30a9ae26b/085ae7ea6a1c449013fd5806c390ac1ce5eb1c17);
|
|
13
|
+
- ✅[`convert-assign-to-add`](https://putout.cloudcmd.io/#/gist/043e2fec17734c5671a8528091d1275b/f200da1222cdd86fee5fd3125a67f2d0703391d7);
|
|
14
|
+
- ✅[`convert-assign-to-sub`](https://putout.cloudcmd.io/#/gist/6543aba90ae4ac95b5fb7a79c0314f25/9eb8259ffa611b714ebd4b2e7be5ca124aae7e18);
|
|
15
|
+
- ✅[`convert-assign-to-mov`](https://putout.cloudcmd.io/#/gist/1e4a2f439d20fe7cad91d75881bce08a/e5dc7cad875e4be3faafb47f384115cf28a62d25);
|
|
16
|
+
- ✅[`convert-assign-to-xor`](https://putout.cloudcmd.io/#/gist/1e4a2f439d20fe7cad91d75881bce08a/e5dc7cad875e4be3faafb47f384115cf28a62d2);
|
|
17
|
+
- ✅[`convert-assign-to-shl`](https://putout.cloudcmd.io/#/gist/e7b609200727bb78cfa073c0c1220c46/da0309ac125855533f7e0baa332b0670fd46f6b2);
|
|
18
|
+
- ✅[`convert-assign-to-add`](https://putout.cloudcmd.io/#/gist/0e35a6cf08cb74aafa30810133bfa062/91f9cdf97b3884747e1c0a0b9521a8fc6cd067b2);
|
|
19
|
+
- ✅[`convert-assign-to-or`](https://putout.cloudcmd.io/#/gist/a456caa9f956fdb8b19f21065de96209/c411fb6937fd37d5d97cd72a2740b897b0c30092);
|
|
20
|
+
- ✅[`convert-args-to-regs`](https://putout.cloudcmd.io/#/gist/7d76d789c35b33dfacc149e32214537f/c35a2f0fe80b6a4c00bbb99249562069d072fc64);
|
|
21
|
+
- ✅[`convert-bios-clear-screen-to-int-10`](https://putout.cloudcmd.io/#/gist/602d579a76cf38b5927f0207ee4bcf98/a31a08ce34e4a83ca909a9afc2ec76533ded8c82);
|
|
22
|
+
- ✅[`convert-bios-print-line-to-int-10`](https://putout.cloudcmd.io/#/gist/d87efe4df8f505162e7d922c4fbacd9b/24b97107a50d00df0f012fed507d47aafb5109e2);
|
|
23
|
+
- ✅[`convert-bios-read-char-to-int-16`](https://putout.cloudcmd.io/#/gist/d87efe4df8f505162e7d922c4fbacd9b/af89e4d564811f38b703f482469f5d874a17bad0);
|
|
24
|
+
- ✅[`convert-bios-read-sector-int-13`](https://putout.cloudcmd.io/#/gist/6ae8820756ba1af043f93f3bdb49360e/a575cf6f5432ca215838795c2617c161f2b981cb);
|
|
25
|
+
- ✅[`convert-bios-scroll-to-int-10`](https://putout.cloudcmd.io/#/gist/d87efe4df8f505162e7d922c4fbacd9b/95520a650428a2defd77a65ffc255a073540d902);
|
|
26
|
+
- ✅[`convert-bios-reboot-to-jmp-far`](https://putout.cloudcmd.io/#/gist/44a87987c4d6d3130b5004f8818a3454/4c6dd61184b46c60b8d8dc653232d567238ea865);
|
|
27
|
+
- ✅[`convert-linux-write-to-syscall`](https://putout.cloudcmd.io/#/gist/f036440b0d8c59b32af823511cfea395/b4483ea5a2731c3cff571ce7a6cf45e77f8b49be);
|
|
28
|
+
- ✅[`convert-linux-exit-to-syscall`](https://putout.cloudcmd.io/#/gist/f94a1ce412b33d8e259a9024a0666600/926ae2e4906f6bcacce61725055d429a840d7d3d);
|
|
29
|
+
- ✅[`convert-const-to-equ`](https://putout.cloudcmd.io/#/gist/c0d18aa7138e0e238d41051a2929311a/b45ad43ce7738390f6af9479536b145fdaebf84c);
|
|
30
|
+
- ✅[`convert-strncmp-to-repe-cmsb`](https://putout.cloudcmd.io/#/gist/397388e71e71442d3dd5bebd3a424da6/8eb60aaaf4b5afb85f87ddcd0af51266db158263);
|
|
31
|
+
- ✅[`convert-ternary-to-if`](https://putout.cloudcmd.io/#/gist/4a48fb3a515ef5947032f344b65a0db3/18cf1b250156953febbb8ac5652ce8f40b1192b7);
|
|
32
|
+
- ✅[`convert-function-to-label`](https://putout.cloudcmd.io/#/gist/415829430c67b2824c26901b2cc89fb0/ed8a2186889a0135302bbb64fee0a9ce2d084800);
|
|
33
|
+
- ✅[`convert-if-to-jmp`](https://putout.cloudcmd.io/#/gist/415829430c67b2824c26901b2cc89fb0/ed8a2186889a0135302bbb64fee0a9ce2d084800);
|
|
34
|
+
- ✅[`convert-return-to-eax`](https://putout.cloudcmd.io/#/gist/72dfce2332d04829b70703b389464840/75d1d02c87506a2125e44ee24797240293a3a27b);
|
|
35
|
+
- ✅[`convert-await-to-call`](https://putout.cloudcmd.io/#/gist/0ec93b79f05e36b8ed54e79acd5813d1/e1210ac63069d81dd5f679b324ad82b49a2f25ad);
|
|
36
|
+
- ✅[`convert-do-while-to-jnz`](https://putout.cloudcmd.io/#/gist/fe11c0afb23c53585fcb55189593a07a/f194c349cd774d5ab49e0e198c2855e1bb8be6ac);
|
|
37
|
+
- ✅[`convert-while-to-jz`](https://putout.cloudcmd.io/#/gist/6be739dd8e167c8a1b1a72a1830a4920/c24d22911ea61d74fb5391c4cc31821da4055116);
|
|
38
|
+
- ✅[`converg-ureg-to-reg`](https://putout.cloudcmd.io/#/gist/794275bc0cf83432615333b1e41f1975/bac80042b461cb09d8f83402de6fd1f1dafb465c);
|
|
39
|
+
- ✅[`convert-mov-to-add`](https://putout.cloudcmd.io/#/gist/2f03076ac9a794c880fcbadcc1cd502d/145f3e930f9514b79adc47076354f2203476607f);
|
|
40
|
+
- ✅[`convert-declaration-to-mov`](https://putout.cloudcmd.io/#/gist/184b75da1a92ae554b522d004c520017/689ff370e4b20204957a22f499d6f963614b7afb);
|
|
41
|
+
- ✅[`extract-labeled-block`](https://putout.cloudcmd.io/#/gist/033921790a761eef2361aa8b4708e29e/e0e0eb1aa41791c2c01e858f7c198f1a408c6418);
|
|
42
|
+
- ✅[`split-stack-operations`](https://putout.cloudcmd.io/#/gist/e7b609200727bb78cfa073c0c1220c46/da0309ac125855533f7e0baa332b0670fd46f6b2);
|
|
43
|
+
- ✅[`split-assign-await-with-assign-eax`](https://putout.cloudcmd.io/#/gist/ad1520cf5e626eb1cc01befa9e900cd1/9392f49641b09d50ea2d29d514b3ab253b21897c);
|
|
44
|
+
- ✅[`apply-inc`](https://putout.cloudcmd.io/#/gist/467983456ef5496f892e74d0972f56a7/f1836597cb21bd7955f6fd62412ff360ad2cafc8);
|
|
45
|
+
- ✅[`remove-useless-declarations`](https://putout.cloudcmd.io/#/gist/9045b99fbb58a53047dec060d3f143cf/d858e357b7b1e01f366943ed8887e8dc26bb37d8);
|
|
46
|
+
- ✅[`remove-useless-braces`](https://putout.cloudcmd.io/#/gist/140689014540d48d501c1fa50b3694ca/e1521db4f951c38c17a6c3af46456c47f1f3a1a8);
|
|
47
|
+
- ✅[`remove-useless-promise`](https://putout.cloudcmd.io/#/gist/d21eb87bc77b53e54c28b1ae8442a403/1b35064142068e623a564f578517c2aace55ceba);
|
|
48
|
+
- ✅[`switch-cmp-operands`](https://putout.cloudcmd.io/#/gist/cdf71331f1024c9c966d4756c6159684/9d3f2ebeb41cd096de7919f0c39bc75cbaf5ce0c);
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import {types} from 'putout';
|
|
2
|
+
|
|
3
|
+
const {isMemberExpression} = types;
|
|
4
|
+
const PREFIX = '__nirguna_';
|
|
5
|
+
|
|
6
|
+
export const report = ({name, newName}) => `Add prefix to label: '${name}' -> '${newName}'`;
|
|
7
|
+
|
|
8
|
+
export const fix = ({newName, path, ids}) => {
|
|
9
|
+
path.node.label.name = newName;
|
|
10
|
+
|
|
11
|
+
for (const {node} of ids) {
|
|
12
|
+
node.name = newName;
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export const traverse = ({push}) => ({
|
|
17
|
+
LabeledStatement(path) {
|
|
18
|
+
const {name} = path.node.label;
|
|
19
|
+
|
|
20
|
+
if (name.startsWith(PREFIX))
|
|
21
|
+
return;
|
|
22
|
+
|
|
23
|
+
const newName = `${PREFIX}${name}`;
|
|
24
|
+
const ids = getIds(path, name);
|
|
25
|
+
|
|
26
|
+
push({
|
|
27
|
+
path,
|
|
28
|
+
ids,
|
|
29
|
+
name,
|
|
30
|
+
newName,
|
|
31
|
+
});
|
|
32
|
+
},
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
function getIds(path, name) {
|
|
36
|
+
const ids = [];
|
|
37
|
+
const {path: programPath} = path.scope.getProgramParent();
|
|
38
|
+
|
|
39
|
+
programPath.traverse({
|
|
40
|
+
Identifier(path) {
|
|
41
|
+
if (isMemberExpression(path.parentPath))
|
|
42
|
+
return;
|
|
43
|
+
|
|
44
|
+
if (name === path.node.name)
|
|
45
|
+
ids.push(path);
|
|
46
|
+
},
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
return ids;
|
|
50
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export const report = () => `Use '===' and '!==' when comparing with zero`;
|
|
2
|
+
|
|
3
|
+
export const replace = () => ({
|
|
4
|
+
'if (!__identifier__a) __b': 'if (__identifier__a === 0) __b',
|
|
5
|
+
'if (__identifier__a) __b': 'if (__identifier__a !== 0) __b',
|
|
6
|
+
'if (!__identifier__a) __b; else __c': 'if (__identifier__a === 0) __b; else __c',
|
|
7
|
+
'if (__identifier__a) __b; else __c': 'if (__identifier__a !== 0) __b; else __c',
|
|
8
|
+
});
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
const readFileSyncStub = () => '';
|
|
2
|
+
|
|
3
|
+
export const report = () => `Apply 'include'`;
|
|
4
|
+
|
|
5
|
+
export const replace = ({options}) => {
|
|
6
|
+
const {
|
|
7
|
+
readFileSync = readFileSyncStub,
|
|
8
|
+
} = options;
|
|
9
|
+
|
|
10
|
+
return {
|
|
11
|
+
'include(__a)': ({__a}) => {
|
|
12
|
+
const result = readFileSync(__a.value, 'utf8');
|
|
13
|
+
|
|
14
|
+
return `include\`\n ${result}\n\``;
|
|
15
|
+
},
|
|
16
|
+
};
|
|
17
|
+
};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import {types} from 'putout';
|
|
2
|
+
|
|
3
|
+
const {isArrayExpression} = types;
|
|
4
|
+
|
|
5
|
+
function getType(arg) {
|
|
6
|
+
return arg.__nirguna_type || 'i16';
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export const report = (path) => {
|
|
10
|
+
const arg1 = path.get('left.0');
|
|
11
|
+
const arg2 = path.get('right.0');
|
|
12
|
+
const type1 = getType(arg1);
|
|
13
|
+
const type2 = getType(arg2);
|
|
14
|
+
|
|
15
|
+
if (type1 !== type2)
|
|
16
|
+
return `Types mismatch: '${arg1}:${type1} = ${arg2}:${type2}'`;
|
|
17
|
+
|
|
18
|
+
return `Use registers to address memory`;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export const match = () => ({
|
|
22
|
+
'[__a] = [__b]': ({__a, __b}) => {
|
|
23
|
+
return !isArrayExpression(__a) && !isArrayExpression(__b);
|
|
24
|
+
},
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
export const replace = () => ({
|
|
28
|
+
'[__a] = [__b]': (vars, path) => {
|
|
29
|
+
const arg1 = path.get('left.0');
|
|
30
|
+
const arg2 = path.get('right.0');
|
|
31
|
+
const type1 = getType(arg1);
|
|
32
|
+
const type2 = getType(arg2);
|
|
33
|
+
|
|
34
|
+
if (type1 !== type2)
|
|
35
|
+
return path;
|
|
36
|
+
|
|
37
|
+
const reg = type1 === 'i8' ? 'al' : 'ax';
|
|
38
|
+
|
|
39
|
+
return `{
|
|
40
|
+
mov(${reg}, [__b]);
|
|
41
|
+
mov([__a], ${reg});
|
|
42
|
+
}`;
|
|
43
|
+
},
|
|
44
|
+
});
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import {types, operator} from 'putout';
|
|
2
|
+
|
|
3
|
+
const isString = (a) => typeof a === 'string';
|
|
4
|
+
const {
|
|
5
|
+
isTSStringKeyword,
|
|
6
|
+
isExportNamedDeclaration,
|
|
7
|
+
isFunction,
|
|
8
|
+
isProgram,
|
|
9
|
+
isStringLiteral,
|
|
10
|
+
} = types;
|
|
11
|
+
|
|
12
|
+
const {extract} = operator;
|
|
13
|
+
|
|
14
|
+
const TYPES = {
|
|
15
|
+
i8: 'db',
|
|
16
|
+
i16: 'dw',
|
|
17
|
+
i32: 'dd',
|
|
18
|
+
i64: 'dq',
|
|
19
|
+
rb: 'rb',
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export const report = () => `Use 'db' instead of 'i8'`;
|
|
23
|
+
|
|
24
|
+
export const filter = (path) => {
|
|
25
|
+
if (!isProgram(path.parentPath))
|
|
26
|
+
return;
|
|
27
|
+
|
|
28
|
+
const {init} = path.node.declarations[0];
|
|
29
|
+
|
|
30
|
+
if (isFunction(init))
|
|
31
|
+
return false;
|
|
32
|
+
|
|
33
|
+
return !isExportNamedDeclaration(path.parentPath);
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export const replace = () => ({
|
|
37
|
+
'let __a = __array': (vars, path) => {
|
|
38
|
+
const values = [];
|
|
39
|
+
const elementsPath = path.get('declarations.0.init');
|
|
40
|
+
|
|
41
|
+
for (const element of elementsPath.get('elements')) {
|
|
42
|
+
if (isStringLiteral(element)) {
|
|
43
|
+
values.push(element.node.raw);
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const value = extract(element);
|
|
48
|
+
|
|
49
|
+
if (isString(value)) {
|
|
50
|
+
const escaped = value.replaceAll(`'`, `\\'`);
|
|
51
|
+
values.push(`'${escaped}'`);
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
values.push(value);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return `__a.db = ${values.join(',')}, 0`;
|
|
59
|
+
},
|
|
60
|
+
'let __a: __b = __c': convert,
|
|
61
|
+
'let __a = __c': convert,
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
function convert({__b, __c}) {
|
|
65
|
+
if (!__b && isString(__c.value))
|
|
66
|
+
return '__a.db = __c, 0';
|
|
67
|
+
|
|
68
|
+
if (!__b)
|
|
69
|
+
return '__a.db = __c';
|
|
70
|
+
|
|
71
|
+
if (isTSStringKeyword(__b))
|
|
72
|
+
return '__a.db = __c, 0';
|
|
73
|
+
|
|
74
|
+
const {name} = __b.typeName;
|
|
75
|
+
const type = TYPES[name];
|
|
76
|
+
|
|
77
|
+
return `__a.${type} = __c`;
|
|
78
|
+
}
|
|
79
|
+
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import {
|
|
2
|
+
template,
|
|
3
|
+
types,
|
|
4
|
+
operator,
|
|
5
|
+
} from 'putout';
|
|
6
|
+
|
|
7
|
+
const {
|
|
8
|
+
replaceWithMultiple,
|
|
9
|
+
rename,
|
|
10
|
+
traverse,
|
|
11
|
+
compare,
|
|
12
|
+
} = operator;
|
|
13
|
+
|
|
14
|
+
const {
|
|
15
|
+
expressionStatement,
|
|
16
|
+
isReturnStatement,
|
|
17
|
+
isLabeledStatement,
|
|
18
|
+
blockStatement,
|
|
19
|
+
} = types;
|
|
20
|
+
|
|
21
|
+
const isEax = (name) => /[re]?a[xl]/.test(name);
|
|
22
|
+
|
|
23
|
+
const createExpression = (a) => {
|
|
24
|
+
return expressionStatement(template.ast(a));
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export const report = () => `Use 'regs' instead of 'args'`;
|
|
28
|
+
|
|
29
|
+
export const match = () => ({
|
|
30
|
+
'async function __a(__args) {__body}': ({__args}, path) => {
|
|
31
|
+
const {returnType} = path.node;
|
|
32
|
+
|
|
33
|
+
if (returnType && returnType.typeAnnotation.typeName.name === 'ureg')
|
|
34
|
+
return false;
|
|
35
|
+
|
|
36
|
+
return __args.length;
|
|
37
|
+
},
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
export const replace = () => ({
|
|
41
|
+
'async function __a(__args) {__body}': ({__body, __args}, path) => {
|
|
42
|
+
const bytes = getBytes(path);
|
|
43
|
+
const startCount = 2;
|
|
44
|
+
|
|
45
|
+
const ebp = getRegister(path, 'ebp');
|
|
46
|
+
const esp = getRegister(path, 'esp');
|
|
47
|
+
|
|
48
|
+
__body.body.unshift(...[
|
|
49
|
+
createExpression(`push(${ebp})`),
|
|
50
|
+
createExpression(`mov(${ebp}, ${esp})`),
|
|
51
|
+
]);
|
|
52
|
+
|
|
53
|
+
insertReturnAtEnd(ebp, __body);
|
|
54
|
+
|
|
55
|
+
const params = path.get('params');
|
|
56
|
+
|
|
57
|
+
for (const [i, param] of params.entries()) {
|
|
58
|
+
const arg = param.node;
|
|
59
|
+
const {name} = getType(arg);
|
|
60
|
+
|
|
61
|
+
rename(path, arg.name, `[${ebp} + ${bytes * (i + startCount)}]`);
|
|
62
|
+
param.__nirguna_type = name;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const argsSize = bytes * __args.length;
|
|
66
|
+
|
|
67
|
+
path.__nirguna_args_size = argsSize;
|
|
68
|
+
path.node.params = [];
|
|
69
|
+
|
|
70
|
+
const replaceReturn = createReplaceReturn(path, argsSize);
|
|
71
|
+
|
|
72
|
+
traverse(path, {
|
|
73
|
+
'ReturnStatement': replaceReturn,
|
|
74
|
+
'ret()': replaceReturn,
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
delete path.node.returnType;
|
|
78
|
+
|
|
79
|
+
return path;
|
|
80
|
+
},
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
const REG = {
|
|
84
|
+
i16: {
|
|
85
|
+
eax: 'ax',
|
|
86
|
+
ebp: 'bp',
|
|
87
|
+
esp: 'sp',
|
|
88
|
+
},
|
|
89
|
+
i32: {
|
|
90
|
+
eax: 'eax',
|
|
91
|
+
ebp: 'ebp',
|
|
92
|
+
esp: 'esp',
|
|
93
|
+
},
|
|
94
|
+
i64: {
|
|
95
|
+
eax: 'rax',
|
|
96
|
+
ebp: 'rbp',
|
|
97
|
+
esp: 'rsp',
|
|
98
|
+
},
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
const BYTES = {
|
|
102
|
+
i16: 2,
|
|
103
|
+
i32: 4,
|
|
104
|
+
i64: 8,
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
function getBytes(path) {
|
|
108
|
+
const {returnType} = path.node;
|
|
109
|
+
|
|
110
|
+
if (!returnType)
|
|
111
|
+
return 2;
|
|
112
|
+
|
|
113
|
+
const {name} = path.node.returnType.typeAnnotation.typeName;
|
|
114
|
+
|
|
115
|
+
return BYTES[name];
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function getRegister(path, reg) {
|
|
119
|
+
const {returnType} = path.node;
|
|
120
|
+
|
|
121
|
+
if (!returnType)
|
|
122
|
+
return REG.i16[reg];
|
|
123
|
+
|
|
124
|
+
const {name} = path.node.returnType.typeAnnotation.typeName;
|
|
125
|
+
|
|
126
|
+
return REG[name][reg];
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function getType({typeAnnotation}) {
|
|
130
|
+
if (!typeAnnotation)
|
|
131
|
+
return 'i16';
|
|
132
|
+
|
|
133
|
+
return typeAnnotation.typeAnnotation.typeName.name;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const createReplaceReturn = (fnPath, argsSize) => (path) => {
|
|
137
|
+
const statements = [
|
|
138
|
+
expressionStatement(template.ast(`pop(${getRegister(fnPath, 'ebp')})`)),
|
|
139
|
+
expressionStatement(template.ast(`ret(${argsSize})`)),
|
|
140
|
+
];
|
|
141
|
+
|
|
142
|
+
const argPath = path.get('argument');
|
|
143
|
+
const arg = argPath.node;
|
|
144
|
+
|
|
145
|
+
if (arg && !isEax(arg.name)) {
|
|
146
|
+
const expression = template.ast(`${getRegister(fnPath, 'eax')} = ${argPath}`);
|
|
147
|
+
statements.unshift(expressionStatement(expression));
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
if (path.parentPath.isLabeledStatement()) {
|
|
151
|
+
path.parentPath.node.body = blockStatement(statements);
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
replaceWithMultiple(path, statements);
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
function insertReturnAtEnd(ebp, __body) {
|
|
159
|
+
const last = __body.body.at(-1);
|
|
160
|
+
|
|
161
|
+
if (isReturnStatement(last) || isLabeledStatement(last))
|
|
162
|
+
return;
|
|
163
|
+
|
|
164
|
+
const popEBP = createExpression(`pop(${ebp})`);
|
|
165
|
+
|
|
166
|
+
if (compare(last, 'ret()'))
|
|
167
|
+
__body.body.splice(-1, 0, popEBP);
|
|
168
|
+
else
|
|
169
|
+
__body.body.push(popEBP);
|
|
170
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import {types, operator} from 'putout';
|
|
2
|
+
import {isRegister} from '@nirguna/operator-fasm/regs';
|
|
3
|
+
|
|
4
|
+
const {traverse} = operator;
|
|
5
|
+
|
|
6
|
+
const {
|
|
7
|
+
isMemberExpression,
|
|
8
|
+
isCallExpression,
|
|
9
|
+
isArrayExpression,
|
|
10
|
+
isBinaryExpression,
|
|
11
|
+
} = types;
|
|
12
|
+
|
|
13
|
+
export const report = (path) => {
|
|
14
|
+
return `Use 'mov()' instead of '=' in '${path}'`;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export const match = () => ({
|
|
18
|
+
'__a = __b': ({__a, __b}) => {
|
|
19
|
+
if (isArrayExpression(__a) && isArrayExpression(__b))
|
|
20
|
+
return false;
|
|
21
|
+
|
|
22
|
+
if (isMemberExpression(__a))
|
|
23
|
+
return false;
|
|
24
|
+
|
|
25
|
+
if (isMemberExpression(__b))
|
|
26
|
+
return false;
|
|
27
|
+
|
|
28
|
+
if (isBinaryExpression(__b)) {
|
|
29
|
+
let is = false;
|
|
30
|
+
|
|
31
|
+
traverse(__b, {
|
|
32
|
+
Identifier: (path) => {
|
|
33
|
+
const {name} = path.node;
|
|
34
|
+
|
|
35
|
+
if (isRegister(name)) {
|
|
36
|
+
is = true;
|
|
37
|
+
path.stop();
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
if (is)
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return !isCallExpression(__b);
|
|
47
|
+
},
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
export const replace = () => ({
|
|
51
|
+
'__a = __b': 'mov(__a, __b)',
|
|
52
|
+
});
|
|
53
|
+
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import {
|
|
2
|
+
template,
|
|
3
|
+
operator,
|
|
4
|
+
types,
|
|
5
|
+
} from 'putout';
|
|
6
|
+
|
|
7
|
+
const {insertBefore} = operator;
|
|
8
|
+
const {
|
|
9
|
+
expressionStatement,
|
|
10
|
+
isObjectExpression,
|
|
11
|
+
isExpressionStatement,
|
|
12
|
+
} = types;
|
|
13
|
+
|
|
14
|
+
export const report = () => `Use 'call()' operations instead of 'await'`;
|
|
15
|
+
|
|
16
|
+
const createMov = template('mov(__key, __value)', {
|
|
17
|
+
placeholderPattern: /__[a-z]/,
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
export const filter = (path) => {
|
|
21
|
+
return isExpressionStatement(path.parentPath);
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export const replace = () => ({
|
|
25
|
+
'await __a(__b, __c)': `{
|
|
26
|
+
push(__b);
|
|
27
|
+
push(__c);
|
|
28
|
+
call(__a);
|
|
29
|
+
}`,
|
|
30
|
+
'await __a()': 'call(__a)',
|
|
31
|
+
'await __a(__b)': ({__b}, path) => {
|
|
32
|
+
if (!isObjectExpression(__b))
|
|
33
|
+
return `{
|
|
34
|
+
push(__b);
|
|
35
|
+
call(__a);
|
|
36
|
+
}`;
|
|
37
|
+
|
|
38
|
+
for (const {key, value} of __b.properties) {
|
|
39
|
+
const mov = expressionStatement(createMov({
|
|
40
|
+
__key: key,
|
|
41
|
+
__value: value,
|
|
42
|
+
}));
|
|
43
|
+
|
|
44
|
+
insertBefore(path, mov);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const {argument} = path.node;
|
|
48
|
+
|
|
49
|
+
argument.arguments = [];
|
|
50
|
+
|
|
51
|
+
return 'call(__a)';
|
|
52
|
+
},
|
|
53
|
+
});
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import {operator, types} from 'putout';
|
|
2
|
+
|
|
3
|
+
const {isArrayExpression} = types;
|
|
4
|
+
const {extract} = operator;
|
|
5
|
+
|
|
6
|
+
export const report = () => `Use '0x10' instead of 'bios.printLine()'`;
|
|
7
|
+
|
|
8
|
+
export const replace = () => ({
|
|
9
|
+
'bios.printLine()': `{
|
|
10
|
+
ax = 0x1301;
|
|
11
|
+
int(0x10);
|
|
12
|
+
}`,
|
|
13
|
+
'bios.printLine(__a, __object)': ({__object}) => {
|
|
14
|
+
const {
|
|
15
|
+
page = 0,
|
|
16
|
+
color = 0,
|
|
17
|
+
count = 0,
|
|
18
|
+
line = 0,
|
|
19
|
+
column = 0,
|
|
20
|
+
} = parseArgs(__object.properties);
|
|
21
|
+
|
|
22
|
+
return `{
|
|
23
|
+
push(bp);
|
|
24
|
+
bh = ${page};
|
|
25
|
+
bl = ${color};
|
|
26
|
+
cx = ${count};
|
|
27
|
+
dh = ${line};
|
|
28
|
+
dl = ${column};
|
|
29
|
+
bp = __a;
|
|
30
|
+
ax = 0x1301;
|
|
31
|
+
int(0x10);
|
|
32
|
+
pop(bp);
|
|
33
|
+
}`;
|
|
34
|
+
},
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
function parseArgs(properties) {
|
|
38
|
+
const result = {};
|
|
39
|
+
|
|
40
|
+
for (const {key, value} of properties) {
|
|
41
|
+
const extracted = extract(value);
|
|
42
|
+
|
|
43
|
+
if (isArrayExpression(value)) {
|
|
44
|
+
result[key.name] = `[${extracted}]`;
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
result[key.name] = extracted;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return result;
|
|
52
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export const report = () => `Use '0x16' instead of 'bios.readChar()'`;
|
|
2
|
+
|
|
3
|
+
export const match = () => ({
|
|
4
|
+
'bios.readChar()': (vars, path) => {
|
|
5
|
+
return path.parentPath.isExpressionStatement();
|
|
6
|
+
},
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
export const replace = () => ({
|
|
10
|
+
'ax = bios.readChar()': `{
|
|
11
|
+
ax = 0;
|
|
12
|
+
int(0x16)
|
|
13
|
+
}`,
|
|
14
|
+
'bios.readChar()': `{
|
|
15
|
+
ax = 0;
|
|
16
|
+
int(0x16)
|
|
17
|
+
}`,
|
|
18
|
+
});
|