Skip to content

Commit 7065336

Browse files
committed
Add bitshift, arithmetic shift, and invert operators
1 parent c26146b commit 7065336

23 files changed

Lines changed: 814 additions & 619 deletions

File tree

packages/cashc/src/Errors.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,15 @@ export class IndexOutOfBoundsError extends CashScriptError {
273273
}
274274
}
275275

276+
export class BitshiftBitcountNegativeError extends CashScriptError {
277+
constructor(
278+
node: BinaryOpNode,
279+
bitcount: number,
280+
) {
281+
super(node, `Bitshift bitcount cannot be negative: ${bitcount}`);
282+
}
283+
}
284+
276285
export class VersionError extends Error {
277286
constructor(
278287
actual: string,

packages/cashc/src/ast/Operator.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ export enum NullaryOperator {
1010
export enum UnaryOperator {
1111
NOT = '!',
1212
NEGATE = '-',
13+
INVERT = '~',
1314
SIZE = '.length',
1415
REVERSE = '.reverse()',
1516
INPUT_VALUE = 'tx.inputs[i].value',
@@ -34,15 +35,17 @@ export enum BinaryOperator {
3435
MOD = '%',
3536
PLUS = '+',
3637
MINUS = '-',
38+
SHIFT_LEFT = '<<',
39+
SHIFT_RIGHT = '>>',
3740
LT = '<',
41+
BIT_AND = '&',
42+
BIT_XOR = '^',
43+
BIT_OR = '|',
3844
LE = '<=',
3945
GT = '>',
4046
GE = '>=',
4147
EQ = '==',
4248
NE = '!=',
43-
BIT_AND = '&',
44-
BIT_XOR = '^',
45-
BIT_OR = '|',
4649
AND = '&&',
4750
OR = '||',
4851
SPLIT = '.split',

packages/cashc/src/generation/GenerateTargetTraversal.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import {
77
Op,
88
OpOrData,
99
PrimitiveType,
10-
resultingType,
1110
Script,
1211
scriptToAsm,
1312
generateSourceMap,
@@ -60,6 +59,7 @@ import {
6059
compileTimeOp,
6160
compileUnaryOp,
6261
} from './utils.js';
62+
import { resultingTypeForBinaryOp } from '../utils.js';
6363

6464
export default class GenerateTargetTraversalWithLocation extends AstTraversal {
6565
private locationData: FullLocationData = []; // detailed location data needed for sourcemap creation
@@ -582,7 +582,7 @@ export default class GenerateTargetTraversalWithLocation extends AstTraversal {
582582
visitBinaryOp(node: BinaryOpNode): Node {
583583
node.left = this.visit(node.left);
584584
node.right = this.visit(node.right);
585-
const isNumeric = resultingType(node.left.type, node.right.type) === PrimitiveType.INT;
585+
const isNumeric = resultingTypeForBinaryOp(node.operator, node.left.type!, node.right.type!) === PrimitiveType.INT;
586586
this.emit(compileBinaryOp(node.operator, isNumeric), { location: node.location, positionHint: PositionHint.END });
587587
this.popFromStack(2);
588588
this.pushToStack('(value)');

packages/cashc/src/generation/utils.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,11 @@ export function compileBinaryOp(op: BinaryOperator, numeric: boolean = false): S
5656
[BinaryOperator.MOD]: [Op.OP_MOD],
5757
[BinaryOperator.PLUS]: [Op.OP_CAT],
5858
[BinaryOperator.MINUS]: [Op.OP_SUB],
59+
[BinaryOperator.SHIFT_LEFT]: [Op.OP_LSHIFTBIN],
60+
[BinaryOperator.SHIFT_RIGHT]: [Op.OP_RSHIFTBIN],
61+
[BinaryOperator.BIT_AND]: [Op.OP_AND],
62+
[BinaryOperator.BIT_OR]: [Op.OP_OR],
63+
[BinaryOperator.BIT_XOR]: [Op.OP_XOR],
5964
[BinaryOperator.LT]: [Op.OP_LESSTHAN],
6065
[BinaryOperator.LE]: [Op.OP_LESSTHANOREQUAL],
6166
[BinaryOperator.GT]: [Op.OP_GREATERTHAN],
@@ -64,16 +69,15 @@ export function compileBinaryOp(op: BinaryOperator, numeric: boolean = false): S
6469
[BinaryOperator.NE]: [Op.OP_EQUAL, Op.OP_NOT],
6570
[BinaryOperator.AND]: [Op.OP_BOOLAND],
6671
[BinaryOperator.OR]: [Op.OP_BOOLOR],
67-
[BinaryOperator.BIT_AND]: [Op.OP_AND],
68-
[BinaryOperator.BIT_OR]: [Op.OP_OR],
69-
[BinaryOperator.BIT_XOR]: [Op.OP_XOR],
7072
[BinaryOperator.SPLIT]: [Op.OP_SPLIT],
7173
};
7274

7375
if (numeric) {
7476
mapping[BinaryOperator.PLUS] = [Op.OP_ADD];
7577
mapping[BinaryOperator.EQ] = [Op.OP_NUMEQUAL];
7678
mapping[BinaryOperator.NE] = [Op.OP_NUMNOTEQUAL];
79+
mapping[BinaryOperator.SHIFT_LEFT] = [Op.OP_LSHIFTNUM];
80+
mapping[BinaryOperator.SHIFT_RIGHT] = [Op.OP_RSHIFTNUM];
7781
}
7882

7983
return mapping[op];
@@ -83,6 +87,7 @@ export function compileUnaryOp(op: UnaryOperator): Op[] {
8387
const mapping = {
8488
[UnaryOperator.NOT]: [Op.OP_NOT],
8589
[UnaryOperator.NEGATE]: [Op.OP_NEGATE],
90+
[UnaryOperator.INVERT]: [Op.OP_INVERT],
8691
[UnaryOperator.SIZE]: [Op.OP_SIZE, Op.OP_NIP],
8792
[UnaryOperator.REVERSE]: [Op.OP_REVERSEBYTES],
8893
[UnaryOperator.INPUT_VALUE]: [Op.OP_UTXOVALUE],

packages/cashc/src/grammar/CashScript.g4

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -124,10 +124,10 @@ expression
124124
| expression op=('.reverse()' | '.length') # UnaryOp
125125
| left=expression op='.split' '(' right=expression ')' # BinaryOp
126126
| element=expression '.slice' '(' start=expression ',' end=expression ')' # Slice
127-
| op=('!' | '-') expression # UnaryOp
127+
| op=('!' | '-' | '~') expression # UnaryOp
128128
| left=expression op=('*' | '/' | '%') right=expression # BinaryOp
129129
| left=expression op=('+' | '-') right=expression # BinaryOp
130-
// | expression ('>>' | '<<') expression --- OP_LSHIFT & RSHIFT are disabled in BCH Script
130+
| left=expression op=('>>' | '<<') right=expression # BinaryOp
131131
| left=expression op=('<' | '<=' | '>' | '>=') right=expression # BinaryOp
132132
| left=expression op=('==' | '!=') right=expression # BinaryOp
133133
| left=expression op='&' right=expression # BinaryOp

packages/cashc/src/grammar/CashScript.interp

Lines changed: 5 additions & 1 deletion
Large diffs are not rendered by default.

packages/cashc/src/grammar/CashScript.tokens

Lines changed: 34 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -58,23 +58,25 @@ T__56=57
5858
T__57=58
5959
T__58=59
6060
T__59=60
61-
VersionLiteral=61
62-
BooleanLiteral=62
63-
NumberUnit=63
64-
NumberLiteral=64
65-
NumberPart=65
66-
ExponentPart=66
67-
Bytes=67
68-
Bound=68
69-
StringLiteral=69
70-
DateLiteral=70
71-
HexLiteral=71
72-
TxVar=72
73-
NullaryOp=73
74-
Identifier=74
75-
WHITESPACE=75
76-
COMMENT=76
77-
LINE_COMMENT=77
61+
T__60=61
62+
T__61=62
63+
VersionLiteral=63
64+
BooleanLiteral=64
65+
NumberUnit=65
66+
NumberLiteral=66
67+
NumberPart=67
68+
ExponentPart=68
69+
Bytes=69
70+
Bound=70
71+
StringLiteral=71
72+
DateLiteral=72
73+
HexLiteral=73
74+
TxVar=74
75+
NullaryOp=75
76+
Identifier=76
77+
WHITESPACE=77
78+
COMMENT=78
79+
LINE_COMMENT=79
7880
'pragma'=1
7981
';'=2
8082
'cashscript'=3
@@ -122,16 +124,18 @@ LINE_COMMENT=77
122124
'/'=45
123125
'%'=46
124126
'+'=47
125-
'=='=48
126-
'!='=49
127-
'&'=50
128-
'|'=51
129-
'&&'=52
130-
'||'=53
131-
'constant'=54
132-
'int'=55
133-
'bool'=56
134-
'string'=57
135-
'pubkey'=58
136-
'sig'=59
137-
'datasig'=60
127+
'>>'=48
128+
'<<'=49
129+
'=='=50
130+
'!='=51
131+
'&'=52
132+
'|'=53
133+
'&&'=54
134+
'||'=55
135+
'constant'=56
136+
'int'=57
137+
'bool'=58
138+
'string'=59
139+
'pubkey'=60
140+
'sig'=61
141+
'datasig'=62

packages/cashc/src/grammar/CashScriptLexer.interp

Lines changed: 7 additions & 1 deletion
Large diffs are not rendered by default.

packages/cashc/src/grammar/CashScriptLexer.tokens

Lines changed: 34 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -58,23 +58,25 @@ T__56=57
5858
T__57=58
5959
T__58=59
6060
T__59=60
61-
VersionLiteral=61
62-
BooleanLiteral=62
63-
NumberUnit=63
64-
NumberLiteral=64
65-
NumberPart=65
66-
ExponentPart=66
67-
Bytes=67
68-
Bound=68
69-
StringLiteral=69
70-
DateLiteral=70
71-
HexLiteral=71
72-
TxVar=72
73-
NullaryOp=73
74-
Identifier=74
75-
WHITESPACE=75
76-
COMMENT=76
77-
LINE_COMMENT=77
61+
T__60=61
62+
T__61=62
63+
VersionLiteral=63
64+
BooleanLiteral=64
65+
NumberUnit=65
66+
NumberLiteral=66
67+
NumberPart=67
68+
ExponentPart=68
69+
Bytes=69
70+
Bound=70
71+
StringLiteral=71
72+
DateLiteral=72
73+
HexLiteral=73
74+
TxVar=74
75+
NullaryOp=75
76+
Identifier=76
77+
WHITESPACE=77
78+
COMMENT=78
79+
LINE_COMMENT=79
7880
'pragma'=1
7981
';'=2
8082
'cashscript'=3
@@ -122,16 +124,18 @@ LINE_COMMENT=77
122124
'/'=45
123125
'%'=46
124126
'+'=47
125-
'=='=48
126-
'!='=49
127-
'&'=50
128-
'|'=51
129-
'&&'=52
130-
'||'=53
131-
'constant'=54
132-
'int'=55
133-
'bool'=56
134-
'string'=57
135-
'pubkey'=58
136-
'sig'=59
137-
'datasig'=60
127+
'>>'=48
128+
'<<'=49
129+
'=='=50
130+
'!='=51
131+
'&'=52
132+
'|'=53
133+
'&&'=54
134+
'||'=55
135+
'constant'=56
136+
'int'=57
137+
'bool'=58
138+
'string'=59
139+
'pubkey'=60
140+
'sig'=61
141+
'datasig'=62

0 commit comments

Comments
 (0)