-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathqubasic.py
More file actions
130 lines (114 loc) · 3.99 KB
/
qubasic.py
File metadata and controls
130 lines (114 loc) · 3.99 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
#!/usr/bin/env python3
"""
QUBASIC — Quantum BASIC Interactive Terminal
Usage:
python qubasic.py Interactive REPL
python qubasic.py script.qb Run a script file
"""
import sys
import os
# Force UTF-8 output on Windows
if sys.stdout and hasattr(sys.stdout, 'reconfigure'):
try:
sys.stdout.reconfigure(encoding='utf-8')
except Exception:
pass
if sys.stderr and hasattr(sys.stderr, 'reconfigure'):
try:
sys.stderr.reconfigure(encoding='utf-8')
except Exception:
pass
from qubasic_core.terminal import QBasicTerminal
from qubasic_core.program_mgmt import ProgramMgmtMixin
def run_script(path: str, terminal: 'QBasicTerminal') -> None:
"""Run a .qb script file. Supports multi-line DEF blocks.
After loading all lines, auto-runs the program if it contains
numbered lines with a MEASURE statement.
"""
with open(path, 'r') as f:
lines = [l.rstrip('\n\r') for l in f.readlines()]
ProgramMgmtMixin._load_lines_with_defs(
lines, lambda line: terminal.process(line, track_undo=False))
# Auto-run if the program has a MEASURE statement
has_measure = any(
terminal.program.get(ln, '').strip().upper() == 'MEASURE'
for ln in terminal.program
)
if terminal.program and has_measure:
terminal.cmd_run()
def main():
import json as _json
os.environ.setdefault('PYTHONIOENCODING', 'utf-8')
args = sys.argv[1:]
quiet = '--quiet' in args or '-q' in args
json_mode = '--json' in args
seed_val = None
if quiet:
args = [a for a in args if a not in ('--quiet', '-q')]
if json_mode:
args = [a for a in args if a != '--json']
# Parse --seed N
filtered = []
i = 0
while i < len(args):
if args[i] == '--seed' and i + 1 < len(args):
seed_val = int(args[i + 1])
i += 2
else:
filtered.append(args[i])
i += 1
args = filtered
if any(a in ('-h', '--help') for a in args):
from qubasic_core import __version__
print(f"QUBASIC {__version__} — Quantum BASIC Interactive Terminal")
print()
print("Usage:")
print(" qubasic Interactive REPL")
print(" qubasic script.qb Run a script file")
print(" qubasic --quiet script Suppress banner and progress")
print(" qubasic --json script Output results as JSON")
print(" qubasic --seed N script Set random seed for reproducibility")
print(" qubasic --help Show this help")
print()
print("Type HELP inside the REPL for full command reference.")
sys.exit(0)
term = QBasicTerminal()
if seed_val is not None:
import numpy as _np
term._seed = seed_val
_np.random.seed(seed_val)
if args:
path = args[0]
if os.path.isfile(path):
if quiet or json_mode:
import io
buf = io.StringIO()
old = sys.stdout
sys.stdout = buf
try:
run_script(path, term)
finally:
sys.stdout = old
if json_mode:
result = {
'counts': term.last_counts or {},
'num_qubits': term.num_qubits,
'shots': term.shots,
}
print(_json.dumps(result, indent=2))
elif not quiet:
print(buf.getvalue())
else:
term.print_banner()
run_script(path, term)
# Exit code: 0 if results exist, 1 if error
sys.exit(0 if term.last_counts is not None or not any(
term.program.get(ln, '').strip().upper() == 'MEASURE'
for ln in term.program) else 1)
else:
print(f"?FILE NOT FOUND: {path}")
sys.exit(1)
else:
term.repl()
if __name__ == '__main__':
main()