Coverage for src / tracekit / dsl / repl.py: 94%
94 statements
« prev ^ index » next coverage.py v7.13.1, created at 2026-01-11 23:04 +0000
« prev ^ index » next coverage.py v7.13.1, created at 2026-01-11 23:04 +0000
1"""TraceKit DSL REPL (Read-Eval-Print Loop).
3Interactive shell for TraceKit DSL.
4"""
6import sys
8from tracekit.dsl.interpreter import Interpreter, InterpreterError
9from tracekit.dsl.parser import parse_dsl
12class REPL:
13 """Interactive DSL shell."""
15 def __init__(self) -> None:
16 """Initialize REPL with new interpreter."""
17 self.interpreter = Interpreter()
18 self.running = True
20 def print_banner(self) -> None:
21 """Print welcome banner."""
22 print("TraceKit DSL REPL v0.1.0")
23 print("Type 'exit' or 'quit' to exit, 'help' for help")
24 print()
26 def print_help(self) -> None:
27 """Print help message."""
28 print("TraceKit DSL Commands:")
29 print(" load <filename> - Load a trace file")
30 print(" filter <type> <params> - Apply filter (lowpass, highpass, etc.)")
31 print(" measure <name> - Measure property (rise_time, etc.)")
32 print(" plot - Plot trace")
33 print(" export <format> - Export data (json, csv, hdf5)")
34 print(" glob(<pattern>) - Match files")
35 print()
36 print("Variables:")
37 print(" $name = expression - Assign variable")
38 print(" $name - Reference variable")
39 print()
40 print("Pipelines:")
41 print(" expr | command | command - Chain operations")
42 print()
43 print("Loops:")
44 print(" for $var in expr: statement - Iterate")
45 print()
46 print("Special commands:")
47 print(" help - Show this help")
48 print(" vars - List variables")
49 print(" exit, quit - Exit REPL")
50 print()
52 def print_variables(self) -> None:
53 """Print current variables."""
54 if not self.interpreter.variables:
55 print("No variables defined")
56 return
58 print("Variables:")
59 for name, value in self.interpreter.variables.items():
60 # Truncate long values
61 str_value = str(value)
62 if len(str_value) > 60:
63 str_value = str_value[:57] + "..."
64 print(f" {name} = {str_value}")
66 def read_input(self) -> str | None:
67 """Read input line from user.
69 Returns:
70 Input line or None on EOF
71 """
72 try:
73 return input("tk> ")
74 except EOFError:
75 return None
77 def eval_special_command(self, line: str) -> bool:
78 """Evaluate special REPL commands.
80 Args:
81 line: Input line
83 Returns:
84 True if special command was handled, False otherwise
85 """
86 line = line.strip()
88 if line in ("exit", "quit"):
89 self.running = False
90 return True
92 if line == "help":
93 self.print_help()
94 return True
96 if line == "vars":
97 self.print_variables()
98 return True
100 return False
102 def eval_line(self, line: str) -> None:
103 """Evaluate a single line of input.
105 Args:
106 line: Input line
107 """
108 line = line.strip()
110 # Skip empty lines
111 if not line:
112 return
114 # Skip comments
115 if line.startswith("#"):
116 return
118 # Check for special commands
119 if self.eval_special_command(line):
120 return
122 # Parse and execute
123 try:
124 ast = parse_dsl(line)
125 self.interpreter.execute(ast)
127 # Print result if expression statement (not assignment)
128 if ast and hasattr(ast[-1], "expression"):
129 # Assignment - don't print
130 pass
131 else:
132 # Expression - could print result
133 # For now, commands handle their own output
134 pass
136 except SyntaxError as e:
137 print(f"Syntax error: {e}", file=sys.stderr)
139 except InterpreterError as e:
140 print(f"Error: {e}", file=sys.stderr)
142 except Exception as e:
143 print(f"Unexpected error: {e}", file=sys.stderr)
145 def run(self) -> None:
146 """Run REPL loop."""
147 self.print_banner()
149 while self.running:
150 line = self.read_input()
152 if line is None:
153 # EOF
154 print()
155 break
157 self.eval_line(line)
159 print("Goodbye!")
162def start_repl() -> None:
163 """Start interactive REPL.
165 This is the main entry point for the DSL REPL.
166 """
167 repl = REPL()
168 repl.run()
171if __name__ == "__main__":
172 start_repl()