qasm-ts 1.1.1 → 1.1.2

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "qasm-ts",
3
- "version": "1.1.1",
3
+ "version": "1.1.2",
4
4
  "description": "QASM, the low-level programming language for quantum circuit specification, implemented in TypeScript.",
5
5
  "main": "dist/main.js",
6
6
  "scripts": {
package/src/ast.ts DELETED
@@ -1,192 +0,0 @@
1
-
2
- /** Base class representing a basic AST node. */
3
- class AstNode {}
4
-
5
- /** Class representing a qubit register. */
6
- class QReg extends AstNode {
7
- size:number;
8
- id:string;
9
- constructor(id:string, size:number) {
10
- super();
11
- this.id = id;
12
- this.size = size;
13
- }
14
- }
15
-
16
- /** Class representing a classical register. */
17
- class CReg extends AstNode {
18
- size:number;
19
- id:string;
20
- constructor(id:string, size:number) {
21
- super();
22
- this.id = id;
23
- this.size = size;
24
- }
25
- }
26
-
27
- /** Class representing an identifier. */
28
- class Id extends AstNode {
29
- id:string;
30
- constructor(id:string) {
31
- super();
32
- this.id = id;
33
- }
34
- }
35
-
36
- /** Class representing a barrier. */
37
- class Barrier extends AstNode {
38
- index:number;
39
- register:string;
40
- constructor(register:string, index?:number) {
41
- super();
42
- this.index = index || null;
43
- this.register = register;
44
- }
45
- }
46
-
47
- /** Class representing a variable. */
48
- class Variable extends AstNode {
49
- value:string;
50
- constructor(value:string) {
51
- super();
52
- this.value= value|| null;
53
- }
54
- }
55
-
56
- /** Class representing a measurement. */
57
- class Measure extends AstNode {
58
- src_index:number;
59
- src_register:string;
60
- dest_index:number;
61
- dest_register:string;
62
- constructor(src_register:string, dest_register:string, src_index?:number,
63
- dest_index?:number) {
64
- super();
65
- this.src_index = src_index != undefined ? src_index : null;
66
- this.src_register = src_register;
67
- this.dest_index = dest_index != undefined ? dest_index : null;
68
- this.dest_register = dest_register;
69
- }
70
- }
71
-
72
- /** Class representing a gate application. */
73
- class ApplyGate extends AstNode {
74
- name:string;
75
- qubits:Array<[string, number?]>;
76
- params:Array<AstNode>;
77
- constructor(name:string, qubits:Array<[string, number?]>,
78
- params:Array<AstNode>) {
79
- super();
80
- this.name = name;
81
- this.qubits = qubits;
82
- this.params = params;
83
- }
84
- }
85
-
86
- /** Class representing a gate. */
87
- class Gate extends AstNode {
88
- name:string;
89
- registers:Array<string>;
90
- params:Array<string>;
91
- nodes:Array<AstNode>;
92
- constructor(name:string, registers:Array<string>, params:Array<string>, nodes:Array<AstNode>) {
93
- super();
94
- this.name = name;
95
- this.registers = registers;
96
- this.params = params;
97
- this.nodes = nodes;
98
- }
99
- }
100
- /** Class representing conditional. */
101
- class If extends AstNode {
102
- register:string;
103
- param:number;
104
- gate:AstNode;
105
- constructor(register:string, param:number, gate:AstNode) {
106
- super();
107
- this.register = register;
108
- this.param = param;
109
- this.gate = gate;
110
- }
111
- }
112
-
113
- /** Class representing minus. */
114
- class Minus extends AstNode {}
115
-
116
- /** Class representing plus. */
117
- class Plus extends AstNode {}
118
-
119
- /** Class representing times. */
120
- class Times extends AstNode {}
121
-
122
- /** Class representing power. */
123
- class Power extends AstNode {}
124
-
125
- /** Class representing division. */
126
- class Divide extends AstNode {}
127
-
128
- /** Class representing pi. */
129
- class Pi extends AstNode {}
130
-
131
- /** Class representing the square root. */
132
- class Sqrt extends AstNode {}
133
-
134
- /** Class representing natural logarithm. */
135
- class Ln extends AstNode {}
136
-
137
- /** Class representing exponentiation. */
138
- class Exp extends AstNode {}
139
-
140
- /** Class representing tagnent. */
141
- class Tan extends AstNode {}
142
-
143
- /** Class representing cosine. */
144
- class Cos extends AstNode {}
145
-
146
- /** Class representing sine. */
147
- class Sin extends AstNode {}
148
-
149
- /** Class representing an integer. */
150
- class NNInteger extends AstNode {
151
- value:number;
152
- constructor(value:number) {
153
- super();
154
- this.value = value;
155
- }
156
- }
157
-
158
- /** Class representing a real. */
159
- class Real extends AstNode {
160
- value:number;
161
- constructor(value:number) {
162
- super();
163
- this.value = value;
164
- }
165
- }
166
-
167
- export {
168
- AstNode,
169
- QReg,
170
- CReg,
171
- Barrier,
172
- Measure,
173
- ApplyGate,
174
- Gate,
175
- If,
176
- Id,
177
- Divide,
178
- Plus,
179
- Minus,
180
- Times,
181
- Power,
182
- Sin,
183
- Cos,
184
- Tan,
185
- Exp,
186
- Ln,
187
- Sqrt,
188
- Pi,
189
- NNInteger,
190
- Real,
191
- Variable
192
- };
package/src/errors.ts DELETED
@@ -1,102 +0,0 @@
1
- /** Class representing a bad argument exception. */
2
- class BadArgumentError extends Error {
3
- constructor(message?: string) {
4
- super(message);
5
- Object.setPrototypeOf(this, new.target.prototype);
6
- this.name = BadArgumentError.name;
7
- }
8
- }
9
-
10
- /** Class representing a bad quantum register exception. */
11
- class BadQregError extends Error {
12
- constructor(message?: string) {
13
- super(message);
14
- Object.setPrototypeOf(this, new.target.prototype);
15
- this.name = BadQregError.name;
16
- }
17
- }
18
-
19
- /** Class representing a bad equality exception. */
20
- class BadEqualsError extends Error {
21
- constructor(message?: string) {
22
- super(message);
23
- Object.setPrototypeOf(this, new.target.prototype);
24
- this.name = BadEqualsError.name;
25
- }
26
- }
27
-
28
- /** Class representing a bad classical register exception. */
29
- class BadCregError extends Error {
30
- constructor(message?: string) {
31
- super(message);
32
- Object.setPrototypeOf(this, new.target.prototype);
33
- this.name = BadCregError.name;
34
- }
35
- }
36
-
37
- /** Class representing a bad conditional exception. */
38
- class BadConditionalError extends Error {
39
- constructor(message?: string) {
40
- super(message);
41
- Object.setPrototypeOf(this, new.target.prototype);
42
- this.name = BadConditionalError.name;
43
- }
44
- }
45
-
46
- /** Class representing a bad barrier exception. */
47
- class BadBarrierError extends Error {
48
- constructor(message?: string) {
49
- super(message);
50
- Object.setPrototypeOf(this, new.target.prototype);
51
- this.name = BadBarrierError.name;
52
- }
53
- }
54
-
55
- /** Class representing a bad measurement exception. */
56
- class BadMeasurementError extends Error {
57
- constructor(message?: string) {
58
- super(message);
59
- Object.setPrototypeOf(this, new.target.prototype);
60
- this.name = BadMeasurementError.name;
61
- }
62
- }
63
-
64
- /** Class representing a bad gate exception. */
65
- class BadGateError extends Error {
66
- constructor(message?: string) {
67
- super(message);
68
- Object.setPrototypeOf(this, new.target.prototype);
69
- this.name = BadGateError.name;
70
- }
71
- }
72
-
73
- /** Class representing a bad parameter exception. */
74
- class BadParameterError extends Error {
75
- constructor(message?: string) {
76
- super(message);
77
- Object.setPrototypeOf(this, new.target.prototype);
78
- this.name = BadParameterError.name;
79
- }
80
- }
81
-
82
- /** Class representing a missing semicolon exception. */
83
- class MissingSemicolonError extends Error {
84
- constructor(message?: string) {
85
- super(message);
86
- Object.setPrototypeOf(this, new.target.prototype);
87
- this.name = MissingSemicolonError.name;
88
- }
89
- }
90
-
91
- export {
92
- BadArgumentError,
93
- BadCregError,
94
- BadQregError,
95
- BadConditionalError,
96
- BadBarrierError,
97
- BadMeasurementError,
98
- BadGateError,
99
- BadEqualsError,
100
- BadParameterError,
101
- MissingSemicolonError
102
- };
package/src/lexer.ts DELETED
@@ -1,319 +0,0 @@
1
- import { Token, lookup } from './token';
2
- import { BadEqualsError, MissingSemicolonError } from './errors';
3
-
4
- /**
5
- * Returns whether a given character could be an element of a numeric value.
6
- * @param c - The character.
7
- * @return Whether the character is numeric.
8
- */
9
- function isNumeric(c:string): boolean {
10
- return (c == '.') || !isNaN(parseInt(c));
11
- }
12
-
13
- /**
14
- * Returns whether a given character is a letter.
15
- * @param c - The character.
16
- * @return Whether the character is a letter.
17
- */
18
- function isLetter(c:string): boolean {
19
- if (c.match(/[a-z]/i)) {
20
- return true;
21
- }
22
-
23
- return false;
24
- }
25
-
26
- /**
27
- * Returns whether a given character is alphanumeric.
28
- * @param c - The character.
29
- * @return Whether the character is alphanumeric.
30
- */
31
- function isAlpha(c:string): boolean {
32
- if (c.match(/^[0-9a-zA-Z]+$/)) {
33
- return true;
34
- }
35
- return false;
36
- }
37
-
38
- /**
39
- * Returns whether a given character is a newline character.
40
- * @param c - The character.
41
- * @return Whether the character is a newline.
42
- */
43
- function isNewline(c:string): boolean {
44
- if (c.match(/\n|\r(?!\n)|\u2028|\u2029|\r\n/g)) {
45
- return true;
46
- }
47
- return false;
48
- }
49
-
50
- /** Class representing a lexer. */
51
- class Lexer {
52
- /** The string to lex. */
53
- input:string;
54
- /** The lexer's current cursor location. */
55
- cursor:number;
56
- /**
57
- * Creates a lexer.
58
- * @param input - The string to lex.
59
- * @param cursor - The starting cursor position.
60
- */
61
- constructor(input:string, cursor:number = 0) {
62
- this.input = input;
63
- this.cursor = cursor;
64
- }
65
- verifyInput = (): boolean => {
66
- const lines = this.input.split(/\n|\r(?!\n)|\u2028|\u2029|\r\n/g);
67
- for(let i = 0; i < lines.length; i++) {
68
- if (
69
- !lines[i].startsWith('//')
70
- && !(lines[i].length == 0)
71
- && !(lines[i].includes('gate'))
72
- && !(lines[i].trim() == '{' || lines[i].trim() == '}')
73
- && !lines[i].includes(';')
74
- ){
75
- return false;
76
- }
77
- }
78
- return true;
79
- }
80
-
81
- /**
82
- * Calling this method lexes the code represented by the provided string.
83
- * @return An array of tokens and their corresponding values.
84
- */
85
- lex = (): Array<[Token, (number | String)?]> => {
86
- let tokens:Array<[Token, (number | String)?]> = [];
87
- let token:[Token, (number | String)?];
88
- if (!this.verifyInput()) {
89
- throw MissingSemicolonError;
90
- }
91
- while (this.cursor < this.input.length) {
92
- token = this.nextToken();
93
- if (token) {
94
- tokens.push(token);
95
- }
96
- }
97
- return tokens;
98
- }
99
-
100
- /**
101
- * Reads a character and advances the cursor.
102
- * @param num - Optional cursor position modifier.
103
- */
104
- readChar = (num:number=1): string => {
105
- this.cursor += num;
106
- return this.input[this.cursor - num];
107
- }
108
-
109
- /**
110
- * Advances the cusor past the next comment.
111
- */
112
- skipComment = () => {
113
- let char = '';
114
- while(!isNewline(char)) {
115
- char = this.readChar();
116
- }
117
- }
118
-
119
- /**
120
- * Determines whether the next character to process equals a given character.
121
- * @param c - The given character.
122
- * @return Whether the next character equals the given character.
123
- */
124
- peekEq = (c:string): boolean => (this.peek() == c);
125
-
126
- /**
127
- * Reads a character without advancing the cursor.
128
- * @param index - Optional peek position offset.
129
- */
130
- peek = (): string => this.input[this.cursor]
131
-
132
- /**
133
- * Reads a numeric value.
134
- * @return The numeric value as a string.
135
- */
136
- readNumeric = (): string => {
137
- let num = '';
138
- while (isNumeric(this.peek())) {
139
- num += this.readChar();
140
- }
141
- return num;
142
- }
143
-
144
- /**
145
- * Reads an identifier.
146
- * @return The identifier as a string.
147
- */
148
- readIdentifier = (): string => {
149
- let id = '';
150
- while (isAlpha(this.peek())) {
151
- id += this.readChar();
152
- }
153
- return id;
154
- }
155
-
156
- /**
157
- * Reads a string literal.
158
- * @param terminator - The literal's termination character.
159
- * @return The literal as a string.
160
- */
161
- readStringLiteral = (terminator:string): string => {
162
- let lit = '';
163
- let char = '';
164
- while (!(terminator == char)) {
165
- char = this.readChar();
166
- lit += char;
167
- }
168
- return lit;
169
- }
170
-
171
- /**
172
- * Advances the cusor past the next block of whitespace.
173
- */
174
- skipWhitespace = (): null => {
175
- while (' \t\n\r\v'.indexOf(this.peek()) > -1) {
176
- this.cursor += 1;
177
- }
178
- return null;
179
- }
180
-
181
- /**
182
- * Lexes the next token.
183
- * @return The next token and its corresponding value.
184
- */
185
- nextToken = (): [Token, (number | String)?] => {
186
- this.skipWhitespace();
187
-
188
- if (this.cursor == this.input.length) {
189
- return [Token.EndOfFile];
190
- }
191
-
192
- let char = this.peek();
193
- this.readChar();
194
-
195
- switch(char) {
196
- case '=':
197
- if (this.peekEq('=')) {
198
- this.readChar();
199
- return [Token.Equals];
200
- } else {
201
- throw BadEqualsError;
202
- }
203
- case '-':
204
- if (this.peekEq('>')) {
205
- this.readChar();
206
- return [Token.Arrow];
207
- } else {
208
- return [Token.Minus];
209
- }
210
- case '+':
211
- return [Token.Plus];
212
- case '*':
213
- return [Token.Times];
214
- case '^':
215
- return [Token.Power];
216
- case ';':
217
- return [Token.Semicolon];
218
- case ',':
219
- return [Token.Comma];
220
- case '(':
221
- return [Token.LParen];
222
- case '[':
223
- return [Token.LSParen];
224
- case '{':
225
- return [Token.LCParen];
226
- case ')':
227
- return [Token.RParen];
228
- case ']':
229
- return [Token.RSParen];
230
- case '}':
231
- return [Token.RCParen];
232
- case '/':
233
- if (this.peekEq('/')) {
234
- this.skipComment();
235
- return;
236
- } else {
237
- return [Token.Divide];
238
- }
239
- case 'g':
240
- if ((this.input[this.cursor] == 'a')
241
- && (this.input[this.cursor + 1] == 't')
242
- && (this.input[this.cursor + 2] == 'e')
243
- ){
244
- this.readChar(3);
245
- return [Token.Gate];
246
- }
247
- let literal = char + this.readIdentifier();
248
- return [lookup(literal), new String(literal)];
249
- case 'q':
250
- if ((this.input[this.cursor] == 'r')
251
- && (this.input[this.cursor + 1] == 'e')
252
- && (this.input[this.cursor + 2] == 'g')
253
- ){
254
- this.readChar(3);
255
- return [Token.QReg];
256
- }
257
- let qregLit = char + this.readIdentifier();
258
- return [lookup(qregLit), new String(qregLit)];
259
- case 'c':
260
- if ((this.input[this.cursor] == 'r')
261
- && (this.input[this.cursor + 1] == 'e')
262
- && (this.input[this.cursor + 2] == 'g')
263
- ){
264
- this.readChar(3);
265
- return [Token.QReg];
266
- }
267
- let cregLit = char + this.readIdentifier();
268
- return [lookup(cregLit), new String(cregLit)];
269
- case 'b':
270
- if ((this.input[this.cursor] == 'a')
271
- && (this.input[this.cursor + 1] == 'r')
272
- && (this.input[this.cursor + 2] == 'r')
273
- && (this.input[this.cursor + 3] == 'i')
274
- && (this.input[this.cursor + 4] == 'e')
275
- && (this.input[this.cursor + 5] == 'r')
276
- ){
277
- this.readChar(6);
278
- return [Token.Barrier];
279
- }
280
- let barLit = char + this.readIdentifier();
281
- return [lookup(barLit), new String(barLit)];
282
- case 'm':
283
- if ((this.input[this.cursor] == 'e')
284
- && (this.input[this.cursor + 1] == 'a')
285
- && (this.input[this.cursor + 2] == 's')
286
- && (this.input[this.cursor + 3] == 'u')
287
- && (this.input[this.cursor + 4] == 'r')
288
- && (this.input[this.cursor + 5] == 'e')
289
- ){
290
- this.readChar(6);
291
- return [Token.Measure];
292
- }
293
- let measureLit = char + this.readIdentifier();
294
- return [lookup(measureLit), new String(measureLit)];
295
- case '\"':
296
- let stringLiteral = char + this.readStringLiteral('\"');
297
- return [Token.String, new String(stringLiteral)];
298
- case '\’':
299
- let singleStringLiteral = char + this.readStringLiteral('\’');
300
- return [Token.String, new String(singleStringLiteral)];
301
- default:
302
- if (isLetter(char)) {
303
- let literal = char + this.readIdentifier();
304
- return [lookup(literal), new String(literal)];
305
- } else if (isNumeric(char)) {
306
- let num = char + this.readNumeric();
307
- if (num.indexOf('.') != -1) {
308
- return [Token.Real, parseFloat(num)];
309
- } else {
310
- return [Token.NNInteger, parseFloat(num)];
311
- }
312
- } else {
313
- return [Token.Illegal];
314
- }
315
- }
316
- }
317
- }
318
- export default Lexer;
319
-
package/src/main.ts DELETED
@@ -1,27 +0,0 @@
1
- import Parser from './parser';
2
- import Lexer from './lexer';
3
- import * as fs from 'fs';
4
-
5
- /**
6
- * Returns the abstract syntax tree for a given string of QASM code.
7
- * @param qasm - The code string.
8
- * @return The corresponding AST.
9
- */
10
- function parseString(qasm:string) {
11
- const lexer = new Lexer(qasm, 0);
12
- const tokens = lexer.lex();
13
- const parser = new Parser(tokens);
14
- const ast = parser.parse();
15
- return ast;
16
- }
17
-
18
- /**
19
- * Returns the abstract syntax tree for a given QASM file.
20
- * @param file - The file location.
21
- * @return The corresponding AST.
22
- */
23
- exports.parse = function(file:string) {
24
- return parseString(fs.readFileSync(file, 'utf8'));
25
- }
26
-
27
- exports.parseString = parseString;
package/src/parser.ts DELETED
@@ -1,531 +0,0 @@
1
- import {
2
- Token,
3
- notParam
4
- } from './token';
5
-
6
- import {
7
- BadArgumentError,
8
- BadCregError,
9
- BadQregError,
10
- BadConditionalError,
11
- BadBarrierError,
12
- BadMeasurementError,
13
- BadGateError,
14
- BadParameterError
15
- } from './errors';
16
-
17
- import {
18
- AstNode,
19
- QReg,
20
- CReg,
21
- Barrier,
22
- Measure,
23
- Gate,
24
- If,
25
- ApplyGate,
26
- Divide,
27
- Power,
28
- Times,
29
- Plus,
30
- Minus,
31
- Sin,
32
- Cos,
33
- Tan,
34
- Exp,
35
- Ln,
36
- Sqrt,
37
- Pi,
38
- NNInteger,
39
- Real,
40
- Variable
41
- } from './ast';
42
-
43
- /** Class representing a token parser. */
44
- class Parser {
45
-
46
- /** The tokens to parse. */
47
- tokens:Array<[Token, (number | String)?]>;
48
-
49
- /** The allowed gates. */
50
- gates:Array<string>;
51
-
52
- /**
53
- * Creates a parser.
54
- * @param tokens - Tokens to parse.
55
- */
56
- constructor(tokens:Array<[Token, (number | String)?]>) {
57
- this.tokens = tokens;
58
- this.gates = [
59
- 'x',
60
- 'y',
61
- 'z',
62
- 'u1',
63
- 'u2',
64
- 'u3',
65
- 's',
66
- 'sdg',
67
- 'h',
68
- 'tdg',
69
- 'cx',
70
- 'cy',
71
- 'cz',
72
- 't',
73
- 'ccx',
74
- 'reset',
75
- 'cu1',
76
- 'ccy',
77
- 'ccz'
78
- ]
79
- }
80
-
81
- /**
82
- * Calling this method parses the code represented by the provided tokens.
83
- * @return The abstract syntax tree.
84
- */
85
- parse(): Array<AstNode> {
86
- let ast:Array<AstNode> = [];
87
- let i = 0;
88
- while (i < (this.tokens.length - 1)) {
89
- let nodes = this.parseNode(this.tokens.slice(i));
90
- ast = ast.concat(
91
- nodes ? nodes : []
92
- );
93
- while (!(this.matchNext(this.tokens.slice(i), [Token.Semicolon]))) {
94
- if (this.matchNext(this.tokens.slice(i), [Token.LCParen])) {
95
- while (!(this.matchNext(this.tokens.slice(i), [Token.RCParen]))) {
96
- i++;
97
- }
98
- break;
99
- }
100
- i++;
101
- }
102
- i++;
103
- }
104
- return ast;
105
- }
106
-
107
- /**
108
- * Delegates the parsing of the next set of tokens to the appropriate method.
109
- * @param tokens - Remaining tokens to parse.
110
- * @param allowVariables - Whether encountered identifiers should be consider
111
- variable initializations or references.
112
- * @return A set of AST nodes.
113
- */
114
- parseNode(tokens:Array<[Token, (number | String)?]>, allowVariables=false): Array<AstNode> {
115
- const token = tokens[0];
116
- switch(token[0]) {
117
- case Token.QReg:
118
- return [this.qreg(tokens.slice(1))];
119
- case Token.CReg:
120
- return [this.creg(tokens.slice(1))];
121
- case Token.Barrier:
122
- return [this.barrier(tokens.slice(1))];
123
- case Token.Measure:
124
- return [this.measure(tokens.slice(1))];
125
- case Token.Id:
126
- if (!(token[1].toString().indexOf('QASM') != -1) &&
127
- !(token[1].toString().indexOf('include') != -1)) {
128
- if (this.gates.includes(token[1].toString())) {
129
- return [this.application(tokens, token[1].toString())];
130
- } else if (allowVariables) {
131
- return [new Variable(token[1].toString())];
132
- } else {
133
- throw BadGateError;
134
- }
135
- } else {
136
- return [];
137
- }
138
- case Token.Gate:
139
- return [this.gate(tokens.slice(1))];
140
- case Token.If:
141
- return [this.conditional(tokens.slice(1))];
142
- case Token.Power:
143
- return [new Power()];
144
- case Token.Divide:
145
- return [new Divide()];
146
- case Token.Times:
147
- return [new Times()];
148
- case Token.Plus:
149
- return [new Plus()];
150
- case Token.Minus:
151
- return [new Minus()];
152
- case Token.Pi:
153
- return [new Pi()];
154
- case Token.Sin:
155
- return [new Sin()];
156
- case Token.Cos:
157
- return [new Cos()];
158
- case Token.Exp:
159
- return [new Exp()];
160
- case Token.Ln:
161
- return [new Ln()];
162
- case Token.Sqrt:
163
- return [new Sqrt()];
164
- case Token.Tan:
165
- return [new Tan()];
166
- case Token.NNInteger:
167
- return [new NNInteger(Number(token[1]))];
168
- case Token.Real:
169
- return [new Real(Number(token[1]))];
170
- }
171
- }
172
-
173
- /**
174
- * Checks if the next tokens match those expected.
175
- * @param tokens - Remaining tokens to parse.
176
- * @param expectedTokens - Expected tokens.
177
- * @return Whether these is a match.
178
- */
179
- matchNext(tokens:Array<[Token, (number | String)?]>, expectedTokens:Array<Token>): boolean {
180
- let matches = true;
181
- let i = 0;
182
- if (tokens.length == 0) {
183
- return false;
184
- }
185
- while (i < expectedTokens.length) {
186
- if (tokens[i][0] != expectedTokens[i]) {
187
- matches = false;
188
- break;
189
- }
190
- i++;
191
- }
192
- return matches;
193
- }
194
-
195
- /**
196
- * Parses a quantum register.
197
- * @param tokens - Remaining tokens to parse.
198
- * @return An AST node representing the quantum register.
199
- */
200
- qreg(tokens:Array<[Token, (number | String)?]>): AstNode {
201
- if (this.matchNext(tokens, [Token.Id, Token.LSParen, Token.NNInteger, Token.RSParen, Token.Semicolon])) {
202
- const id = tokens[0][1];
203
- const size = tokens[2][1];
204
- return new QReg(id.toString(), Number(size));
205
- } else {
206
- throw BadQregError;
207
- }
208
- }
209
-
210
- /**
211
- * Parses a classical register.
212
- * @param tokens - Remaining tokens to parse.
213
- * @return An AST node representing the classical register.
214
- */
215
- creg(tokens:Array<[Token, (number | String)?]>): AstNode {
216
- if (this.matchNext(tokens, [Token.Id, Token.LSParen, Token.NNInteger,
217
- Token.RSParen, Token.Semicolon])) {
218
- const id = tokens[0][1];
219
- const size = tokens[2][1];
220
- return new CReg(id.toString(), Number(size));
221
- } else {
222
- throw BadCregError;
223
- }
224
- }
225
-
226
- /**
227
- * Parses a conditional.
228
- * @param tokens - Remaining tokens to parse.
229
- * @return An AST node representing the conditional.
230
- */
231
- conditional(tokens:Array<[Token, (number | String)?]>): AstNode {
232
- if (this.matchNext(tokens, [Token.LParen, Token.Id, Token.Equals, Token.NNInteger, Token.RParen])) {
233
- let id = tokens[1][1];
234
- let val = tokens[3][1];
235
- let node = this.parseNode(tokens.slice(5));
236
- return new If(id.toString(), Number(val), node);
237
- } else {
238
- throw BadConditionalError;
239
- }
240
- }
241
-
242
- /**
243
- * Parses a barrier.
244
- * @param tokens - Remaining tokens to parse.
245
- * @return An AST node representing the barrier.
246
- */
247
- barrier(tokens:Array<[Token, (number | String)?]>): AstNode {
248
- if (this.matchNext(tokens, [Token.Id, Token.Semicolon])) {
249
- let id = tokens[0][1];
250
- return new Barrier(id.toString());
251
- } else if (this.matchNext(tokens, [Token.Id, Token.LParen,
252
- Token.NNInteger, Token.RParen, Token.Semicolon])) {
253
- let id = tokens[0][1];
254
- let index = tokens[2][1];
255
- return new Barrier(id.toString(), Number(index));
256
- } else {
257
- throw BadBarrierError;
258
- }
259
- }
260
-
261
- /**
262
- * Parses a measurement.
263
- * @param tokens - Remaining tokens to parse.
264
- * @return An AST node representing the measurement.
265
- */
266
- measure(tokens:Array<[Token, (number | String)?]>): AstNode {
267
- let first_id:string;
268
- let second_id:string;
269
- let first_index:number;
270
- let second_index:number;
271
- if (this.matchNext(tokens, [Token.Id, Token.Arrow])) {
272
- first_id = tokens[0][1].toString();
273
- tokens = tokens.slice(2);
274
- } else if (this.matchNext(tokens, [Token.Id, Token.LSParen, Token.NNInteger, Token.RSParen, Token.Arrow])) {
275
- first_id = tokens[0][1].toString();
276
- first_index = Number(tokens[2][1]);
277
- tokens = tokens.slice(5);
278
- } else {
279
- throw BadMeasurementError;
280
- }
281
- if (this.matchNext(tokens, [Token.Id, Token.Semicolon])) {
282
- second_id = tokens[0][1].toString();
283
- tokens = tokens.slice(2);
284
- } else if (this.matchNext(tokens, [Token.Id, Token.LSParen, Token.NNInteger, Token.RSParen, Token.Semicolon])) {
285
- second_id = tokens[0][1].toString();
286
- second_index = Number(tokens[2][1]);
287
- tokens = tokens.slice(5);
288
- } else {
289
- throw BadMeasurementError;
290
- }
291
- if (first_index != undefined && second_index != undefined) {
292
- return new Measure(first_id, second_id, first_index, second_index);
293
- } else if (first_index != undefined) {
294
- return new Measure(first_id, second_id, first_index=first_index);
295
- } else if (second_index != undefined) {
296
- return new Measure(first_id, second_id, second_index=second_index);
297
- }
298
- return new Measure(first_id, second_id);
299
- }
300
-
301
- /**
302
- * Parses an application of one of the allowed gates.
303
- * @param tokens - Remaining tokens to parse.
304
- * @return An AST node representing the gate application.
305
- */
306
- application(tokens:Array<[Token, (number | String)?]>, op:string): Array<AstNode> {
307
- let params:Array<AstNode> = [];
308
- let list:Array<[string, number?]> = [];
309
- let applications:Array<AstNode> = [];
310
- let id:string;
311
- if (tokens[0][1] == op) {
312
- tokens = tokens.slice(1);
313
- }
314
- if (this.matchNext(tokens, [Token.LParen])) {
315
- if (this.matchNext(tokens.slice(1), [Token.RParen])) {
316
- params = [];
317
- tokens = tokens.slice(2);
318
- } else {
319
- params = this.matchParamList(tokens.slice(1));
320
- let count = 0;
321
- let commas = 0;
322
- for (let i in params) {
323
- commas += 1;
324
- for (let j in params[i]) {
325
- count++;
326
- }
327
- }
328
-
329
- tokens = tokens.slice(count + (commas - 1) + 2);
330
- }
331
- }
332
- let args = this.matchArgList(tokens);
333
- for (let arg in args) {
334
- id = args[arg][0];
335
- list.push(args[arg]);
336
- }
337
- applications.push(new ApplyGate(op, list, params));
338
- return applications;
339
- }
340
-
341
- /**
342
- * Parses a subroutine used in a custom gate definition.
343
- * @param tokens - Expression tokens to parse.
344
- * @return A parsed subroutine.
345
- */
346
- sub(tokens:Array<[Token, (number | String)?]>): Array<AstNode> {
347
- let ast:Array<AstNode> = [];
348
- let i = 0;
349
- if (this.matchNext(tokens.slice(i), [Token.LCParen])) {
350
- tokens = tokens.slice(1);
351
- }
352
- while ((i < (tokens.length - 1)) && (tokens[i][0] != Token.RCParen)) {
353
- let nodes = this.parseNode(tokens.slice(i));
354
- ast = ast.concat(
355
- nodes ? nodes : []
356
- );
357
- while ((!this.matchNext(tokens.slice(i), [Token.Semicolon])) &&
358
- (!this.matchNext(tokens.slice(i), [Token.RCParen]))) {
359
- i++;
360
- }
361
- if (this.matchNext(tokens.slice(i), [Token.RCParen])) {
362
- break;
363
- }
364
- i++;
365
- }
366
- return ast;
367
- }
368
-
369
- /**
370
- * Parses a parameter value.
371
- * @param tokens - Tokens to parse.
372
- * @return An AST node representing the parameter value.
373
- */
374
- matchParam(tokens:Array<[Token, (number | String)?]>): AstNode {
375
- let param:AstNode;
376
- if (!(notParam(tokens[0][0]))) {
377
- param = this.parseNode([tokens[0]], true);
378
- } else {
379
- throw BadParameterError;
380
- }
381
- return param;
382
- }
383
-
384
- /**
385
- * Parses a list of parameter values.
386
- * @param tokens - Tokens to parse.
387
- * @return An array of AST nodes representing the parameter values.
388
- */
389
- matchParamList(tokens:Array<[Token, (number | String)?]>): Array<Array<AstNode>> {
390
- let args:Array<Array<AstNode>> = [];
391
- let i:number = 0;
392
- let j:number = 0;
393
- args[0] = [];
394
- while(!this.matchNext(tokens.slice(j), [Token.RParen])) {
395
- while(!this.matchNext(tokens.slice(j), [Token.Comma]) &&
396
- !this.matchNext(tokens.slice(j), [Token.RParen])) {
397
- if (notParam(tokens[j][0])) {
398
- throw BadParameterError;
399
- }
400
- let next = this.matchParam(tokens.slice(j));
401
- args[i].push(next);
402
- j++;
403
- }
404
- if (this.matchNext(tokens.slice(j), [Token.RParen])) {
405
- break;
406
- }
407
- i++;
408
- j++;
409
- args[i] = [];
410
- }
411
- return args;
412
- }
413
-
414
- /**
415
- * Parses an argument value.
416
- * @param tokens - Tokens to parse.
417
- * @return An AST node representing the argument value.
418
- */
419
- matchArg(tokens:Array<[Token, (number | String)?]>): number {
420
- let index:number;
421
- if (this.matchNext(tokens, [Token.LSParen])) {
422
- tokens = tokens.slice(1);
423
- if (this.matchNext(tokens, [Token.NNInteger])) {
424
- index = Number(tokens[0][1]);
425
- tokens = tokens.slice(1);
426
- } else {
427
- throw BadArgumentError;
428
- }
429
- if (this.matchNext(tokens, [Token.RSParen])) {
430
- return index;
431
- } else {
432
- throw BadArgumentError;
433
- }
434
- }
435
- }
436
-
437
- /**
438
- * Parses a list of argument values.
439
- * @param tokens - Tokens to parse.
440
- * @return An array of AST nodes representing the argument values.
441
- */
442
- matchArgList(tokens:Array<[Token, (number | String)?]>): Array<[string,number?]> {
443
- let args:Array<[string, number?]> = [];
444
- let next:[string, number?];
445
- let id:string;
446
- let j:number = 0;
447
- while(j < tokens.length && !this.matchNext(tokens.slice(j),[Token.Semicolon])) {
448
- if (this.matchNext(tokens.slice(j), [Token.Id])) {
449
- id = tokens[j][1].toString();
450
- let index = this.matchArg(tokens.slice(j + 1));
451
- next = [id, index];
452
- args.push(next);
453
- if (index != undefined) {
454
- j += 4;
455
- } else {
456
- j++;
457
- }
458
- if (this.matchNext(tokens.slice(j), [Token.Comma])) {
459
- j++;
460
- }
461
- } else {
462
- throw BadArgumentError;
463
- }
464
- }
465
- return args;
466
- }
467
-
468
- /**
469
- * Parses a list of identifiers.
470
- * @param tokens - Tokens to parse.
471
- * @return An array of AST nodes representing the identifiers.
472
- */
473
- matchIdList(tokens:Array<[Token, (number | String)?]>): Array<string> {
474
- let args:Array<string> = [];
475
- let head:string;
476
- if (this.matchNext(tokens, [Token.Id])) {
477
- head = tokens[0][1].toString();
478
- }
479
- tokens = tokens.slice(1);
480
- args.push(head);
481
- if (this.matchNext(tokens, [Token.Comma])) {
482
- tokens = tokens.slice(1);
483
- let sub = this.matchIdList(tokens);
484
- args = args.concat(sub);
485
- }
486
- return args;
487
- }
488
-
489
- /**
490
- * Parses a gate.
491
- * @param tokens - Remaining tokens to parse.
492
- * @return An AST node representing the gate.
493
- */
494
- gate(tokens:Array<[Token, (number | String)?]>): AstNode {
495
- let name:string;
496
- let params:Array<string>;
497
- let registers:Array<string>;
498
- let applications:Array<AstNode>;
499
- if (this.matchNext(tokens, [Token.Id])) {
500
- name = tokens[0][1].toString();
501
- } else {
502
- throw BadGateError;
503
- }
504
- tokens = tokens.slice(1);
505
- if (this.matchNext(tokens, [Token.LParen])) {
506
- tokens = tokens.slice(1);
507
- if (this.matchNext(tokens, [Token.RParen])) {
508
- params = [];
509
- tokens = tokens.slice(1);
510
- } else {
511
- params = this.matchIdList(tokens);
512
- let count = 0;
513
- for (let i in params) {
514
- count++;
515
- }
516
- tokens = tokens.slice(count + 1);
517
- }
518
- }
519
- registers = this.matchIdList(tokens);
520
- let count = 0;
521
- for (let i in registers) {
522
- count++;
523
- }
524
- tokens = tokens.slice(count + (count - 1));
525
- applications = this.sub(tokens);
526
- this.gates.push(name);
527
- return new Gate(name, registers, params, applications);
528
- }
529
- }
530
-
531
- export default Parser;
package/src/token.ts DELETED
@@ -1,92 +0,0 @@
1
- enum Token {
2
- Illegal,
3
- EndOfFile,
4
- Real,
5
- NNInteger,
6
- Id,
7
- OpenQASM,
8
- Semicolon,
9
- Comma,
10
- LParen,
11
- LSParen,
12
- LCParen,
13
- RParen,
14
- RSParen,
15
- RCParen,
16
- Arrow,
17
- Equals,
18
- Plus,
19
- Minus,
20
- Times,
21
- Divide,
22
- Power,
23
- Sin,
24
- Cos,
25
- Tan,
26
- Exp,
27
- Ln,
28
- Sqrt,
29
- Pi,
30
- QReg,
31
- CReg,
32
- Barrier,
33
- Gate,
34
- Measure,
35
- Reset,
36
- Include,
37
- If,
38
- String
39
- }
40
-
41
- const lookupMap:object = {
42
- 'if': Token.If,
43
- 'sin': Token.Sin,
44
- 'cos': Token.Cos,
45
- 'tan': Token.Tan,
46
- 'exp': Token.Exp,
47
- 'ln': Token.Ln,
48
- 'sqrt': Token.Sqrt,
49
- 'pi': Token.Pi,
50
- '+': Token.Plus,
51
- '-': Token.Minus,
52
- '/': Token.Divide,
53
- '*': Token.Times,
54
- '^': Token.Power
55
- }
56
-
57
- /**
58
- * Returns the token that represents a given string.
59
- * @param ident - The string.
60
- * @return The corresponding token.
61
- */
62
- function lookup(ident: string): Token {
63
- return ident in lookupMap ? lookupMap[ident]: Token.Id;
64
- }
65
-
66
- /**
67
- * Returns the string representation of a token.
68
- * @param tokens - The token.
69
- * @return The string representation of the token.
70
- */
71
- function inverseLookup(token:Token): string {
72
- return Object.keys(lookupMap).find((ident) => lookupMap[ident] == token);
73
- }
74
-
75
- /**
76
- * Determines whether a token denotes a parameter.
77
- * @param tokens - The token.
78
- * @return Whether the token does NOT denote a parameter.
79
- */
80
- function notParam(token:Token): boolean {
81
- if (token == Token.NNInteger || token == Token.Real || token == Token.Id || this.inverseLookup(token)) {
82
- return false;
83
- }
84
- return true;
85
- }
86
-
87
- export {
88
- Token,
89
- notParam,
90
- lookup,
91
- inverseLookup
92
- };