1
1
module Quasar
2
2
3
3
using .. BraketSimulator
4
- using Automa, AbstractTrees, DataStructures
4
+ using Automa, AbstractTrees, DataStructures, Dates
5
5
using DataStructures: Stack
6
6
using BraketSimulator: Control, Instruction, Result, bind_value!, remap, qubit_count, Circuit
7
7
@@ -71,9 +71,7 @@ const qasm_tokens = [
71
71
:arrow_token => re " ->" ,
72
72
:reset_token => re " reset" ,
73
73
:delay_token => re " delay" ,
74
- :stretch_token => re " stretch" ,
75
- :barrier_token => re " barrier" ,
76
- :duration_token => re " duration" ,
74
+ :barrier_token => re " barrier" ,
77
75
:void => re " void" ,
78
76
:const_token => re " const" ,
79
77
:assignment => re " =|-=|\+ =|\* =|/=|^=|&=|\| =|<<=|>>=" ,
@@ -110,12 +108,18 @@ const qasm_tokens = [
110
108
:string_token => ' "' * rep (re " [ !#-~]" | re "\\\\\" " ) * ' "' | ' \' ' * rep (re " [ -&(-~]" | (' \\ ' * re " [ -~]" )) * ' \' ' ,
111
109
:newline => re "\r ?\n " ,
112
110
:spaces => re " [\t ]+" ,
113
- :durationof_token => re "durationof " , # this MUST be lower than duration_token to preempt duration
114
- :classical_type => re "bool|uint|int|float|angle|complex|array|bit " ,
115
- :duration_value => (float | integer) * re " ns|µs| us|ms|s" ,
111
+ :classical_type => re "bool|uint|int|float|angle|complex|array|bit|stretch|duration " ,
112
+ :durationof_token => re "durationof " , # this MUST be lower than classical_type to preempt duration
113
+ :duration_literal => (float | integer) * re "dt| ns|us|ms|s| \x ce \x bc \x 73 " , # transcode'd μs
116
114
:forbidden_keyword => re " cal|defcal|extern" ,
117
115
]
118
116
117
+ const dt_type = Ref {DataType} ()
118
+
119
+ function __init__ ()
120
+ dt_type[] = Nanosecond
121
+ end
122
+
119
123
@eval @enum Token error $ (first .(qasm_tokens)... )
120
124
make_tokenizer ((error,
121
125
[Token (i) => j for (i,j) in enumerate (last .(qasm_tokens))]
@@ -369,6 +373,15 @@ function parse_classical_type(tokens, stack, start, qasm)
369
373
first (array_tokens)[end ] == comma && popfirst! (array_tokens)
370
374
size = parse_expression (array_tokens, stack, start, qasm)
371
375
return QasmExpression (:classical_type , SizedArray (eltype, size))
376
+ elseif var_type == " duration"
377
+ @warn " duration expression encountered -- currently `duration` is a no-op"
378
+ # TODO : add proper parsing of duration expressions, including
379
+ # support for units and algebraic durations like 2*a.
380
+ return QasmExpression (:classical_type , :duration )
381
+ elseif var_type == " stretch"
382
+ @warn " stretch expression encountered -- currently `stretch` is a no-op"
383
+ # TODO : add proper parsing of stretch expressions
384
+ return QasmExpression (:classical_type , :stretch )
372
385
else
373
386
! any (triplet-> triplet[end ] == semicolon, tokens) && push! (tokens, (- 1 , Int32 (- 1 ), semicolon))
374
387
size = is_sized ? parse_expression (tokens, stack, start, qasm) : QasmExpression (:integer_literal , - 1 )
@@ -427,6 +440,21 @@ parse_oct_literal(token, qasm) = QasmExpression(:integer_literal, tryparse(I
427
440
parse_bin_literal (token, qasm) = QasmExpression (:integer_literal , tryparse (Int, qasm[token[1 ]: token[1 ]+ token[2 ]- 1 ]))
428
441
parse_float_literal (token, qasm) = QasmExpression (:float_literal , tryparse (Float64, qasm[token[1 ]: token[1 ]+ token[2 ]- 1 ]))
429
442
parse_boolean_literal (token, qasm) = QasmExpression (:boolean_literal , tryparse (Bool, qasm[token[1 ]: token[1 ]+ token[2 ]- 1 ]))
443
+ function parse_duration_literal (token, qasm)
444
+ str = String (codeunits (qasm)[token[1 ]: token[1 ]+ token[2 ]- 1 ])
445
+ duration = if endswith (str, " ns" )
446
+ Nanosecond (tryparse (Int, chop (str, tail= 2 )))
447
+ elseif endswith (str, " ms" )
448
+ Millisecond (tryparse (Int, chop (str, tail= 2 )))
449
+ elseif endswith (str, " us" ) || endswith (str, " μs" )
450
+ Microsecond (tryparse (Int, chop (str, tail= 2 )))
451
+ elseif endswith (str, " s" )
452
+ Second (tryparse (Int, chop (str, tail= 1 )))
453
+ elseif endswith (str, " dt" )
454
+ dt_type[](tryparse (Int, chop (str, tail= 2 )))
455
+ end
456
+ QasmExpression (:duration_literal , duration)
457
+ end
430
458
function parse_irrational_literal (token, qasm)
431
459
raw_string = String (codeunits (qasm)[token[1 ]: token[1 ]+ token[2 ]- 1 ])
432
460
raw_string == " pi" && return QasmExpression (:irrational_literal , π)
@@ -463,7 +491,7 @@ function extract_braced_block(tokens::Vector{Tuple{Int64, Int32, Token}}, stack,
463
491
next_token[end ] == rbracket && (closers_met += 1 )
464
492
push! (braced_tokens, next_token)
465
493
end
466
- pop! (braced_tokens) # closing }
494
+ pop! (braced_tokens) # closing ]
467
495
push! (braced_tokens, (- 1 , Int32 (- 1 ), semicolon))
468
496
return braced_tokens
469
497
end
@@ -511,6 +539,7 @@ function parse_list_expression(tokens::Vector{Tuple{Int64, Int32, Token}}, stack
511
539
end
512
540
513
541
function parse_literal (tokens:: Vector{Tuple{Int64, Int32, Token}} , stack, start, qasm)
542
+ tokens[1 ][end ] == duration_literal && return parse_duration_literal (popfirst! (tokens), qasm)
514
543
tokens[1 ][end ] == string_token && return parse_string_literal (popfirst! (tokens), qasm)
515
544
tokens[1 ][end ] == hex && return parse_hex_literal (popfirst! (tokens), qasm)
516
545
tokens[1 ][end ] == oct && return parse_oct_literal (popfirst! (tokens), qasm)
@@ -634,7 +663,7 @@ function parse_expression(tokens::Vector{Tuple{Int64, Int32, Token}}, stack, sta
634
663
token_name = parse_bracketed_expression (pushfirst! (tokens, start_token), stack, start, qasm)
635
664
elseif start_token[end ] == classical_type
636
665
token_name = parse_classical_type (pushfirst! (tokens, start_token), stack, start, qasm)
637
- elseif start_token[end ] ∈ (string_token, integer_token, float_token, hex, oct, bin, irrational, dot, boolean)
666
+ elseif start_token[end ] ∈ (string_token, integer_token, float_token, hex, oct, bin, irrational, dot, boolean, duration_literal )
638
667
token_name = parse_literal (pushfirst! (tokens, start_token), stack, start, qasm)
639
668
elseif start_token[end ] ∈ (mutable, readonly, const_token)
640
669
token_name = parse_identifier (start_token, qasm)
@@ -644,7 +673,6 @@ function parse_expression(tokens::Vector{Tuple{Int64, Int32, Token}}, stack, sta
644
673
token_name = QasmExpression (:n_dims , QasmExpression (:integer_literal , parse (Int, dim)))
645
674
end
646
675
head (token_name) == :empty && throw (QasmParseError (" unable to parse line with start token $(start_token[end ]) " , stack, start, qasm))
647
-
648
676
next_token = first (tokens)
649
677
if next_token[end ] == semicolon || next_token[end ] == comma || start_token[end ] ∈ (lbracket, lbrace)
650
678
expr = token_name
@@ -657,7 +685,7 @@ function parse_expression(tokens::Vector{Tuple{Int64, Int32, Token}}, stack, sta
657
685
unary_op_symbol ∈ (:~ , :! , :- ) || throw (QasmParseError (" invalid unary operator $unary_op_symbol ." , stack, start, qasm))
658
686
next_expr = parse_expression (tokens, stack, start, qasm)
659
687
# apply unary op to next_expr
660
- if head (next_expr) ∈ (:identifier , :indexed_identifier , :integer_literal , :float_literal , :string_literal , :irrational_literal , :boolean_literal , :complex_literal , :function_call , :cast )
688
+ if head (next_expr) ∈ (:identifier , :indexed_identifier , :integer_literal , :float_literal , :string_literal , :irrational_literal , :boolean_literal , :complex_literal , :function_call , :cast , :duration_literal )
661
689
expr = QasmExpression (:unary_op , unary_op_symbol, next_expr)
662
690
elseif head (next_expr) == :binary_op
663
691
# replace first argument
@@ -1005,36 +1033,37 @@ function parse_qasm(clean_tokens::Vector{Tuple{Int64, Int32, Token}}, qasm::Stri
1005
1033
line_exprs = collect (Iterators. reverse (line_body))[2 : end ]
1006
1034
push! (stack, QasmExpression (:return , line_exprs))
1007
1035
elseif token == box
1008
- @warn " box expression encountered -- currently boxed and delayed expressions are not supported "
1036
+ @warn " box expression encountered -- currently `box` is a no-op "
1009
1037
box_expr = QasmExpression (:box )
1010
1038
parse_block_body (box_expr, clean_tokens, stack, start, qasm)
1011
1039
push! (stack, box_expr)
1012
1040
elseif token == reset_token
1013
1041
@warn " reset expression encountered -- currently `reset` is a no-op"
1014
1042
eol = findfirst (triplet-> triplet[end ] == semicolon, clean_tokens)
1015
1043
reset_tokens = splice! (clean_tokens, 1 : eol)
1016
- targets = parse_expression (reset_tokens, stack, start, qasm)
1044
+ targets = parse_list_expression (reset_tokens, stack, start, qasm)
1017
1045
push! (stack, QasmExpression (:reset , targets))
1018
1046
elseif token == barrier_token
1019
1047
@warn " barrier expression encountered -- currently `barrier` is a no-op"
1020
1048
eol = findfirst (triplet-> triplet[end ] == semicolon, clean_tokens)
1021
1049
barrier_tokens = splice! (clean_tokens, 1 : eol)
1022
- targets = parse_expression (barrier_tokens, stack, start, qasm)
1050
+ targets = parse_list_expression (barrier_tokens, stack, start, qasm)
1023
1051
push! (stack, QasmExpression (:barrier , targets))
1024
- elseif token == duration_token
1025
- @warn " duration expression encountered -- currently `duration` is a no-op"
1026
- eol = findfirst (triplet-> triplet[end ] == semicolon, clean_tokens)
1027
- duration_tokens = splice! (clean_tokens, 1 : eol)
1028
- # TODO : add proper parsing of duration expressions, including
1029
- # support for units and algebraic durations like 2*a.
1030
- # dur_expr = parse_expression(duration_tokens, stack, start, qasm)
1031
- push! (stack, QasmExpression (:duration ))
1032
- elseif token == stretch_token
1033
- @warn " stretch expression encountered -- currently `stretch` is a no-op"
1052
+ elseif token == delay_token
1053
+ @warn " delay expression encountered -- currently `delay` is a no-op"
1034
1054
eol = findfirst (triplet-> triplet[end ] == semicolon, clean_tokens)
1035
- stretch_tokens = splice! (clean_tokens, 1 : eol)
1036
- stretch_expr = parse_expression (stretch_tokens, stack, start, qasm)
1037
- push! (stack, QasmExpression (:stretch , stretch_expr))
1055
+ delay_tokens = splice! (clean_tokens, 1 : eol)
1056
+ delay_expr = QasmExpression (:delay )
1057
+ # format is delay[duration]; or delay[duration] targets;
1058
+ delay_duration = extract_braced_block (delay_tokens, stack, start, qasm)
1059
+ push! (delay_expr, QasmExpression (:duration , parse_expression (delay_duration, stack, start, qasm)))
1060
+ target_expr = QasmExpression (:targets )
1061
+ if first (delay_tokens)[end ] != semicolon # targets present
1062
+ targets = parse_list_expression (delay_tokens, stack, start, qasm)
1063
+ push! (target_expr, targets)
1064
+ end
1065
+ push! (delay_expr, target_expr)
1066
+ push! (stack, delay_expr)
1038
1067
elseif token == end_token
1039
1068
push! (stack, QasmExpression (:end ))
1040
1069
elseif token == identifier || token == builtin_gate
@@ -1327,7 +1356,7 @@ function evaluate(v::V, expr::QasmExpression) where {V<:AbstractVisitor}
1327
1356
step:: Int = evaluate (v, raw_step)
1328
1357
stop:: Int = evaluate (v, raw_stop)
1329
1358
return StepRange (start, step, stop)
1330
- elseif head (expr) ∈ (:integer_literal , :float_literal , :string_literal , :complex_literal , :irrational_literal , :boolean_literal )
1359
+ elseif head (expr) ∈ (:integer_literal , :float_literal , :string_literal , :complex_literal , :irrational_literal , :boolean_literal , :duration_literal )
1331
1360
return expr. args[1 ]
1332
1361
elseif head (expr) == :array_literal
1333
1362
return [evaluate (v, arg) for arg in convert (Vector{QasmExpression}, expr. args)]
@@ -1630,8 +1659,21 @@ function (v::AbstractVisitor)(program_expr::QasmExpression)
1630
1659
elseif head (program_expr) == :version
1631
1660
return v
1632
1661
elseif head (program_expr) == :reset
1662
+ targets = program_expr. args[1 ]:: QasmExpression
1663
+ target_qubits = evaluate (v, targets)
1664
+ push! (v, [BraketSimulator. Instruction (BraketSimulator. Reset (), t) for t in target_qubits])
1633
1665
return v
1634
1666
elseif head (program_expr) == :barrier
1667
+ targets = program_expr. args[1 ]:: QasmExpression
1668
+ target_qubits = evaluate (v, targets)
1669
+ push! (v, [BraketSimulator. Instruction (BraketSimulator. Barrier (), t) for t in target_qubits])
1670
+ return v
1671
+ elseif head (program_expr) == :delay
1672
+ duration_expr = program_expr. args[1 ]. args[1 ]:: QasmExpression
1673
+ targets = program_expr. args[2 ]. args[1 ]:: QasmExpression
1674
+ target_qubits = evaluate (v, targets)
1675
+ duration = evaluate (v, duration_expr)
1676
+ push! (v, [BraketSimulator. Instruction (BraketSimulator. Delay (duration), t) for t in target_qubits])
1635
1677
return v
1636
1678
elseif head (program_expr) == :stretch
1637
1679
return v
0 commit comments