qasm-ts 2.1.1 → 2.1.3

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.
@@ -1,659 +0,0 @@
1
- "use strict";
2
- /**
3
- * OpenQASM 2.0 Parser Implementation
4
- *
5
- * This module implements a parser for OpenQASM 2.0 that focuses on the core
6
- * quantum circuit description language without the advanced features of version 3.0.
7
- * The parser handles quantum and classical register declarations, gate definitions
8
- * and applications, measurements, and basic control structures.
9
- *
10
- * OpenQASM 2.0 parsing capabilities:
11
- * - **Register declarations**: qreg and creg with size specifications
12
- * - **Gate definitions**: Custom gate definitions with parameters and bodies
13
- * - **Gate applications**: Built-in and custom gate applications
14
- * - **Measurements**: Quantum measurements with classical result storage
15
- * - **Basic conditionals**: Simple if statements based on classical register values
16
- * - **Arithmetic expressions**: Parameter expressions for gate operations
17
- * - **Opaque gates**: External gate declarations
18
- *
19
- * The parser maintains a list of known gates and validates gate applications
20
- * against declared gates and built-in operations.
21
- *
22
- * @module
23
- *
24
- * @example Parsing OpenQASM 2.0 code
25
- * ```typescript
26
- * const tokens = lexer.lex();
27
- * const parser = new Parser(tokens);
28
- * const ast = parser.parse();
29
- *
30
- * // AST contains simplified node structure for OpenQASM 2.0
31
- * ```
32
- */
33
- Object.defineProperty(exports, "__esModule", { value: true });
34
- var token_1 = require("./token");
35
- var version_1 = require("../version");
36
- var errors_1 = require("../errors");
37
- var ast_1 = require("./ast");
38
- /**
39
- * OpenQASM 2.0 Parser
40
- *
41
- * A straightforward recursive descent parser for OpenQASM 2.0 that produces
42
- * a simplified AST structure appropriate for the more limited feature set
43
- * of the 2.0 language specification.
44
- *
45
- * @example Basic parsing workflow
46
- * ```typescript
47
- * const parser = new Parser(tokens);
48
- * const ast = parser.parse();
49
- *
50
- * // Process the resulting AST nodes
51
- * ast.forEach(node => {
52
- * if (node instanceof QReg) {
53
- * console.log(`Quantum register: ${node.id}[${node.size}]`);
54
- * }
55
- * });
56
- * ```
57
- */
58
- var Parser = /** @class */ (function () {
59
- /**
60
- * Creates a parser.
61
- * @param tokens - Tokens to parse.
62
- */
63
- function Parser(tokens) {
64
- this.tokens = tokens;
65
- this.gates = [
66
- "x",
67
- "y",
68
- "z",
69
- "u1",
70
- "u2",
71
- "u3",
72
- "s",
73
- "sdg",
74
- "h",
75
- "tdg",
76
- "cx",
77
- "cy",
78
- "cz",
79
- "t",
80
- "ccx",
81
- "reset",
82
- "cu1",
83
- "ccy",
84
- "ccz",
85
- ];
86
- }
87
- /**
88
- * Calling this method parses the code represented by the provided tokens.
89
- * @return The abstract syntax tree.
90
- */
91
- Parser.prototype.parse = function () {
92
- var ast = [];
93
- var i = 0;
94
- while (i < this.tokens.length - 1) {
95
- var nodes = this.parseNode(this.tokens.slice(i));
96
- ast = ast.concat(nodes ? nodes : []);
97
- while (!this.matchNext(this.tokens.slice(i), [token_1.Token.Semicolon])) {
98
- if (this.matchNext(this.tokens.slice(i), [token_1.Token.LCParen])) {
99
- while (!this.matchNext(this.tokens.slice(i), [token_1.Token.RCParen])) {
100
- i++;
101
- }
102
- break;
103
- }
104
- i++;
105
- }
106
- i++;
107
- }
108
- return ast;
109
- };
110
- /**
111
- * Delegates the parsing of the next set of tokens to the appropriate method.
112
- * @param tokens - Remaining tokens to parse.
113
- * @param allowVariables - Whether encountered identifiers should be consider
114
- variable initializations or references.
115
- * @return A set of AST nodes.
116
- */
117
- Parser.prototype.parseNode = function (tokens, allowVariables) {
118
- if (allowVariables === void 0) { allowVariables = false; }
119
- var token = tokens[0];
120
- switch (token[0]) {
121
- case token_1.Token.Include:
122
- return [this.include(tokens.slice(1))];
123
- case token_1.Token.OpenQASM:
124
- return [this.versionHeader(tokens.slice(1))];
125
- case token_1.Token.QReg:
126
- return [this.qreg(tokens.slice(1))];
127
- case token_1.Token.CReg:
128
- return [this.creg(tokens.slice(1))];
129
- case token_1.Token.Barrier:
130
- return [this.barrier(tokens.slice(1))];
131
- case token_1.Token.Measure:
132
- return [this.measure(tokens.slice(1))];
133
- case token_1.Token.Id:
134
- if (!(token[1].toString().indexOf("QASM") != -1) &&
135
- !(token[1].toString().indexOf("include") != -1)) {
136
- if (this.gates.includes(token[1].toString())) {
137
- return [this.application(tokens, token[1].toString())];
138
- }
139
- else if (allowVariables) {
140
- return [new ast_1.Variable(token[1].toString())];
141
- }
142
- else {
143
- throw errors_1.BadGateError;
144
- }
145
- }
146
- else {
147
- return [];
148
- }
149
- case token_1.Token.Gate:
150
- return [this.gate(tokens.slice(1))];
151
- case token_1.Token.Opaque:
152
- return [this.opaque(tokens.slice(1))];
153
- case token_1.Token.If:
154
- return [this.conditional(tokens.slice(1))];
155
- case token_1.Token.Power:
156
- return [new ast_1.Power()];
157
- case token_1.Token.Divide:
158
- return [new ast_1.Divide()];
159
- case token_1.Token.Times:
160
- return [new ast_1.Times()];
161
- case token_1.Token.Plus:
162
- return [new ast_1.Plus()];
163
- case token_1.Token.Minus:
164
- return [new ast_1.Minus()];
165
- case token_1.Token.Pi:
166
- return [new ast_1.Pi()];
167
- case token_1.Token.Sin:
168
- return [new ast_1.Sin()];
169
- case token_1.Token.Cos:
170
- return [new ast_1.Cos()];
171
- case token_1.Token.Exp:
172
- return [new ast_1.Exp()];
173
- case token_1.Token.Ln:
174
- return [new ast_1.Ln()];
175
- case token_1.Token.Sqrt:
176
- return [new ast_1.Sqrt()];
177
- case token_1.Token.Tan:
178
- return [new ast_1.Tan()];
179
- case token_1.Token.NNInteger:
180
- return [new ast_1.NNInteger(Number(token[1]))];
181
- case token_1.Token.Real:
182
- return [new ast_1.Real(Number(token[1]))];
183
- }
184
- };
185
- /**
186
- * Checks if the next tokens match those expected.
187
- * @param tokens - Remaining tokens to parse.
188
- * @param expectedTokens - Expected tokens.
189
- * @return Whether these is a match.
190
- */
191
- Parser.prototype.matchNext = function (tokens, expectedTokens) {
192
- var matches = true;
193
- var i = 0;
194
- if (tokens.length == 0) {
195
- return false;
196
- }
197
- while (i < expectedTokens.length) {
198
- if (tokens[i][0] != expectedTokens[i]) {
199
- matches = false;
200
- break;
201
- }
202
- i++;
203
- }
204
- return matches;
205
- };
206
- /**
207
- * Parses a quantum register.
208
- * @param tokens - Remaining tokens to parse.
209
- * @return An AST node representing the quantum register.
210
- */
211
- Parser.prototype.qreg = function (tokens) {
212
- if (this.matchNext(tokens, [
213
- token_1.Token.Id,
214
- token_1.Token.LSParen,
215
- token_1.Token.NNInteger,
216
- token_1.Token.RSParen,
217
- token_1.Token.Semicolon,
218
- ])) {
219
- var id = tokens[0][1].toString();
220
- if (!this.validateIdentifier(id)) {
221
- throw errors_1.BadQregError;
222
- }
223
- var size = tokens[2][1];
224
- return new ast_1.QReg(id.toString(), Number(size));
225
- }
226
- else {
227
- throw errors_1.BadQregError;
228
- }
229
- };
230
- /**
231
- * Parses a classical register.
232
- * @param tokens - Remaining tokens to parse.
233
- * @return An AST node representing the classical register.
234
- */
235
- Parser.prototype.creg = function (tokens) {
236
- if (this.matchNext(tokens, [
237
- token_1.Token.Id,
238
- token_1.Token.LSParen,
239
- token_1.Token.NNInteger,
240
- token_1.Token.RSParen,
241
- token_1.Token.Semicolon,
242
- ])) {
243
- var id = tokens[0][1].toString();
244
- if (!this.validateIdentifier(id)) {
245
- throw errors_1.BadCregError;
246
- }
247
- var size = tokens[2][1];
248
- return new ast_1.CReg(id.toString(), Number(size));
249
- }
250
- else {
251
- throw errors_1.BadCregError;
252
- }
253
- };
254
- /**
255
- * Parses a conditional.
256
- * @param tokens - Remaining tokens to parse.
257
- * @return An AST node representing the conditional.
258
- */
259
- Parser.prototype.conditional = function (tokens) {
260
- if (this.matchNext(tokens, [
261
- token_1.Token.LParen,
262
- token_1.Token.Id,
263
- token_1.Token.Equals,
264
- token_1.Token.NNInteger,
265
- token_1.Token.RParen,
266
- ])) {
267
- var id = tokens[1][1];
268
- var val = tokens[3][1];
269
- var node = this.parseNode(tokens.slice(5));
270
- return new ast_1.If(id.toString(), Number(val), node);
271
- }
272
- else {
273
- throw errors_1.BadConditionalError;
274
- }
275
- };
276
- /**
277
- * Parses a barrier.
278
- * @param tokens - Remaining tokens to parse.
279
- * @return An AST node representing the barrier.
280
- */
281
- Parser.prototype.barrier = function (tokens) {
282
- if (this.matchNext(tokens, [token_1.Token.Id, token_1.Token.Semicolon])) {
283
- var id = tokens[0][1];
284
- return new ast_1.Barrier(id.toString());
285
- }
286
- else if (this.matchNext(tokens, [
287
- token_1.Token.Id,
288
- token_1.Token.LParen,
289
- token_1.Token.NNInteger,
290
- token_1.Token.RParen,
291
- token_1.Token.Semicolon,
292
- ])) {
293
- var id = tokens[0][1];
294
- var index = tokens[2][1];
295
- return new ast_1.Barrier(id.toString(), Number(index));
296
- }
297
- else {
298
- throw errors_1.BadBarrierError;
299
- }
300
- };
301
- /**
302
- * Parses a measurement.
303
- * @param tokens - Remaining tokens to parse.
304
- * @return An AST node representing the measurement.
305
- */
306
- Parser.prototype.measure = function (tokens) {
307
- var first_id;
308
- var second_id;
309
- var first_index;
310
- var second_index;
311
- if (this.matchNext(tokens, [token_1.Token.Id, token_1.Token.Arrow])) {
312
- first_id = tokens[0][1].toString();
313
- tokens = tokens.slice(2);
314
- }
315
- else if (this.matchNext(tokens, [
316
- token_1.Token.Id,
317
- token_1.Token.LSParen,
318
- token_1.Token.NNInteger,
319
- token_1.Token.RSParen,
320
- token_1.Token.Arrow,
321
- ])) {
322
- first_id = tokens[0][1].toString();
323
- first_index = Number(tokens[2][1]);
324
- tokens = tokens.slice(5);
325
- }
326
- else {
327
- throw errors_1.BadMeasurementError;
328
- }
329
- if (this.matchNext(tokens, [token_1.Token.Id, token_1.Token.Semicolon])) {
330
- second_id = tokens[0][1].toString();
331
- tokens = tokens.slice(2);
332
- }
333
- else if (this.matchNext(tokens, [
334
- token_1.Token.Id,
335
- token_1.Token.LSParen,
336
- token_1.Token.NNInteger,
337
- token_1.Token.RSParen,
338
- token_1.Token.Semicolon,
339
- ])) {
340
- second_id = tokens[0][1].toString();
341
- second_index = Number(tokens[2][1]);
342
- tokens = tokens.slice(5);
343
- }
344
- else {
345
- throw errors_1.BadMeasurementError;
346
- }
347
- if (first_index != undefined && second_index != undefined) {
348
- return new ast_1.Measure(first_id, second_id, first_index, second_index);
349
- }
350
- else if (first_index != undefined) {
351
- return new ast_1.Measure(first_id, second_id, first_index, null);
352
- }
353
- else if (second_index != undefined) {
354
- return new ast_1.Measure(first_id, second_id, null, second_index);
355
- }
356
- return new ast_1.Measure(first_id, second_id);
357
- };
358
- /**
359
- * Parses an application of one of the allowed gates.
360
- * @param tokens - Remaining tokens to parse.
361
- * @return An AST node representing the gate application.
362
- */
363
- Parser.prototype.application = function (tokens, op) {
364
- var params = [];
365
- var list = [];
366
- var applications = [];
367
- if (tokens[0][1] == op) {
368
- tokens = tokens.slice(1);
369
- }
370
- if (this.matchNext(tokens, [token_1.Token.LParen])) {
371
- if (this.matchNext(tokens.slice(1), [token_1.Token.RParen])) {
372
- params = [];
373
- tokens = tokens.slice(2);
374
- }
375
- else {
376
- params = this.matchParamList(tokens.slice(1));
377
- var count = 0;
378
- var commas = 0;
379
- for (var i in params) {
380
- commas += 1;
381
- for (var j in params[i]) {
382
- count++;
383
- }
384
- }
385
- tokens = tokens.slice(count + (commas - 1) + 2);
386
- }
387
- }
388
- var args = this.matchArgList(tokens);
389
- for (var arg in args) {
390
- list.push(args[arg]);
391
- }
392
- applications.push(new ast_1.ApplyGate(op, list, params));
393
- return applications;
394
- };
395
- /**
396
- * Parses a subroutine used in a custom gate definition.
397
- * @param tokens - Expression tokens to parse.
398
- * @return A parsed subroutine.
399
- */
400
- Parser.prototype.sub = function (tokens) {
401
- var ast = [];
402
- var i = 0;
403
- if (this.matchNext(tokens.slice(i), [token_1.Token.LCParen])) {
404
- tokens = tokens.slice(1);
405
- }
406
- while (i < tokens.length - 1 && tokens[i][0] != token_1.Token.RCParen) {
407
- var nodes = this.parseNode(tokens.slice(i));
408
- ast = ast.concat(nodes ? nodes : []);
409
- while (!this.matchNext(tokens.slice(i), [token_1.Token.Semicolon]) &&
410
- !this.matchNext(tokens.slice(i), [token_1.Token.RCParen])) {
411
- i++;
412
- }
413
- if (this.matchNext(tokens.slice(i), [token_1.Token.RCParen])) {
414
- break;
415
- }
416
- i++;
417
- }
418
- return ast;
419
- };
420
- /**
421
- * Parses a parameter value.
422
- * @param tokens - Tokens to parse.
423
- * @return An AST node representing the parameter value.
424
- */
425
- Parser.prototype.matchParam = function (tokens) {
426
- var param;
427
- if (!(0, token_1.notParam)(tokens[0][0])) {
428
- param = this.parseNode([tokens[0]], true);
429
- }
430
- else {
431
- throw errors_1.BadParameterError;
432
- }
433
- return param;
434
- };
435
- /**
436
- * Parses a list of parameter values.
437
- * @param tokens - Tokens to parse.
438
- * @return An array of AST nodes representing the parameter values.
439
- */
440
- Parser.prototype.matchParamList = function (tokens) {
441
- var args = [];
442
- var i = 0;
443
- var j = 0;
444
- args[0] = [];
445
- while (!this.matchNext(tokens.slice(j), [token_1.Token.RParen])) {
446
- while (!this.matchNext(tokens.slice(j), [token_1.Token.Comma]) &&
447
- !this.matchNext(tokens.slice(j), [token_1.Token.RParen])) {
448
- if ((0, token_1.notParam)(tokens[j][0])) {
449
- throw errors_1.BadParameterError;
450
- }
451
- var next = this.matchParam(tokens.slice(j));
452
- args[i].push(next);
453
- j++;
454
- }
455
- if (this.matchNext(tokens.slice(j), [token_1.Token.RParen])) {
456
- break;
457
- }
458
- i++;
459
- j++;
460
- args[i] = [];
461
- }
462
- return args;
463
- };
464
- /**
465
- * Parses an argument value.
466
- * @param tokens - Tokens to parse.
467
- * @return An AST node representing the argument value.
468
- */
469
- Parser.prototype.matchArg = function (tokens) {
470
- var index;
471
- if (this.matchNext(tokens, [token_1.Token.LSParen])) {
472
- tokens = tokens.slice(1);
473
- if (this.matchNext(tokens, [token_1.Token.NNInteger])) {
474
- index = Number(tokens[0][1]);
475
- tokens = tokens.slice(1);
476
- }
477
- else {
478
- throw errors_1.BadArgumentError;
479
- }
480
- if (this.matchNext(tokens, [token_1.Token.RSParen])) {
481
- return index;
482
- }
483
- else {
484
- throw errors_1.BadArgumentError;
485
- }
486
- }
487
- };
488
- /**
489
- * Parses a list of argument values.
490
- * @param tokens - Tokens to parse.
491
- * @return An array of AST nodes representing the argument values.
492
- */
493
- Parser.prototype.matchArgList = function (tokens) {
494
- var args = [];
495
- var next;
496
- var id;
497
- var j = 0;
498
- while (j < tokens.length &&
499
- !this.matchNext(tokens.slice(j), [token_1.Token.Semicolon])) {
500
- if (this.matchNext(tokens.slice(j), [token_1.Token.Id])) {
501
- id = tokens[j][1].toString();
502
- var index = this.matchArg(tokens.slice(j + 1));
503
- next = [id, index];
504
- args.push(next);
505
- if (index != undefined) {
506
- j += 4;
507
- }
508
- else {
509
- j++;
510
- }
511
- if (this.matchNext(tokens.slice(j), [token_1.Token.Comma])) {
512
- j++;
513
- }
514
- }
515
- else {
516
- throw errors_1.BadArgumentError;
517
- }
518
- }
519
- return args;
520
- };
521
- /**
522
- * Parses an include statement.
523
- * @param tokens - Tokens to parse.
524
- * @return An Include node representing the include statement.
525
- */
526
- Parser.prototype.include = function (tokens) {
527
- var filename;
528
- if (this.matchNext(tokens, [token_1.Token.String, token_1.Token.Semicolon])) {
529
- filename = tokens[0][1].toString();
530
- return new ast_1.Include(filename);
531
- }
532
- throw errors_1.BadIncludeError;
533
- };
534
- /**
535
- * Parses the version header and sets the parser version.
536
- * @param tokens - Tokens to parse.
537
- * @return A Version node representing the version statement.
538
- */
539
- Parser.prototype.versionHeader = function (tokens) {
540
- var version;
541
- if (this.matchNext(tokens, [token_1.Token.NNInteger, token_1.Token.Semicolon])) {
542
- version = new version_1.OpenQASMVersion(Number(tokens[0][1]));
543
- if (!version.isVersion2()) {
544
- throw errors_1.UnsupportedOpenQASMVersionError;
545
- }
546
- return new ast_1.Version(version);
547
- }
548
- else if (this.matchNext(tokens, [token_1.Token.Real, token_1.Token.Semicolon])) {
549
- var versionSplits = tokens[0][1].toString().split(".");
550
- version = new version_1.OpenQASMVersion(Number(versionSplits[0]), Number(versionSplits[1]));
551
- if (!version.isVersion2()) {
552
- throw errors_1.UnsupportedOpenQASMVersionError;
553
- }
554
- return new ast_1.Version(version);
555
- }
556
- throw errors_1.UnsupportedOpenQASMVersionError;
557
- };
558
- /**
559
- * Parses a list of identifiers.
560
- * @param tokens - Tokens to parse.
561
- * @return An array of AST nodes representing the identifiers.
562
- */
563
- Parser.prototype.matchIdList = function (tokens) {
564
- var args = [];
565
- var head;
566
- if (this.matchNext(tokens, [token_1.Token.Id])) {
567
- head = tokens[0][1].toString();
568
- }
569
- tokens = tokens.slice(1);
570
- args.push(head);
571
- if (this.matchNext(tokens, [token_1.Token.Comma])) {
572
- tokens = tokens.slice(1);
573
- var sub = this.matchIdList(tokens);
574
- args = args.concat(sub);
575
- }
576
- return args;
577
- };
578
- /**
579
- * Parses a gate.
580
- * @param tokens - Remaining tokens to parse.
581
- * @return An AST node representing the gate.
582
- */
583
- Parser.prototype.gate = function (tokens) {
584
- var name;
585
- var params;
586
- if (this.matchNext(tokens, [token_1.Token.Id])) {
587
- name = tokens[0][1].toString();
588
- if (!this.validateIdentifier(name)) {
589
- throw errors_1.BadGateError;
590
- }
591
- }
592
- else {
593
- throw errors_1.BadGateError;
594
- }
595
- tokens = tokens.slice(1);
596
- if (this.matchNext(tokens, [token_1.Token.LParen])) {
597
- tokens = tokens.slice(1);
598
- if (this.matchNext(tokens, [token_1.Token.RParen])) {
599
- params = [];
600
- tokens = tokens.slice(1);
601
- }
602
- else {
603
- params = this.matchIdList(tokens);
604
- var count_1 = params.length;
605
- tokens = tokens.slice(count_1 + 1);
606
- }
607
- }
608
- var registers = this.matchIdList(tokens);
609
- var count = registers.length;
610
- tokens = tokens.slice(count + (count - 1));
611
- var applications = this.sub(tokens);
612
- this.gates.push(name);
613
- return new ast_1.Gate(name, registers, params, applications);
614
- };
615
- /**
616
- * Parses an opaque declaration if using OpenQASM 2. If using OpenQASM 3 it skips the line.
617
- * @param tokens - Remaining tokens to parse.
618
- * @return An AST node representing the opaque declaration.
619
- */
620
- Parser.prototype.opaque = function (tokens) {
621
- var name;
622
- var params;
623
- var qubits = [];
624
- if (this.matchNext(tokens, [token_1.Token.Id])) {
625
- name = tokens[0][1].toString();
626
- tokens = tokens.slice(1);
627
- }
628
- else {
629
- throw errors_1.BadGateError;
630
- }
631
- if (this.matchNext(tokens, [token_1.Token.LParen])) {
632
- tokens = tokens.slice(1);
633
- if (!this.matchNext(tokens, [token_1.Token.RParen])) {
634
- params = this.matchIdList(tokens);
635
- tokens = tokens.slice(params.length + 1);
636
- }
637
- else {
638
- tokens = tokens.slice(1);
639
- }
640
- }
641
- qubits = this.matchArgList(tokens);
642
- tokens = tokens.slice(qubits.length * 2);
643
- if (!this.matchNext(tokens, [token_1.Token.Semicolon])) {
644
- throw errors_1.BadGateError;
645
- }
646
- return new ast_1.Opaque(name, qubits, params);
647
- };
648
- /**
649
- * Validates whether a register or gate identifier.
650
- * @param identifier - The identifier to validate.
651
- * @return Boolean indicating successful validation or not.
652
- */
653
- Parser.prototype.validateIdentifier = function (identifier) {
654
- var firstChar = identifier[0];
655
- return /^[a-z]$/.test(firstChar);
656
- };
657
- return Parser;
658
- }());
659
- exports.default = Parser;