Skip to content

Commit c8243a4

Browse files
committed
implement bit shift node
1 parent 1f63a36 commit c8243a4

2 files changed

Lines changed: 106 additions & 0 deletions

File tree

src/node/shift.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { Node } from './base';
2+
3+
/**
4+
* This node consumes and stores an integer into a specified
5+
* `field` from the input before forwarding execution.
6+
*/
7+
export class Shift extends Node {
8+
/**
9+
* @param field State's property name
10+
* @param bits number of bits to shift it can be between 1 and 8
11+
* @param lshift if true, bits are shifted to the left.
12+
* otherwise, it goes in the opposite direction.
13+
*/
14+
constructor (public readonly field: string, public readonly bits:number, public readonly lshift: boolean){
15+
const name = (lshift) ? "lshift" : "rshift";
16+
const operation = (bits > 1) ? `_${bits * 8}`: "";
17+
super(`${name}_${field}${operation}`);
18+
if (/^_/.test(field)) {
19+
throw new Error(`Can't use internal field in \`.${name}()\`: "${field}"`);
20+
}
21+
if (bits < 1 || bits > 8){
22+
throw new Error(`bits must be a number between 1 to 8`);
23+
}
24+
}
25+
/** `.otherwise()` is not supported on this type of node as it consumes a bit.
26+
* enabling this defeats the purpose.
27+
*/
28+
public otherwise(): this { throw new Error('Not supported'); }
29+
}

src/shift-checker.ts

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
import { debuglog } from 'node:util';
2+
3+
import { Property } from './property';
4+
import { Node, Shift } from './node';
5+
import { Reachability } from './reachability';
6+
7+
8+
const debug = debuglog('llparse-builder:shift-checker');
9+
10+
/**
11+
* Validates shift nodes to find invalid or missing properties or bit sizes
12+
*/
13+
export class ShiftChecker {
14+
public readonly property_table = new Map<string, Property>();
15+
constructor (properties: readonly Property[]){
16+
properties.forEach((prop) => {this.property_table.set(prop.name, prop)});
17+
}
18+
19+
/**
20+
* validates a single shift node to see if a property exists
21+
* to be fed bits to. It also has the ability of checking if numbers
22+
* may overflow.
23+
*
24+
* @param shift the shift node to check.
25+
*/
26+
private validate_shift(shift: Shift): void{
27+
const property = this.property_table.get(shift.field);
28+
if (!property){
29+
throw new Error(`"${shift.field}" has not been defined for ${shift.name}`);
30+
}
31+
let size;
32+
switch (property.ty){
33+
case 'ptr':
34+
throw new Error(
35+
`${shift.field} cannot be provided to "${shift.name}" because field was defined as a "ptr"`
36+
);
37+
case 'i8':
38+
size = 1;
39+
break;
40+
case 'i16':
41+
size = 2;
42+
break;
43+
case 'i32':
44+
size = 4;
45+
break;
46+
case 'i64':
47+
size = 8;
48+
break;
49+
default:
50+
/* TODO (Vizonex): ensure this is unreachable. */
51+
/* UNREACHABLE */
52+
size = 0;
53+
}
54+
// Ensure bits can't overflow...
55+
if (shift.bits > size){
56+
throw new Error(`${shift.bits} > ${size} and will cause node "${shift.field}" to overflow.`)
57+
}
58+
}
59+
60+
/**
61+
* Run shift checker pass on a graph starting from `root`.
62+
*
63+
* @param root Graph root node
64+
*/
65+
public check(root: Node): void {
66+
const r = new Reachability();
67+
const nodes = r.build(root);
68+
69+
for (const node of nodes){
70+
if (node instanceof Shift){
71+
debug('checking %j', node.name);
72+
this.validate_shift(node);
73+
}
74+
}
75+
}
76+
}
77+

0 commit comments

Comments
 (0)