Alikhani099961 commited on
Commit
16c6a84
·
verified ·
1 Parent(s): 417524f

Update pine_parser.py

Browse files
Files changed (1) hide show
  1. pine_parser.py +151 -113
pine_parser.py CHANGED
@@ -1,120 +1,158 @@
1
- import streamlit as st
2
- from pine_parser import PineScriptParser
3
- import os
4
- from dotenv import load_dotenv
5
 
6
- # Load environment variables
7
- load_dotenv()
8
-
9
- # Configure page
10
- st.set_page_config(
11
- page_title="Pine Script Analyzer Pro",
12
- page_icon="🧠",
13
- layout="wide"
14
- )
15
-
16
- # Custom CSS for better UI
17
- st.markdown("""
18
- <style>
19
- .code-container {
20
- border-radius: 0.5rem;
21
- padding: 1rem;
22
- background-color: #f8f9fa;
23
- border: 1px solid #dee2e6;
24
- }
25
- .fixed-code {
26
- background-color: #e8f5e9;
27
- }
28
- .error-message {
29
- color: #d32f2f;
30
- font-weight: bold;
31
- }
32
- .warning-message {
33
- color: #ffa000;
34
- }
35
- </style>
36
- """, unsafe_allow_html=True)
37
-
38
- def main():
39
- st.title("🧠 Pine Script Analyzer Pro")
40
- st.caption("Professional-grade analysis and optimization for TradingView Pine Script")
41
-
42
- with st.expander("📝 Paste Your Pine Script Code", expanded=True):
43
- user_code = st.text_area(
44
- "Paste your Pine Script code here:",
45
- height=300,
46
- placeholder="""//@version=5
47
- indicator("My Indicator")
48
- plot(close)""",
49
- label_visibility="collapsed"
50
- )
51
-
52
- if st.button("🔍 Analyze & Optimize Code", use_container_width=True):
53
- if not user_code.strip():
54
- st.error("Please enter Pine Script code to analyze")
55
- else:
56
- with st.spinner("Analyzing code with professional-grade tools..."):
57
- try:
58
- parser = PineScriptParser(user_code)
59
- results = {
60
- "version": parser.detect_version() or "Unknown",
61
- "errors": parser.find_errors(),
62
- "warnings": parser.find_warnings(),
63
- "optimizations": parser.find_optimizations(),
64
- "fixed_code": parser.generate_fixed_code()
65
- }
66
-
67
- display_results(results)
68
-
69
- except Exception as e:
70
- st.error(f"Professional analysis failed: {str(e)}")
71
-
72
- def display_results(results):
73
- """Display analysis results in professional UI"""
74
 
75
- # Version and summary
76
- col1, col2 = st.columns(2)
77
- with col1:
78
- st.metric("Detected Version", results["version"])
79
- with col2:
80
- st.metric("Issues Found", f"{len(results['errors'])} Errors, {len(results['warnings'])} Warnings")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
81
 
82
- # Tabs for different analysis aspects
83
- tab1, tab2, tab3, tab4 = st.tabs(["🚨 Errors", "⚠️ Warnings", "✨ Optimizations", "✅ Fixed Code"])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
84
 
85
- with tab1:
86
- if results["errors"]:
87
- for error in results["errors"]:
88
- st.markdown(f'<p class="error-message">• {error}</p>', unsafe_allow_html=True)
89
- else:
90
- st.success("No critical errors found!")
 
 
 
 
 
 
 
91
 
92
- with tab2:
93
- if results["warnings"]:
94
- for warning in results["warnings"]:
95
- st.markdown(f'<p class="warning-message">• {warning}</p>', unsafe_allow_html=True)
96
- else:
97
- st.success("No warnings detected!")
 
 
 
98
 
99
- with tab3:
100
- if results["optimizations"]:
101
- for opt in results["optimizations"]:
102
- st.info(f"• {opt}")
103
- else:
104
- st.success("Code is already optimized!")
 
 
 
 
 
 
 
 
 
 
 
105
 
106
- with tab4:
107
- st.markdown('<div class="code-container fixed-code">', unsafe_allow_html=True)
108
- st.code(results["fixed_code"], language="javascript")
109
- st.markdown('</div>', unsafe_allow_html=True)
110
-
111
- st.download_button(
112
- "📋 Download Optimized Code",
113
- data=results["fixed_code"],
114
- file_name="optimized_script.pine",
115
- mime="text/plain",
116
- use_container_width=True
117
- )
118
-
119
- if __name__ == "__main__":
120
- main()
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import re
2
+ from typing import List, Dict, Optional, Tuple
3
+ import numpy as np
 
4
 
5
+ class PineScriptParser:
6
+ """Professional-grade Pine Script analyzer with advanced features"""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7
 
8
+ def __init__(self, code: str):
9
+ self.original_code = code
10
+ self.code = code.strip()
11
+ self.version = self._detect_version()
12
+ self.errors: List[str] = []
13
+ self.warnings: List[str] = []
14
+ self.optimizations: List[str] = []
15
+ self.formatting_issues: List[str] = []
16
+ self._analyzed = False
17
+
18
+ def _detect_version(self) -> Optional[str]:
19
+ """Detect Pine Script version with advanced pattern matching"""
20
+ patterns = [
21
+ r'//\s*@version\s*=\s*(\d+)',
22
+ r'//\s*version\s*=\s*(\d+)',
23
+ r'@version\s*(\d+)'
24
+ ]
25
+
26
+ for pattern in patterns:
27
+ match = re.search(pattern, self.code, re.IGNORECASE)
28
+ if match:
29
+ version = match.group(1)
30
+ if version in ['4', '5', '6']:
31
+ return version
32
+ return None
33
+
34
+ def _full_analysis(self):
35
+ """Comprehensive code analysis"""
36
+ if self._analyzed:
37
+ return
38
+
39
+ self._check_syntax()
40
+ self._check_semantics()
41
+ self._check_performance()
42
+ self._check_formatting()
43
+ self._analyzed = True
44
 
45
+ def find_errors(self) -> List[str]:
46
+ """Find all syntax and semantic errors"""
47
+ self._full_analysis()
48
+ return self.errors
49
+
50
+ def find_warnings(self) -> List[str]:
51
+ """Find all warnings and deprecations"""
52
+ self._full_analysis()
53
+ return self.warnings
54
+
55
+ def find_optimizations(self) -> List[str]:
56
+ """Find performance optimization opportunities"""
57
+ self._full_analysis()
58
+ return self.optimizations
59
+
60
+ def get_formatting_suggestions(self) -> List[str]:
61
+ """Get professional formatting recommendations"""
62
+ self._full_analysis()
63
+ return self.formatting_issues
64
+
65
+ def _check_syntax(self):
66
+ """Advanced syntax validation"""
67
+ # Check for version declaration
68
+ if not self.version:
69
+ self.errors.append("Critical: Missing version declaration (//@version=X)")
70
+
71
+ # Check for required components
72
+ required_patterns = [
73
+ (r'(indicator|strategy)\s*\(', "Missing indicator/strategy declaration"),
74
+ (r'plot|barcolor|fill', "No output functions found (plot, barcolor, etc.)")
75
+ ]
76
+
77
+ for pattern, message in required_patterns:
78
+ if not re.search(pattern, self.code):
79
+ self.warnings.append(message)
80
+
81
+ # Check bracket balance
82
+ if self.code.count('(') != self.code.count(')'):
83
+ self.errors.append("Syntax Error: Unbalanced parentheses")
84
+
85
+ if self.code.count('[') != self.code.count(']'):
86
+ self.errors.append("Syntax Error: Unbalanced square brackets")
87
+
88
+ if self.code.count('{') != self.code.count('}'):
89
+ self.errors.append("Syntax Error: Unbalanced curly braces")
90
 
91
+ def _check_semantics(self):
92
+ """Deep semantic analysis"""
93
+ # Check for common semantic issues
94
+ if re.search(r'close\s*[+\-*/]\s*open', self.code):
95
+ self.optimizations.append("Consider using 'close - open' instead of arithmetic operations for better performance")
96
+
97
+ if re.search(r'length\s*=\s*\d+', self.code):
98
+ self.warnings.append("Warning: Hardcoded lengths should be configurable via inputs")
99
+
100
+ # Check for version-specific issues
101
+ if self.version == '4':
102
+ if re.search(r'request\.', self.code):
103
+ self.errors.append("Error: request.* functions are not available in v4")
104
 
105
+ def _check_performance(self):
106
+ """Performance optimization checks"""
107
+ # Check for inefficient loops
108
+ if re.search(r'for\s+i\s+from\s+\d+\s+to\s+\d+', self.code):
109
+ self.optimizations.append("Optimization: Consider using array functions instead of for-loops for better performance")
110
+
111
+ # Check for redundant calculations
112
+ if re.search(r'sma\(sma\(', self.code):
113
+ self.optimizations.append("Optimization: Nested SMA calls can be combined for better efficiency")
114
 
115
+ def _check_formatting(self):
116
+ """Professional formatting checks"""
117
+ lines = self.code.split('\n')
118
+
119
+ # Check indentation
120
+ indent_problems = 0
121
+ for i, line in enumerate(lines):
122
+ if line.strip() and not line.startswith(' '):
123
+ indent_problems += 1
124
+
125
+ if indent_problems > len(lines) * 0.1: # More than 10% lines have issues
126
+ self.formatting_issues.append(f"Formatting: {indent_problems} lines with incorrect indentation (recommend 4 spaces)")
127
+
128
+ # Check line length
129
+ long_lines = [i+1 for i, line in enumerate(lines) if len(line) > 120]
130
+ if long_lines:
131
+ self.formatting_issues.append(f"Formatting: Long lines detected (lines: {', '.join(map(str, long_lines))})")
132
 
133
+ def generate_fixed_code(self) -> str:
134
+ """Generate professionally formatted and optimized code"""
135
+ self._full_analysis()
136
+
137
+ # Basic formatting fixes
138
+ fixed_code = []
139
+ lines = self.original_code.split('\n')
140
+
141
+ # Apply consistent indentation
142
+ indent_level = 0
143
+ for line in lines:
144
+ stripped = line.strip()
145
+ if stripped.startswith(('if', 'for', 'while', 'else')) and stripped.endswith(':'):
146
+ fixed_code.append(' ' * indent_level + stripped)
147
+ indent_level += 1
148
+ elif stripped in ('end', 'else'):
149
+ indent_level = max(0, indent_level - 1)
150
+ fixed_code.append(' ' * indent_level + stripped)
151
+ else:
152
+ fixed_code.append(' ' * indent_level + stripped)
153
+
154
+ # Ensure version declaration
155
+ if not self.version:
156
+ fixed_code.insert(0, "//@version=5")
157
+
158
+ return '\n'.join(fixed_code)