Spaces:
Runtime error
Runtime error
| import re | |
| from typing import List, Dict, Optional, Tuple | |
| import numpy as np | |
| class PineScriptParser: | |
| """Professional-grade Pine Script analyzer with advanced features""" | |
| def __init__(self, code: str): | |
| self.original_code = code | |
| self.code = code.strip() | |
| self.version = self._detect_version() | |
| self.errors: List[str] = [] | |
| self.warnings: List[str] = [] | |
| self.optimizations: List[str] = [] | |
| self.formatting_issues: List[str] = [] | |
| self._analyzed = False | |
| def _detect_version(self) -> Optional[str]: | |
| """Detect Pine Script version with advanced pattern matching""" | |
| patterns = [ | |
| r'//\s*@version\s*=\s*(\d+)', | |
| r'//\s*version\s*=\s*(\d+)', | |
| r'@version\s*(\d+)' | |
| ] | |
| for pattern in patterns: | |
| match = re.search(pattern, self.code, re.IGNORECASE) | |
| if match: | |
| version = match.group(1) | |
| if version in ['4', '5', '6']: | |
| return version | |
| return None | |
| def _full_analysis(self): | |
| """Comprehensive code analysis""" | |
| if self._analyzed: | |
| return | |
| self._check_syntax() | |
| self._check_semantics() | |
| self._check_performance() | |
| self._check_formatting() | |
| self._analyzed = True | |
| def find_errors(self) -> List[str]: | |
| """Find all syntax and semantic errors""" | |
| self._full_analysis() | |
| return self.errors | |
| def find_warnings(self) -> List[str]: | |
| """Find all warnings and deprecations""" | |
| self._full_analysis() | |
| return self.warnings | |
| def find_optimizations(self) -> List[str]: | |
| """Find performance optimization opportunities""" | |
| self._full_analysis() | |
| return self.optimizations | |
| def get_formatting_suggestions(self) -> List[str]: | |
| """Get professional formatting recommendations""" | |
| self._full_analysis() | |
| return self.formatting_issues | |
| def _check_syntax(self): | |
| """Advanced syntax validation""" | |
| # Check for version declaration | |
| if not self.version: | |
| self.errors.append("Critical: Missing version declaration (//@version=X)") | |
| # Check for required components | |
| required_patterns = [ | |
| (r'(indicator|strategy)\s*\(', "Missing indicator/strategy declaration"), | |
| (r'plot|barcolor|fill', "No output functions found (plot, barcolor, etc.)") | |
| ] | |
| for pattern, message in required_patterns: | |
| if not re.search(pattern, self.code): | |
| self.warnings.append(message) | |
| # Check bracket balance | |
| if self.code.count('(') != self.code.count(')'): | |
| self.errors.append("Syntax Error: Unbalanced parentheses") | |
| if self.code.count('[') != self.code.count(']'): | |
| self.errors.append("Syntax Error: Unbalanced square brackets") | |
| if self.code.count('{') != self.code.count('}'): | |
| self.errors.append("Syntax Error: Unbalanced curly braces") | |
| def _check_semantics(self): | |
| """Deep semantic analysis""" | |
| # Check for common semantic issues | |
| if re.search(r'close\s*[+\-*/]\s*open', self.code): | |
| self.optimizations.append("Consider using 'close - open' instead of arithmetic operations for better performance") | |
| if re.search(r'length\s*=\s*\d+', self.code): | |
| self.warnings.append("Warning: Hardcoded lengths should be configurable via inputs") | |
| # Check for version-specific issues | |
| if self.version == '4': | |
| if re.search(r'request\.', self.code): | |
| self.errors.append("Error: request.* functions are not available in v4") | |
| def _check_performance(self): | |
| """Performance optimization checks""" | |
| # Check for inefficient loops | |
| if re.search(r'for\s+i\s+from\s+\d+\s+to\s+\d+', self.code): | |
| self.optimizations.append("Optimization: Consider using array functions instead of for-loops for better performance") | |
| # Check for redundant calculations | |
| if re.search(r'sma\(sma\(', self.code): | |
| self.optimizations.append("Optimization: Nested SMA calls can be combined for better efficiency") | |
| def _check_formatting(self): | |
| """Professional formatting checks""" | |
| lines = self.code.split('\n') | |
| # Check indentation | |
| indent_problems = 0 | |
| for i, line in enumerate(lines): | |
| if line.strip() and not line.startswith(' '): | |
| indent_problems += 1 | |
| if indent_problems > len(lines) * 0.1: # More than 10% lines have issues | |
| self.formatting_issues.append(f"Formatting: {indent_problems} lines with incorrect indentation (recommend 4 spaces)") | |
| # Check line length | |
| long_lines = [i+1 for i, line in enumerate(lines) if len(line) > 120] | |
| if long_lines: | |
| self.formatting_issues.append(f"Formatting: Long lines detected (lines: {', '.join(map(str, long_lines))})") | |
| def generate_fixed_code(self) -> str: | |
| """Generate professionally formatted and optimized code""" | |
| self._full_analysis() | |
| # Basic formatting fixes | |
| fixed_code = [] | |
| lines = self.original_code.split('\n') | |
| # Apply consistent indentation | |
| indent_level = 0 | |
| for line in lines: | |
| stripped = line.strip() | |
| if stripped.startswith(('if', 'for', 'while', 'else')) and stripped.endswith(':'): | |
| fixed_code.append(' ' * indent_level + stripped) | |
| indent_level += 1 | |
| elif stripped in ('end', 'else'): | |
| indent_level = max(0, indent_level - 1) | |
| fixed_code.append(' ' * indent_level + stripped) | |
| else: | |
| fixed_code.append(' ' * indent_level + stripped) | |
| # Ensure version declaration | |
| if not self.version: | |
| fixed_code.insert(0, "//@version=5") | |
| return '\n'.join(fixed_code) |