@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.
Files changed (49) hide show
  1. package/README.md +48 -0
  2. package/lib/add-label-prefix/index.js +50 -0
  3. package/lib/apply-equality/index.js +8 -0
  4. package/lib/apply-inc/index.js +8 -0
  5. package/lib/apply-include/index.js +17 -0
  6. package/lib/apply-registers/index.js +44 -0
  7. package/lib/apply-types/index.js +79 -0
  8. package/lib/convert-args-to-regs/index.js +170 -0
  9. package/lib/convert-assign-to-add/index.js +5 -0
  10. package/lib/convert-assign-to-and/index.js +5 -0
  11. package/lib/convert-assign-to-member/index.js +5 -0
  12. package/lib/convert-assign-to-mov/index.js +53 -0
  13. package/lib/convert-assign-to-or/index.js +5 -0
  14. package/lib/convert-assign-to-shl/index.js +5 -0
  15. package/lib/convert-assign-to-sub/index.js +5 -0
  16. package/lib/convert-assign-to-xor/index.js +5 -0
  17. package/lib/convert-await-to-call/index.js +53 -0
  18. package/lib/convert-bios-clear-screen-to-int-10/index.js +8 -0
  19. package/lib/convert-bios-print-line-to-int-10/index.js +52 -0
  20. package/lib/convert-bios-read-char-to-int-16/index.js +18 -0
  21. package/lib/convert-bios-read-sector-to-int-13/index.js +80 -0
  22. package/lib/convert-bios-reboot-to-jmp-far/index.js +5 -0
  23. package/lib/convert-bios-scroll-to-int-10/index.js +16 -0
  24. package/lib/convert-const-to-equ/index.js +15 -0
  25. package/lib/convert-dec-to-hex/index.js +19 -0
  26. package/lib/convert-declaration-to-mov/index.js +23 -0
  27. package/lib/convert-do-while-to-jnz/index.js +155 -0
  28. package/lib/convert-equ-call-to-member/index.js +30 -0
  29. package/lib/convert-function-to-label/index.js +114 -0
  30. package/lib/convert-if-to-jmp/index.js +166 -0
  31. package/lib/convert-if-to-jmp/operator.js +27 -0
  32. package/lib/convert-linux-exit-to-syscall/index.js +15 -0
  33. package/lib/convert-linux-write-to-syscall/index.js +48 -0
  34. package/lib/convert-mov-to-add/index.js +5 -0
  35. package/lib/convert-return-to-eax/index.js +76 -0
  36. package/lib/convert-strncmp-to-repe-cmpsb/index.js +23 -0
  37. package/lib/convert-ternary-to-if/index.js +5 -0
  38. package/lib/convert-ureg-to-reg/index.js +108 -0
  39. package/lib/convert-while-to-jz/index.js +158 -0
  40. package/lib/extract-labeled-block/index.js +68 -0
  41. package/lib/index.js +93 -0
  42. package/lib/remove-useless-braces/index.js +5 -0
  43. package/lib/remove-useless-declarations/index.js +7 -0
  44. package/lib/remove-useless-promise/index.js +5 -0
  45. package/lib/split-assign-await-with-assign-eax/index.js +41 -0
  46. package/lib/split-binary-expression/index.js +31 -0
  47. package/lib/split-stack-operations/index.js +50 -0
  48. package/lib/switch-cmp-operands/index.js +19 -0
  49. 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,8 @@
1
+ export const report = () => `Apply increment/decrement`;
2
+
3
+ export const replace = () => ({
4
+ '[++__a]': 'inc([__a])',
5
+ '++__a': 'inc(__a)',
6
+ '[--__a]': 'dec([__a])',
7
+ '--__a': 'dec(__a)',
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,5 @@
1
+ export const report = () => `Use 'add(__a, __b)' instead of '__a += __b'`;
2
+
3
+ export const replace = () => ({
4
+ '__a += __b': 'add(__a, __b);',
5
+ });
@@ -0,0 +1,5 @@
1
+ export const report = () => `Use 'and(__a, __b)' instead of '__a &= __b'`;
2
+
3
+ export const replace = () => ({
4
+ '__a &= __b': 'and(__a, __b);',
5
+ });
@@ -0,0 +1,5 @@
1
+ export const report = () => `Use 'Member Expression' instead of 'Assignment Expression'`;
2
+
3
+ export const replace = () => ({
4
+ '__a.__b = __c': '__a.__b[__c]',
5
+ });
@@ -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,5 @@
1
+ export const report = () => `Use 'or' instead of 'assign'`;
2
+
3
+ export const replace = () => ({
4
+ '__a |= __b': 'or(__a, __b)',
5
+ });
@@ -0,0 +1,5 @@
1
+ export const report = () => `Use 'shl()' instead of 'assign'`;
2
+
3
+ export const replace = () => ({
4
+ '__a <<= __b': 'shl(__a, __b)',
5
+ });
@@ -0,0 +1,5 @@
1
+ export const report = () => `Use 'sub' instead of 'assign'`;
2
+
3
+ export const replace = () => ({
4
+ '__a -= __b': 'sub(__a, __b)',
5
+ });
@@ -0,0 +1,5 @@
1
+ export const report = () => `Use 'xor()' instead of 'assign'`;
2
+
3
+ export const replace = () => ({
4
+ '__a ^= __a': 'xor(__a, __a)',
5
+ });
@@ -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,8 @@
1
+ export const report = () => `Use '0x10' instead of 'bios.clearScreen()'`;
2
+
3
+ export const replace = () => ({
4
+ 'bios.clearScreen()': `{
5
+ ax = 3;
6
+ int(0x10);
7
+ }`,
8
+ });
@@ -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
+ });