IncludeCPP 4.3.0__py3-none-any.whl → 4.6.0__py3-none-any.whl

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.
Files changed (30) hide show
  1. includecpp/CHANGELOG.md +22 -0
  2. includecpp/__init__.py +1 -1
  3. includecpp/__init__.pyi +1 -4
  4. includecpp/cli/commands.py +1218 -25
  5. includecpp/core/cpp_api_extensions.pyi +204 -200
  6. includecpp/core/cssl/__init__.py +317 -0
  7. includecpp/core/cssl/cpp/build/api.pyd +0 -0
  8. includecpp/core/cssl/cpp/build/cssl_core.pyi +323 -0
  9. includecpp/core/cssl/cpp/build/libgcc_s_seh-1.dll +0 -0
  10. includecpp/core/cssl/cpp/build/libstdc++-6.dll +0 -0
  11. includecpp/core/cssl/cpp/build/libwinpthread-1.dll +0 -0
  12. includecpp/core/cssl/cpp/cssl_core.cp +108 -0
  13. includecpp/core/cssl/cpp/cssl_lexer.hpp +280 -0
  14. includecpp/core/cssl/cssl_builtins.py +142 -27
  15. includecpp/core/cssl/cssl_compiler.py +448 -0
  16. includecpp/core/cssl/cssl_optimizer.py +833 -0
  17. includecpp/core/cssl/cssl_parser.py +433 -38
  18. includecpp/core/cssl/cssl_runtime.py +294 -15
  19. includecpp/core/cssl/cssl_syntax.py +17 -0
  20. includecpp/core/cssl/cssl_types.py +143 -11
  21. includecpp/core/cssl_bridge.py +39 -2
  22. includecpp/generator/parser.cpp +38 -14
  23. includecpp/vscode/cssl/package.json +15 -0
  24. includecpp/vscode/cssl/syntaxes/cssl.tmLanguage.json +96 -0
  25. {includecpp-4.3.0.dist-info → includecpp-4.6.0.dist-info}/METADATA +1 -1
  26. {includecpp-4.3.0.dist-info → includecpp-4.6.0.dist-info}/RECORD +30 -21
  27. {includecpp-4.3.0.dist-info → includecpp-4.6.0.dist-info}/WHEEL +0 -0
  28. {includecpp-4.3.0.dist-info → includecpp-4.6.0.dist-info}/entry_points.txt +0 -0
  29. {includecpp-4.3.0.dist-info → includecpp-4.6.0.dist-info}/licenses/LICENSE +0 -0
  30. {includecpp-4.3.0.dist-info → includecpp-4.6.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,833 @@
1
+ """
2
+ CSSL Optimizer - Smart Adaptive Performance System
3
+
4
+ This module provides intelligent C++/Python execution switching:
5
+ 1. Adaptive threshold learning from actual execution times
6
+ 2. Complexity scoring based on code analysis
7
+ 3. Automatic tuning based on runtime performance
8
+ 4. Full C++ interpreter for complex code (375x+ speedup)
9
+ 5. Python for simple code (lower overhead)
10
+
11
+ The optimizer learns which execution path is fastest for different code patterns.
12
+ """
13
+
14
+ import sys
15
+ import time
16
+ import hashlib
17
+ import re
18
+ from pathlib import Path
19
+ from typing import Optional, Dict, Any, List, Tuple, Callable
20
+ from dataclasses import dataclass, field
21
+ from threading import Lock
22
+ from collections import defaultdict
23
+
24
+
25
+ # =============================================================================
26
+ # Performance Thresholds (Auto-Tuned)
27
+ # =============================================================================
28
+
29
+ @dataclass
30
+ class PerformanceThresholds:
31
+ """Configurable thresholds for optimization decisions."""
32
+
33
+ # Source size thresholds (characters)
34
+ small_source: int = 200 # Use Python for < 200 chars
35
+ medium_source: int = 1000 # Mixed optimization
36
+ large_source: int = 5000 # Full C++ acceleration
37
+
38
+ # Complexity score thresholds
39
+ simple_complexity: int = 10 # Simple code - Python
40
+ complex_threshold: int = 50 # Complex code - C++
41
+
42
+ # Loop thresholds
43
+ small_loop: int = 50 # Small loops - Python OK
44
+ large_loop: int = 500 # Large loops - prefer C++
45
+
46
+ # Cache settings
47
+ cache_enabled: bool = True
48
+ cache_max_size: int = 200
49
+ cache_ttl: float = 600.0 # 10 minutes TTL
50
+
51
+ # Adaptive tuning
52
+ adaptive_enabled: bool = True
53
+ learning_rate: float = 0.1 # How fast to adapt thresholds
54
+ min_samples: int = 5 # Min samples before adapting
55
+
56
+
57
+ # Global thresholds instance
58
+ THRESHOLDS = PerformanceThresholds()
59
+
60
+
61
+ # =============================================================================
62
+ # Complexity Analyzer
63
+ # =============================================================================
64
+
65
+ class ComplexityAnalyzer:
66
+ """
67
+ Analyzes CSSL code to estimate execution complexity.
68
+
69
+ Scoring:
70
+ - Each loop: +10 (nested: +20)
71
+ - Each class: +15
72
+ - Each function: +5
73
+ - Datastruct operations: +20
74
+ - String operations in loop: +15
75
+ - Math operations: +5
76
+ - Recursion detected: +30
77
+ """
78
+
79
+ # Patterns for complexity detection
80
+ LOOP_PATTERNS = [
81
+ r'\bfor\s*\(',
82
+ r'\bwhile\s*\(',
83
+ r'\bforeach\s*\(',
84
+ ]
85
+ CLASS_PATTERN = r'\bclass\s+\w+'
86
+ FUNC_PATTERN = r'\b(?:define|void|int|float|string|bool|dynamic)\s+\w+\s*\('
87
+ DATASTRUCT_PATTERN = r'\b(?:datastruct|shuffled|iterator|combo|dataspace)\b'
88
+ RECURSION_PATTERN = r'(\w+)\s*\([^)]*\)[^{]*\{[^}]*\1\s*\('
89
+ # v4.6.0: Native keyword forces C++ execution
90
+ NATIVE_PATTERN = r'\bnative\b'
91
+
92
+ def __init__(self):
93
+ self._pattern_cache: Dict[str, re.Pattern] = {}
94
+
95
+ def _get_pattern(self, pattern: str) -> re.Pattern:
96
+ """Get compiled regex pattern (cached)."""
97
+ if pattern not in self._pattern_cache:
98
+ self._pattern_cache[pattern] = re.compile(pattern, re.MULTILINE | re.IGNORECASE)
99
+ return self._pattern_cache[pattern]
100
+
101
+ def analyze(self, source: str) -> 'ComplexityScore':
102
+ """Analyze source and return complexity score."""
103
+ score = ComplexityScore(source=source)
104
+
105
+ # Count loops
106
+ for pattern in self.LOOP_PATTERNS:
107
+ matches = self._get_pattern(pattern).findall(source)
108
+ score.loop_count += len(matches)
109
+
110
+ # Detect nested loops (simplified)
111
+ score.nested_loops = source.count('for (') > 1 and 'for (' in source[source.find('for (') + 5:]
112
+
113
+ # Count classes
114
+ score.class_count = len(self._get_pattern(self.CLASS_PATTERN).findall(source))
115
+
116
+ # Count functions
117
+ score.function_count = len(self._get_pattern(self.FUNC_PATTERN).findall(source))
118
+
119
+ # Check for datastruct operations
120
+ score.has_datastruct = bool(self._get_pattern(self.DATASTRUCT_PATTERN).search(source))
121
+
122
+ # Check for recursion
123
+ score.has_recursion = bool(self._get_pattern(self.RECURSION_PATTERN).search(source))
124
+
125
+ # Check for native keyword (forces C++ execution)
126
+ score.force_native = bool(self._get_pattern(self.NATIVE_PATTERN).search(source))
127
+
128
+ # Calculate total score
129
+ score.calculate()
130
+
131
+ return score
132
+
133
+
134
+ @dataclass
135
+ class ComplexityScore:
136
+ """Complexity analysis result."""
137
+ source: str = ""
138
+ loop_count: int = 0
139
+ nested_loops: bool = False
140
+ class_count: int = 0
141
+ function_count: int = 0
142
+ has_datastruct: bool = False
143
+ has_recursion: bool = False
144
+ force_native: bool = False # Force C++ execution (native keyword)
145
+ total_score: int = 0
146
+
147
+ def calculate(self) -> None:
148
+ """Calculate total complexity score."""
149
+ self.total_score = 0
150
+
151
+ # Base score from source size
152
+ self.total_score += len(self.source) // 100
153
+
154
+ # Loop complexity
155
+ self.total_score += self.loop_count * 10
156
+ if self.nested_loops:
157
+ self.total_score += 20
158
+
159
+ # Class complexity
160
+ self.total_score += self.class_count * 15
161
+
162
+ # Function complexity
163
+ self.total_score += self.function_count * 5
164
+
165
+ # Datastruct operations
166
+ if self.has_datastruct:
167
+ self.total_score += 20
168
+
169
+ # Recursion
170
+ if self.has_recursion:
171
+ self.total_score += 30
172
+
173
+ @property
174
+ def recommendation(self) -> str:
175
+ """Get execution recommendation."""
176
+ if self.total_score < THRESHOLDS.simple_complexity:
177
+ return "python"
178
+ elif self.total_score >= THRESHOLDS.complex_threshold:
179
+ return "cpp"
180
+ else:
181
+ return "hybrid"
182
+
183
+
184
+ # Global analyzer
185
+ _ANALYZER = ComplexityAnalyzer()
186
+
187
+
188
+ # =============================================================================
189
+ # Adaptive Performance Tracker
190
+ # =============================================================================
191
+
192
+ class PerformanceTracker:
193
+ """
194
+ Tracks execution performance and adapts thresholds.
195
+
196
+ Learns which execution path (Python vs C++) is faster for different
197
+ code patterns and complexity levels.
198
+ """
199
+
200
+ def __init__(self):
201
+ self._lock = Lock()
202
+ # Track times by complexity bracket
203
+ self._python_times: Dict[str, List[float]] = defaultdict(list)
204
+ self._cpp_times: Dict[str, List[float]] = defaultdict(list)
205
+ # Track decisions and outcomes
206
+ self._decisions: List[Tuple[str, str, float]] = [] # (complexity_bracket, engine, time)
207
+
208
+ def _get_bracket(self, score: int) -> str:
209
+ """Get complexity bracket for a score."""
210
+ if score < 10:
211
+ return "tiny"
212
+ elif score < 30:
213
+ return "small"
214
+ elif score < 70:
215
+ return "medium"
216
+ elif score < 150:
217
+ return "large"
218
+ else:
219
+ return "huge"
220
+
221
+ def record(self, complexity_score: int, engine: str, exec_time: float) -> None:
222
+ """Record execution performance."""
223
+ bracket = self._get_bracket(complexity_score)
224
+
225
+ with self._lock:
226
+ if engine == "python":
227
+ self._python_times[bracket].append(exec_time)
228
+ # Keep last 50 samples
229
+ if len(self._python_times[bracket]) > 50:
230
+ self._python_times[bracket] = self._python_times[bracket][-50:]
231
+ else:
232
+ self._cpp_times[bracket].append(exec_time)
233
+ if len(self._cpp_times[bracket]) > 50:
234
+ self._cpp_times[bracket] = self._cpp_times[bracket][-50:]
235
+
236
+ self._decisions.append((bracket, engine, exec_time))
237
+ if len(self._decisions) > 200:
238
+ self._decisions = self._decisions[-200:]
239
+
240
+ def get_best_engine(self, complexity_score: int) -> str:
241
+ """Get recommended engine based on historical performance."""
242
+ bracket = self._get_bracket(complexity_score)
243
+
244
+ with self._lock:
245
+ py_times = self._python_times.get(bracket, [])
246
+ cpp_times = self._cpp_times.get(bracket, [])
247
+
248
+ # Need minimum samples
249
+ if len(py_times) < THRESHOLDS.min_samples:
250
+ # Not enough Python data - use default logic
251
+ return "cpp" if complexity_score >= THRESHOLDS.complex_threshold else "python"
252
+
253
+ if len(cpp_times) < THRESHOLDS.min_samples:
254
+ # Not enough C++ data - try C++ to gather data
255
+ return "cpp" if complexity_score >= THRESHOLDS.simple_complexity else "python"
256
+
257
+ # Compare averages
258
+ py_avg = sum(py_times) / len(py_times)
259
+ cpp_avg = sum(cpp_times) / len(cpp_times)
260
+
261
+ # Add small overhead penalty for C++ (call overhead)
262
+ cpp_overhead = 0.0001 # 0.1ms overhead
263
+
264
+ if cpp_avg + cpp_overhead < py_avg:
265
+ return "cpp"
266
+ else:
267
+ return "python"
268
+
269
+ def get_stats(self) -> Dict[str, Any]:
270
+ """Get performance statistics."""
271
+ with self._lock:
272
+ stats = {
273
+ "brackets": {},
274
+ "total_decisions": len(self._decisions),
275
+ }
276
+
277
+ for bracket in ["tiny", "small", "medium", "large", "huge"]:
278
+ py_times = self._python_times.get(bracket, [])
279
+ cpp_times = self._cpp_times.get(bracket, [])
280
+
281
+ stats["brackets"][bracket] = {
282
+ "python_samples": len(py_times),
283
+ "python_avg_ms": (sum(py_times) / len(py_times) * 1000) if py_times else 0,
284
+ "cpp_samples": len(cpp_times),
285
+ "cpp_avg_ms": (sum(cpp_times) / len(cpp_times) * 1000) if cpp_times else 0,
286
+ "recommended": self.get_best_engine(
287
+ {"tiny": 5, "small": 20, "medium": 50, "large": 100, "huge": 200}[bracket]
288
+ ),
289
+ }
290
+
291
+ return stats
292
+
293
+
294
+ # Global tracker
295
+ _TRACKER = PerformanceTracker()
296
+
297
+
298
+ # =============================================================================
299
+ # AST Cache
300
+ # =============================================================================
301
+
302
+ @dataclass
303
+ class CachedAST:
304
+ """Cached AST with metadata."""
305
+ ast: Any
306
+ source_hash: str
307
+ created_at: float
308
+ complexity_score: int = 0
309
+ access_count: int = 0
310
+ total_exec_time: float = 0.0
311
+
312
+ @property
313
+ def avg_exec_time(self) -> float:
314
+ if self.access_count == 0:
315
+ return 0.0
316
+ return self.total_exec_time / self.access_count
317
+
318
+
319
+ class ASTCache:
320
+ """Thread-safe AST cache with LRU eviction and TTL."""
321
+
322
+ def __init__(self, max_size: int = 200, ttl: float = 600.0):
323
+ self._cache: Dict[str, CachedAST] = {}
324
+ self._lock = Lock()
325
+ self._max_size = max_size
326
+ self._ttl = ttl
327
+ self._hits = 0
328
+ self._misses = 0
329
+
330
+ def _hash_source(self, source: str) -> str:
331
+ return hashlib.md5(source.encode('utf-8')).hexdigest()
332
+
333
+ def get(self, source: str) -> Optional[CachedAST]:
334
+ """Get cached AST for source code."""
335
+ source_hash = self._hash_source(source)
336
+
337
+ with self._lock:
338
+ if source_hash in self._cache:
339
+ cached = self._cache[source_hash]
340
+
341
+ if time.time() - cached.created_at > self._ttl:
342
+ del self._cache[source_hash]
343
+ self._misses += 1
344
+ return None
345
+
346
+ cached.access_count += 1
347
+ self._hits += 1
348
+ return cached
349
+
350
+ self._misses += 1
351
+ return None
352
+
353
+ def put(self, source: str, ast: Any, complexity_score: int = 0) -> None:
354
+ """Cache AST for source code."""
355
+ source_hash = self._hash_source(source)
356
+
357
+ with self._lock:
358
+ if len(self._cache) >= self._max_size:
359
+ self._evict_lru()
360
+
361
+ self._cache[source_hash] = CachedAST(
362
+ ast=ast,
363
+ source_hash=source_hash,
364
+ created_at=time.time(),
365
+ complexity_score=complexity_score
366
+ )
367
+
368
+ def record_execution(self, source: str, exec_time: float) -> None:
369
+ """Record execution time for adaptive optimization."""
370
+ source_hash = self._hash_source(source)
371
+
372
+ with self._lock:
373
+ if source_hash in self._cache:
374
+ self._cache[source_hash].total_exec_time += exec_time
375
+
376
+ def _evict_lru(self) -> None:
377
+ """Evict least recently used entry."""
378
+ if not self._cache:
379
+ return
380
+
381
+ oldest_hash = min(
382
+ self._cache.keys(),
383
+ key=lambda h: (self._cache[h].access_count, -self._cache[h].created_at)
384
+ )
385
+ del self._cache[oldest_hash]
386
+
387
+ def clear(self) -> None:
388
+ """Clear all cached ASTs."""
389
+ with self._lock:
390
+ self._cache.clear()
391
+ self._hits = 0
392
+ self._misses = 0
393
+
394
+ @property
395
+ def stats(self) -> Dict[str, Any]:
396
+ total = self._hits + self._misses
397
+ return {
398
+ 'size': len(self._cache),
399
+ 'max_size': self._max_size,
400
+ 'hits': self._hits,
401
+ 'misses': self._misses,
402
+ 'hit_rate': self._hits / total if total > 0 else 0.0,
403
+ }
404
+
405
+
406
+ # Global AST cache
407
+ _AST_CACHE = ASTCache(
408
+ max_size=THRESHOLDS.cache_max_size,
409
+ ttl=THRESHOLDS.cache_ttl
410
+ )
411
+
412
+
413
+ # =============================================================================
414
+ # Execution Context
415
+ # =============================================================================
416
+
417
+ @dataclass
418
+ class ExecutionContext:
419
+ """Context for optimized execution decisions."""
420
+ source: str
421
+ source_size: int = 0
422
+ complexity: Optional[ComplexityScore] = None
423
+ recommended_engine: str = "python"
424
+ cached_ast: Optional[CachedAST] = None
425
+
426
+ def __post_init__(self):
427
+ self.source_size = len(self.source)
428
+ # Quick complexity analysis
429
+ self.complexity = _ANALYZER.analyze(self.source)
430
+ # Get recommendation from tracker (adaptive) or complexity score
431
+ if THRESHOLDS.adaptive_enabled:
432
+ self.recommended_engine = _TRACKER.get_best_engine(self.complexity.total_score)
433
+ else:
434
+ self.recommended_engine = self.complexity.recommendation
435
+
436
+
437
+ # =============================================================================
438
+ # Optimized Operations
439
+ # =============================================================================
440
+
441
+ class OptimizedOperations:
442
+ """
443
+ Provides optimized implementations that automatically choose
444
+ between Python and C++ based on input size.
445
+ """
446
+
447
+ def __init__(self):
448
+ self._cpp_module = None
449
+ self._cpp_available = False
450
+ self._load_cpp()
451
+
452
+ def _load_cpp(self) -> None:
453
+ try:
454
+ from . import _cpp_module, _CPP_AVAILABLE
455
+ self._cpp_module = _cpp_module
456
+ self._cpp_available = _CPP_AVAILABLE
457
+ except ImportError:
458
+ pass
459
+
460
+ def str_upper(self, s: str) -> str:
461
+ if len(s) < 100 or not self._cpp_available:
462
+ return s.upper()
463
+ if self._cpp_module and hasattr(self._cpp_module, 'str_upper'):
464
+ return self._cpp_module.str_upper(s)
465
+ return s.upper()
466
+
467
+ def str_lower(self, s: str) -> str:
468
+ if len(s) < 100 or not self._cpp_available:
469
+ return s.lower()
470
+ if self._cpp_module and hasattr(self._cpp_module, 'str_lower'):
471
+ return self._cpp_module.str_lower(s)
472
+ return s.lower()
473
+
474
+ def str_replace(self, s: str, old: str, new: str) -> str:
475
+ if len(s) < 100 or not self._cpp_available:
476
+ return s.replace(old, new)
477
+ if self._cpp_module and hasattr(self._cpp_module, 'str_replace'):
478
+ return self._cpp_module.str_replace(s, old, new)
479
+ return s.replace(old, new)
480
+
481
+ def str_split(self, s: str, sep: str) -> List[str]:
482
+ if len(s) < 100 or not self._cpp_available:
483
+ return s.split(sep)
484
+ if self._cpp_module and hasattr(self._cpp_module, 'str_split'):
485
+ return self._cpp_module.str_split(s, sep)
486
+ return s.split(sep)
487
+
488
+ def str_join(self, sep: str, items: List[str]) -> str:
489
+ if len(items) < 50 or not self._cpp_available:
490
+ return sep.join(items)
491
+ if self._cpp_module and hasattr(self._cpp_module, 'str_join'):
492
+ return self._cpp_module.str_join(sep, items)
493
+ return sep.join(items)
494
+
495
+ def str_trim(self, s: str) -> str:
496
+ if len(s) < 100 or not self._cpp_available:
497
+ return s.strip()
498
+ if self._cpp_module and hasattr(self._cpp_module, 'str_trim'):
499
+ return self._cpp_module.str_trim(s)
500
+ return s.strip()
501
+
502
+ def tokenize(self, source: str) -> List[Any]:
503
+ """Optimized tokenization."""
504
+ use_cpp = (
505
+ self._cpp_available and
506
+ len(source) >= THRESHOLDS.small_source and
507
+ self._cpp_module and
508
+ hasattr(self._cpp_module, 'Lexer')
509
+ )
510
+
511
+ if use_cpp:
512
+ try:
513
+ lexer = self._cpp_module.Lexer(source)
514
+ return lexer.tokenize()
515
+ except Exception:
516
+ pass
517
+
518
+ from .cssl_parser import CSSLLexer
519
+ lexer = CSSLLexer(source)
520
+ return lexer.tokenize()
521
+
522
+
523
+ # Global optimized operations
524
+ OPS = OptimizedOperations()
525
+
526
+
527
+ # =============================================================================
528
+ # Smart Optimized Runtime
529
+ # =============================================================================
530
+
531
+ class OptimizedRuntime:
532
+ """
533
+ Smart CSSL runtime with adaptive C++/Python switching.
534
+
535
+ Features:
536
+ - Learns from execution times to optimize decisions
537
+ - Uses complexity analysis for initial estimates
538
+ - Full C++ interpreter for complex code (375x+ speedup)
539
+ - Python for simple code (lower call overhead)
540
+ - AST caching for repeated execution
541
+ """
542
+
543
+ def __init__(self):
544
+ self._cache = _AST_CACHE
545
+ self._tracker = _TRACKER
546
+ self._ops = OPS
547
+ self._execution_times: List[float] = []
548
+ self._cpp_module = None
549
+ self._cpp_available = False
550
+ self._load_cpp()
551
+
552
+ def _load_cpp(self) -> None:
553
+ try:
554
+ from . import _cpp_module, _CPP_AVAILABLE
555
+ self._cpp_module = _cpp_module
556
+ self._cpp_available = _CPP_AVAILABLE
557
+ except ImportError:
558
+ pass
559
+
560
+ def execute(self, source: str, service_engine=None) -> Any:
561
+ """
562
+ Execute CSSL with smart optimization.
563
+
564
+ Decision flow:
565
+ 1. Analyze complexity
566
+ 2. Check if service_engine requires Python
567
+ 3. Consult adaptive tracker for best engine
568
+ 4. Check AST cache
569
+ 5. Execute with chosen engine
570
+ 6. Record performance for learning
571
+ """
572
+ start_time = time.perf_counter()
573
+
574
+ # Create execution context (includes complexity analysis)
575
+ ctx = ExecutionContext(source)
576
+
577
+ # Check for 'native' keyword - forces C++ execution
578
+ force_native = ctx.complexity.force_native if ctx.complexity else False
579
+
580
+ # Determine execution engine
581
+ if force_native and self._cpp_available:
582
+ # 'native' keyword forces C++ execution (no fallback)
583
+ engine = "cpp"
584
+ elif service_engine is not None:
585
+ # Service engine requires Python runtime
586
+ engine = "python"
587
+ elif self._cpp_available and ctx.recommended_engine == "cpp":
588
+ # Check adaptive recommendation
589
+ engine = "cpp"
590
+ else:
591
+ engine = "python"
592
+
593
+ # Execute
594
+ try:
595
+ if engine == "cpp" and self._cpp_module and hasattr(self._cpp_module, 'run_cssl'):
596
+ result = self._execute_cpp(source)
597
+ else:
598
+ # Check cache for Python execution
599
+ cached = self._cache.get(source) if THRESHOLDS.cache_enabled else None
600
+ if cached is not None:
601
+ result = self._execute_ast(cached.ast, service_engine)
602
+ else:
603
+ result = self._parse_and_execute(source, ctx, service_engine)
604
+ engine = "python" # Ensure we record correctly
605
+
606
+ # Record timing
607
+ exec_time = time.perf_counter() - start_time
608
+ self._execution_times.append(exec_time)
609
+ if len(self._execution_times) > 100:
610
+ self._execution_times = self._execution_times[-100:]
611
+
612
+ # Record for adaptive learning
613
+ if THRESHOLDS.adaptive_enabled and ctx.complexity:
614
+ self._tracker.record(ctx.complexity.total_score, engine, exec_time)
615
+
616
+ if THRESHOLDS.cache_enabled:
617
+ self._cache.record_execution(source, exec_time)
618
+
619
+ return result
620
+
621
+ except Exception as e:
622
+ # On C++ failure, fallback to Python
623
+ if engine == "cpp":
624
+ return self._parse_and_execute(source, ctx, service_engine)
625
+ raise
626
+
627
+ def _execute_cpp(self, source: str) -> Any:
628
+ """Execute using full C++ interpreter."""
629
+ return self._cpp_module.run_cssl(source)
630
+
631
+ def _parse_and_execute(self, source: str, ctx: ExecutionContext, service_engine) -> Any:
632
+ """Parse and execute with Python runtime."""
633
+ from .cssl_parser import CSSLParser
634
+ from .cssl_runtime import CSSLRuntime
635
+
636
+ # Tokenize (with smart switching)
637
+ tokens = self._ops.tokenize(source)
638
+
639
+ # Parse
640
+ parser = CSSLParser(tokens)
641
+ ast = parser.parse()
642
+
643
+ # Cache AST
644
+ if THRESHOLDS.cache_enabled and ctx.complexity:
645
+ self._cache.put(source, ast, ctx.complexity.total_score)
646
+
647
+ # Execute
648
+ runtime = CSSLRuntime(service_engine)
649
+ return runtime.execute_ast(ast)
650
+
651
+ def _execute_ast(self, ast: Any, service_engine) -> Any:
652
+ """Execute pre-parsed AST."""
653
+ from .cssl_runtime import CSSLRuntime
654
+ runtime = CSSLRuntime(service_engine)
655
+ return runtime.execute_ast(ast)
656
+
657
+ @property
658
+ def avg_execution_time(self) -> float:
659
+ if not self._execution_times:
660
+ return 0.0
661
+ return sum(self._execution_times) / len(self._execution_times) * 1000
662
+
663
+ @property
664
+ def cache_stats(self) -> Dict[str, Any]:
665
+ return self._cache.stats
666
+
667
+ @property
668
+ def performance_stats(self) -> Dict[str, Any]:
669
+ return self._tracker.get_stats()
670
+
671
+
672
+ # Global optimized runtime
673
+ _OPTIMIZED_RUNTIME = OptimizedRuntime()
674
+
675
+
676
+ # =============================================================================
677
+ # Public API
678
+ # =============================================================================
679
+
680
+ def run_optimized(source: str, service_engine=None) -> Any:
681
+ """
682
+ Run CSSL with smart adaptive optimization.
683
+
684
+ Automatically chooses between:
685
+ - C++ interpreter for complex code (375x+ faster)
686
+ - Python runtime for simple code (lower overhead)
687
+ - Cached AST for repeated execution
688
+
689
+ The optimizer learns from execution times to make better decisions.
690
+
691
+ Args:
692
+ source: CSSL source code
693
+ service_engine: Optional service engine for Python interop
694
+
695
+ Returns:
696
+ Execution result
697
+ """
698
+ return _OPTIMIZED_RUNTIME.execute(source, service_engine)
699
+
700
+
701
+ def get_optimizer_stats() -> Dict[str, Any]:
702
+ """Get comprehensive optimizer statistics."""
703
+ from . import _CPP_AVAILABLE, _CPP_LOAD_SOURCE
704
+
705
+ return {
706
+ 'cpp_available': _CPP_AVAILABLE,
707
+ 'cpp_source': _CPP_LOAD_SOURCE,
708
+ 'cache': _AST_CACHE.stats,
709
+ 'performance': _TRACKER.get_stats(),
710
+ 'avg_exec_time_ms': _OPTIMIZED_RUNTIME.avg_execution_time,
711
+ 'thresholds': {
712
+ 'small_source': THRESHOLDS.small_source,
713
+ 'medium_source': THRESHOLDS.medium_source,
714
+ 'large_source': THRESHOLDS.large_source,
715
+ 'simple_complexity': THRESHOLDS.simple_complexity,
716
+ 'complex_threshold': THRESHOLDS.complex_threshold,
717
+ }
718
+ }
719
+
720
+
721
+ def configure_optimizer(
722
+ cache_enabled: bool = None,
723
+ cache_max_size: int = None,
724
+ cache_ttl: float = None,
725
+ adaptive_enabled: bool = None,
726
+ small_source: int = None,
727
+ complex_threshold: int = None,
728
+ ) -> None:
729
+ """
730
+ Configure optimizer settings.
731
+
732
+ Args:
733
+ cache_enabled: Enable/disable AST caching
734
+ cache_max_size: Maximum cached ASTs
735
+ cache_ttl: Cache TTL in seconds
736
+ adaptive_enabled: Enable adaptive threshold learning
737
+ small_source: Source size threshold for Python
738
+ complex_threshold: Complexity score threshold for C++
739
+ """
740
+ global THRESHOLDS, _AST_CACHE
741
+
742
+ if cache_enabled is not None:
743
+ THRESHOLDS.cache_enabled = cache_enabled
744
+ if cache_max_size is not None:
745
+ THRESHOLDS.cache_max_size = cache_max_size
746
+ if cache_ttl is not None:
747
+ THRESHOLDS.cache_ttl = cache_ttl
748
+ if adaptive_enabled is not None:
749
+ THRESHOLDS.adaptive_enabled = adaptive_enabled
750
+ if small_source is not None:
751
+ THRESHOLDS.small_source = small_source
752
+ if complex_threshold is not None:
753
+ THRESHOLDS.complex_threshold = complex_threshold
754
+
755
+ _AST_CACHE = ASTCache(
756
+ max_size=THRESHOLDS.cache_max_size,
757
+ ttl=THRESHOLDS.cache_ttl
758
+ )
759
+
760
+
761
+ def clear_cache() -> None:
762
+ """Clear AST cache."""
763
+ _AST_CACHE.clear()
764
+
765
+
766
+ def get_optimized_ops() -> OptimizedOperations:
767
+ """Get the optimized operations instance."""
768
+ return OPS
769
+
770
+
771
+ def analyze_complexity(source: str) -> Dict[str, Any]:
772
+ """
773
+ Analyze CSSL code complexity.
774
+
775
+ Returns complexity score and recommendation (python/cpp/hybrid).
776
+ """
777
+ score = _ANALYZER.analyze(source)
778
+ return {
779
+ 'source_size': len(source),
780
+ 'loop_count': score.loop_count,
781
+ 'nested_loops': score.nested_loops,
782
+ 'class_count': score.class_count,
783
+ 'function_count': score.function_count,
784
+ 'has_datastruct': score.has_datastruct,
785
+ 'has_recursion': score.has_recursion,
786
+ 'total_score': score.total_score,
787
+ 'recommendation': score.recommendation,
788
+ }
789
+
790
+
791
+ # =============================================================================
792
+ # Precompiled Patterns
793
+ # =============================================================================
794
+
795
+ class PrecompiledPattern:
796
+ """
797
+ Precompiled CSSL code for maximum performance.
798
+
799
+ Use this for frequently executed code patterns.
800
+ """
801
+
802
+ def __init__(self, source: str):
803
+ self.source = source
804
+ self._ast = None
805
+ self._complexity = _ANALYZER.analyze(source)
806
+ self._compile()
807
+
808
+ def _compile(self) -> None:
809
+ """Pre-parse the source."""
810
+ from .cssl_parser import CSSLParser
811
+ tokens = OPS.tokenize(self.source)
812
+ parser = CSSLParser(tokens)
813
+ self._ast = parser.parse()
814
+
815
+ def execute(self, service_engine=None) -> Any:
816
+ """Execute precompiled pattern."""
817
+ from .cssl_runtime import CSSLRuntime
818
+ runtime = CSSLRuntime(service_engine)
819
+ return runtime.execute_ast(self._ast)
820
+
821
+ @property
822
+ def complexity(self) -> int:
823
+ return self._complexity.total_score
824
+
825
+
826
+ def precompile(source: str) -> PrecompiledPattern:
827
+ """
828
+ Precompile CSSL source for repeated execution.
829
+
830
+ Returns a PrecompiledPattern that can be executed multiple times
831
+ without re-parsing.
832
+ """
833
+ return PrecompiledPattern(source)