mirror of
https://github.com/0x5t4l1n/Nex.git
synced 2026-05-26 19:36:35 +00:00
373 lines
12 KiB
Python
373 lines
12 KiB
Python
import sys
|
|
import re
|
|
from PyQt5.QtWidgets import QApplication, QMainWindow, QVBoxLayout, QPushButton, QLineEdit, QTextEdit, QLabel, QMenuBar, QMenu, QAction, QFileDialog, QMessageBox, QWidget, QDialog, QDialogButtonBox, QTabWidget, QHBoxLayout
|
|
from PyQt5.QtCore import QThread, pyqtSignal
|
|
from PyQt5.QtCore import Qt
|
|
import time
|
|
|
|
# Define black theme stylesheet
|
|
black_stylesheet = """
|
|
QMainWindow {
|
|
background-color: #2E2E2E;
|
|
color: white;
|
|
}
|
|
QTextEdit, QLineEdit {
|
|
background-color: #444444;
|
|
color: white;
|
|
border: 1px solid #666666;
|
|
}
|
|
QTextEdit {
|
|
border-radius: 5px;
|
|
}
|
|
QLabel {
|
|
color: white;
|
|
}
|
|
QPushButton {
|
|
background-color: #5A5A5A;
|
|
color: white;
|
|
border: 1px solid #777777;
|
|
border-radius: 5px;
|
|
padding: 5px 15px;
|
|
}
|
|
QPushButton:hover {
|
|
background-color: #888888;
|
|
}
|
|
QMenuBar {
|
|
background-color: #333333;
|
|
color: white;
|
|
}
|
|
QMenuBar::item:selected {
|
|
background-color: #555555;
|
|
}
|
|
QMenu {
|
|
background-color: #333333;
|
|
color: white;
|
|
}
|
|
QMenu::item:selected {
|
|
background-color: #555555;
|
|
}
|
|
QDialog {
|
|
background-color: #333333;
|
|
color: white;
|
|
}
|
|
|
|
"""
|
|
|
|
def evaluate_expression(expr):
|
|
"""Evaluate basic arithmetic expressions."""
|
|
try:
|
|
expr = expr.strip()
|
|
if not re.match(r"^[\d+\-*/().\s]+$", expr):
|
|
return f"Error: Invalid arithmetic expression - {expr}"
|
|
|
|
# Evaluate the expression using eval (Python's built-in function)
|
|
return str(eval(expr))
|
|
except ZeroDivisionError:
|
|
return "Error: Division by zero"
|
|
except Exception:
|
|
return f"Error: Invalid arithmetic expression - {expr}"
|
|
|
|
def is_valid_string(value):
|
|
"""Check if the value is a properly formatted string (enclosed in double quotes)."""
|
|
return value.startswith('"') and value.endswith('"')
|
|
|
|
def is_valid_number(value):
|
|
"""Check if the value is a valid number (integer or float)."""
|
|
return re.match(r"^\d+(\.\d+)?$", value) is not None
|
|
|
|
def ullitu(prompt):
|
|
"""Simulate user input dynamically."""
|
|
return prompt # Simply return the prompt as an example of how user would input.
|
|
|
|
def parse_nex(code, user_input=None):
|
|
"""Parse and execute Nex syntax, including loops and dynamic input."""
|
|
statements = code.split("\n")
|
|
results = []
|
|
|
|
for statement in statements:
|
|
statement = statement.strip()
|
|
|
|
if statement.startswith("accu("):
|
|
# Handle accu() as a print statement
|
|
content = re.findall(r'accu\((.*?)\)', statement)
|
|
if content:
|
|
parts = [p.strip() for p in content[0].split(",")]
|
|
output = ""
|
|
for part in parts:
|
|
if is_valid_string(part):
|
|
output += part[1:-1] # Remove quotes and add to output
|
|
elif is_valid_number(part):
|
|
output += part
|
|
elif re.match(r"[\d+\-*/().\s]+", part):
|
|
output += evaluate_expression(part)
|
|
elif "ullitu" in part:
|
|
prompt = re.findall(r'ullitu\("(.*?)"\)', part)
|
|
if prompt:
|
|
user_input_value = user_input # Get the user input
|
|
output += f" {prompt[0]}: {user_input_value}" # Display user input
|
|
results.append(output)
|
|
|
|
elif "for" in statement:
|
|
# Handle for loop
|
|
loop_content = re.findall(r'for\s+(\w+)\s+in\s+range\((.*?)\):\s*(.*)', statement)
|
|
if loop_content:
|
|
var, range_values, body = loop_content[0]
|
|
start, end = [int(x) for x in range_values.split(",")]
|
|
loop_output = []
|
|
for i in range(start, end):
|
|
loop_output.append(parse_nex(body.replace(var, str(i)), user_input))
|
|
results.append(" ".join(loop_output))
|
|
|
|
elif "while" in statement:
|
|
# Handle while loop
|
|
loop_content = re.findall(r'while\s+(.*):\s*(.*)', statement)
|
|
if loop_content:
|
|
condition, body = loop_content[0]
|
|
loop_output = []
|
|
while eval(condition):
|
|
loop_output.append(parse_nex(body, user_input))
|
|
results.append(" ".join(loop_output))
|
|
|
|
else:
|
|
# If the statement is just a regular expression or text
|
|
results.append(f"Error: Invalid content - {statement}")
|
|
|
|
return "\n".join(results)
|
|
|
|
class CodeExecutionThread(QThread):
|
|
"""Thread for executing code in the background to keep UI responsive."""
|
|
result_ready = pyqtSignal(str)
|
|
|
|
def __init__(self, code, user_input):
|
|
super().__init__()
|
|
self.code = code
|
|
self.user_input = user_input
|
|
|
|
def run(self):
|
|
"""Run code execution in a separate thread."""
|
|
try:
|
|
time.sleep(1) # Simulate processing time
|
|
result = parse_nex(self.code, self.user_input)
|
|
self.result_ready.emit(result)
|
|
except Exception as e:
|
|
self.result_ready.emit(f"Error: {str(e)}")
|
|
|
|
class HelpDialog(QDialog):
|
|
"""Dialog to show help information about the application."""
|
|
def __init__(self):
|
|
super().__init__()
|
|
self.setWindowTitle("Help")
|
|
self.setGeometry(150, 150, 500, 300)
|
|
|
|
# Create layout
|
|
layout = QVBoxLayout()
|
|
|
|
# Help content
|
|
help_text = (
|
|
""" Nex Help:
|
|
|
|
1. Write your code in the text area (e.g., for loops, while loops, accu for print statements).
|
|
|
|
2. The 'accu()' function works as a print statement. Example: accu('Hello World')
|
|
|
|
3. You can use for loops like:
|
|
for i in range(0, 5):
|
|
accu('Iteration: ' + str(i))
|
|
|
|
4. You can use while loops like:
|
|
while i < 5:
|
|
accu('Iteration: ' + str(i))
|
|
|
|
5. Use 'ullitu()' for dynamic input prompts. Example: ullitu('Enter a number')
|
|
|
|
6. You can load/save your code with the 'File' menu.
|
|
|
|
7. For more information, please refer to the documentation.
|
|
|
|
8. Use 'if' statements for conditional logic. Example:
|
|
if i < 5:
|
|
accu('i is less than 5')
|
|
|
|
9. To create functions, use the syntax:
|
|
def function_name(parameters):
|
|
# function body
|
|
|
|
10. You can call a function like this:
|
|
function_name(arguments)
|
|
|
|
11. To use variables, simply assign them with '=':
|
|
x = 5
|
|
|
|
"""
|
|
|
|
)
|
|
|
|
# Text display widget for help content
|
|
help_label = QLabel(help_text, self)
|
|
layout.addWidget(help_label)
|
|
|
|
# OK button to close the help dialog
|
|
button_box = QDialogButtonBox(QDialogButtonBox.Ok)
|
|
button_box.accepted.connect(self.accept)
|
|
layout.addWidget(button_box)
|
|
|
|
self.setLayout(layout)
|
|
|
|
class CompilerGUI(QMainWindow):
|
|
def __init__(self):
|
|
super().__init__()
|
|
|
|
self.initUI()
|
|
|
|
def initUI(self):
|
|
# Apply black theme stylesheet
|
|
self.setStyleSheet(black_stylesheet)
|
|
|
|
# Create layout
|
|
layout = QVBoxLayout()
|
|
|
|
# Create input area for user to input code
|
|
self.code_input = QTextEdit(self)
|
|
self.code_input.setPlaceholderText("") # Remove the placeholder text
|
|
self.code_input.setStyleSheet("QTextEdit {border: none; padding: 10px;}") # Remove box inside text area
|
|
layout.addWidget(self.code_input)
|
|
|
|
# Create input for the user to enter dynamic values
|
|
self.user_input_label = QLabel("Enter a number or text:", self)
|
|
layout.addWidget(self.user_input_label)
|
|
|
|
self.user_input_field = QLineEdit(self)
|
|
self.user_input_field.setPlaceholderText("") # Remove the placeholder text
|
|
layout.addWidget(self.user_input_field)
|
|
|
|
# Create run button
|
|
self.run_button = QPushButton("Run", self)
|
|
self.run_button.clicked.connect(self.run_code)
|
|
layout.addWidget(self.run_button)
|
|
|
|
# Create a tab widget for output
|
|
self.tab_widget = QTabWidget(self)
|
|
layout.addWidget(self.tab_widget)
|
|
|
|
# Set central widget for layout
|
|
central_widget = QWidget(self)
|
|
central_widget.setLayout(layout)
|
|
self.setCentralWidget(central_widget)
|
|
|
|
# Add Menu Bar
|
|
menubar = self.menuBar()
|
|
|
|
file_menu = menubar.addMenu('File')
|
|
|
|
open_action = QAction('Open', self)
|
|
open_action.triggered.connect(self.open_file)
|
|
file_menu.addAction(open_action)
|
|
|
|
save_action = QAction('Save', self)
|
|
save_action.triggered.connect(self.save_file)
|
|
file_menu.addAction(save_action)
|
|
|
|
file_menu.addSeparator()
|
|
|
|
close_action = QAction('Close', self)
|
|
close_action.triggered.connect(self.close)
|
|
file_menu.addAction(close_action)
|
|
|
|
help_menu = menubar.addMenu('Help')
|
|
help_action = QAction('Help', self)
|
|
help_action.triggered.connect(self.show_help)
|
|
help_menu.addAction(help_action)
|
|
|
|
# Set window properties
|
|
self.setWindowTitle('Nex')
|
|
self.setGeometry(100, 100, 600, 400)
|
|
self.show()
|
|
|
|
def run_code(self):
|
|
code = self.code_input.toPlainText() # Get code from input field
|
|
user_input_value = self.user_input_field.text() # Get user input value
|
|
|
|
# Disable input and button to prevent re-triggering during execution
|
|
self.code_input.setDisabled(True)
|
|
self.user_input_field.setDisabled(True)
|
|
self.run_button.setDisabled(True)
|
|
|
|
# Start code execution in a background thread
|
|
self.execution_thread = CodeExecutionThread(code, user_input_value)
|
|
self.execution_thread.result_ready.connect(self.display_result)
|
|
self.execution_thread.start()
|
|
|
|
def display_result(self, result):
|
|
"""Display the result in a new tab with a cancel button to close it."""
|
|
new_tab = QWidget()
|
|
layout = QVBoxLayout()
|
|
|
|
# Create a horizontal layout to add the close button and output area
|
|
close_layout = QHBoxLayout()
|
|
close_button = QPushButton("Close Tab", self)
|
|
close_button.clicked.connect(self.close_tab)
|
|
close_layout.addWidget(close_button)
|
|
|
|
output_area = QTextEdit()
|
|
output_area.setPlainText(result)
|
|
output_area.setReadOnly(True)
|
|
output_area.setStyleSheet("""
|
|
QTextEdit {
|
|
background-color: #121212;
|
|
color: #A9D0D1;
|
|
border: 1px solid #333333;
|
|
border-radius: 8px;
|
|
padding: 10px;
|
|
font-family: "Courier New", Courier, monospace;
|
|
font-size: 14px;
|
|
}
|
|
""")
|
|
close_layout.addWidget(output_area)
|
|
|
|
layout.addLayout(close_layout)
|
|
new_tab.setLayout(layout)
|
|
|
|
# Add the new tab
|
|
tab_name = "Output " + str(self.tab_widget.count() + 1)
|
|
self.tab_widget.addTab(new_tab, tab_name)
|
|
|
|
# Re-enable inputs and button
|
|
self.code_input.setEnabled(True)
|
|
self.user_input_field.setEnabled(True)
|
|
self.run_button.setEnabled(True)
|
|
|
|
def close_tab(self):
|
|
"""Close the currently selected tab."""
|
|
current_index = self.tab_widget.currentIndex()
|
|
self.tab_widget.removeTab(current_index)
|
|
|
|
def open_file(self):
|
|
"""Open a file dialog to select a file and load the content."""
|
|
options = QFileDialog.Options()
|
|
file_name, _ = QFileDialog.getOpenFileName(self, "Open File", "", "Text Files (*.txt);;All Files (*)", options=options)
|
|
if file_name:
|
|
with open(file_name, 'r') as file:
|
|
code = file.read()
|
|
self.code_input.setPlainText(code)
|
|
|
|
def save_file(self):
|
|
"""Save the content of the text area to a file."""
|
|
options = QFileDialog.Options()
|
|
file_name, _ = QFileDialog.getSaveFileName(self, "Save File", "", "Text Files (*.txt);;All Files (*)", options=options)
|
|
if file_name:
|
|
with open(file_name, 'w') as file:
|
|
code = self.code_input.toPlainText()
|
|
file.write(code)
|
|
|
|
def show_help(self):
|
|
"""Show help dialog with detailed information."""
|
|
help_dialog = HelpDialog()
|
|
help_dialog.exec_()
|
|
|
|
|
|
# Main execution
|
|
if __name__ == '__main__':
|
|
app = QApplication(sys.argv)
|
|
ex = CompilerGUI()
|
|
sys.exit(app.exec_())
|