文件
SunsetCodeLang/plugins/basic.py
T

1174 行
51 KiB
Python

# Basic syntax plugin for SunsetCodeLang
import requests
class BasicPlugin:
def __init__(self, interpreter):
self.interpreter = interpreter
# 预定义的颜色名称映射到ANSI转义码
self.color_names = {
# 基础颜色
'black': '30',
'red': '31',
'green': '32',
'yellow': '33',
'blue': '34',
'magenta': '35',
'cyan': '36',
'white': '37',
# 亮色
'bright_black': '90',
'bright_red': '91',
'bright_green': '92',
'bright_yellow': '93',
'bright_blue': '94',
'bright_magenta': '95',
'bright_cyan': '96',
'bright_white': '97'
}
# 类和函数定义
self.classes = {}
self.functions = {}
# 用于解析的辅助变量
self.tokens = []
self.current_pos = 0
def consume(self):
"""Consume and return the current token"""
if self.current_pos < len(self.tokens):
token = self.tokens[self.current_pos]
self.current_pos += 1
return token
return None
def peek(self, offset=0):
"""Peek at the token at the given offset without consuming it"""
if self.current_pos + offset < len(self.tokens):
return self.tokens[self.current_pos + offset]
return None
def register_syntax(self):
"""Register basic syntax handlers"""
# This will be called by the interpreter to register syntax handlers
pass
def parse_statement(self, tokens, pos):
"""Parse basic statements"""
# 不修改全局状态,使用局部变量
local_pos = pos
def peek(offset=0):
if local_pos + offset < len(tokens):
return tokens[local_pos + offset]
return None
def consume():
nonlocal local_pos
if local_pos < len(tokens):
token = tokens[local_pos]
local_pos += 1
return token
return None
token = peek()
if not token:
return None, pos
if token[0] == 'IDENTIFIER' and token[1] == 'set':
# Variable declaration: set a | a : 1
consume() # Consume 'set'
var_name = consume()[1] # Get variable name
if peek() and peek()[0] == 'SEPARATOR':
consume() # Consume '|'
# Check if next is the same variable for assignment
if peek() and peek()[0] == 'IDENTIFIER' and peek()[1] == var_name:
consume() # Consume variable name
if peek() and peek()[0] == 'ASSIGN':
consume() # Consume ':'
expr, new_pos = self.interpreter.parse_expression(tokens, local_pos)
if expr:
local_pos = new_pos
return ('ASSIGN', var_name, expr), local_pos
elif token[0] == 'IDENTIFIER' and token[1] == 'sout':
# Print statement: sout : "Hello World!"
consume() # Consume 'sout'
if peek() and peek()[0] == 'ASSIGN':
# Handle sout : "Hello World!"
consume() # Consume ':'
# 使用 parse_expression 解析完整的表达式
expr, new_pos = self.interpreter.parse_expression(tokens, local_pos)
if expr:
local_pos = new_pos
return ('PRINT', expr), local_pos
elif token[0] == 'IDENTIFIER' and token[1] == 'soutc':
# Color print statement: soutc : color : text
consume() # Consume 'soutc'
if peek() and peek()[0] == 'ASSIGN':
consume() # Consume ':'
# Get color specification
color_token = consume()
if not color_token:
return None, pos
# Check for another colon before text
if not (peek() and peek()[0] == 'ASSIGN'):
return None, pos
consume() # Consume ':'
# 使用 parse_expression 解析完整的文本表达式
text_expr, new_pos = self.interpreter.parse_expression(tokens, local_pos)
if text_expr:
local_pos = new_pos
return ('COLOR_OUTPUT', color_token, text_expr), local_pos
elif token[0] == 'IDENTIFIER' and token[1] == 'start':
# Run another SCL file: start : "file.scl"
consume() # Consume 'start'
if peek() and peek()[0] == 'ASSIGN':
# Handle start : "file.scl"
consume() # Consume ':'
# 直接获取下一个令牌作为文件路径
if local_pos < len(tokens):
file_path = tokens[local_pos]
local_pos += 1
return ('START', file_path), local_pos
elif token[0] == 'IDENTIFIER' and token[1] == 'sif':
# If statement: sif condition | ...
consume() # Consume 'sif'
# Find separator '|' for condition
cond_end = local_pos
while cond_end < len(tokens) and not (tokens[cond_end][0] == 'SEPARATOR' and tokens[cond_end][1] == '|'):
cond_end += 1
if cond_end >= len(tokens):
return None, pos
# Extract condition
condition = tokens[local_pos:cond_end]
local_pos = cond_end + 1 # Skip '|'
# Parse if body
if_body = []
body_end = local_pos
while body_end < len(tokens):
token = tokens[body_end]
if token[0] == 'IDENTIFIER' and token[1] in ['seif', 'sel', 'end']:
break
stmt, new_pos = self.parse_statement(tokens, body_end)
if stmt:
if_body.append(stmt)
body_end = new_pos
else:
body_end += 1
local_pos = body_end
# Parse elif clauses
elif_clauses = []
while local_pos < len(tokens) and tokens[local_pos][0] == 'IDENTIFIER' and tokens[local_pos][1] == 'seif':
local_pos += 1 # Skip 'seif'
# Find separator '|' for elif condition
elif_cond_end = local_pos
while elif_cond_end < len(tokens) and not (tokens[elif_cond_end][0] == 'SEPARATOR' and tokens[elif_cond_end][1] == '|'):
elif_cond_end += 1
if elif_cond_end >= len(tokens):
return None, pos
# Extract elif condition
elif_condition = tokens[local_pos:elif_cond_end]
local_pos = elif_cond_end + 1 # Skip '|'
# Parse elif body
elif_body = []
elif_body_end = local_pos
while elif_body_end < len(tokens):
token = tokens[elif_body_end]
if token[0] == 'IDENTIFIER' and token[1] in ['seif', 'sel', 'end']:
break
stmt, new_pos = self.parse_statement(tokens, elif_body_end)
if stmt:
elif_body.append(stmt)
elif_body_end = new_pos
else:
elif_body_end += 1
elif_clauses.append((elif_condition, elif_body))
local_pos = elif_body_end
# Parse else clause
else_body = []
if local_pos < len(tokens) and tokens[local_pos][0] == 'IDENTIFIER' and tokens[local_pos][1] == 'sel':
local_pos += 1 # Skip 'sel'
# Check for separator '|'
if local_pos >= len(tokens) or not (tokens[local_pos][0] == 'SEPARATOR' and tokens[local_pos][1] == '|'):
return None, pos
local_pos += 1 # Skip '|'
# Parse else body
else_body_end = local_pos
while else_body_end < len(tokens):
token = tokens[else_body_end]
if token[0] == 'IDENTIFIER' and token[1] == 'end':
break
stmt, new_pos = self.parse_statement(tokens, else_body_end)
if stmt:
else_body.append(stmt)
else_body_end = new_pos
else:
else_body_end += 1
local_pos = else_body_end
# Check for end statement
if local_pos >= len(tokens) or not (tokens[local_pos][0] == 'IDENTIFIER' and tokens[local_pos][1] == 'end'):
return None, pos
local_pos += 1 # Skip 'end'
return ('IF_ELSE', condition, if_body, elif_clauses, else_body), local_pos
elif token[0] == 'IDENTIFIER' and token[1] == 'swhi':
# While statement: swhi condition | ...
consume() # Consume 'swhi'
# Find separator '|' for condition
cond_end = local_pos
while cond_end < len(tokens) and not (tokens[cond_end][0] == 'SEPARATOR' and tokens[cond_end][1] == '|'):
cond_end += 1
if cond_end >= len(tokens):
return None, pos
# Extract condition
condition = tokens[local_pos:cond_end]
local_pos = cond_end + 1 # Skip '|'
# Parse while body
body = []
body_end = local_pos
while body_end < len(tokens):
token = tokens[body_end]
if token[0] == 'IDENTIFIER' and token[1] == 'end':
break
stmt, new_pos = self.parse_statement(tokens, body_end)
if stmt:
body.append(stmt)
body_end = new_pos
else:
body_end += 1
local_pos = body_end
# Check for end statement
if local_pos >= len(tokens) or not (tokens[local_pos][0] == 'IDENTIFIER' and tokens[local_pos][1] == 'end'):
return None, pos
local_pos += 1 # Skip 'end'
return ('WHILE', condition, body), local_pos
elif token[0] == 'IDENTIFIER' and token[1] == 'break':
# Break statement: break
consume() # Consume 'break'
return ('BREAK',), local_pos
elif token[0] == 'IDENTIFIER' and token[1] == 'sde':
# Function definition or call: sde add : ... end or sde run<add>
consume() # Consume 'sde'
# Check for function call: sde run<add>
next_token = peek()
if next_token and next_token[0] == 'IDENTIFIER' and next_token[1] == 'run':
consume() # Consume 'run'
# Check for <function_name>
if peek() and peek()[0] == 'OPERATOR' and peek()[1] == '<':
consume() # Consume '<'
func_token = peek()
if func_token and func_token[0] == 'IDENTIFIER':
func_name = func_token[1]
consume() # Consume function name
if peek() and peek()[0] == 'OPERATOR' and peek()[1] == '>':
consume() # Consume '>'
return ('FUNCTION_CALL', func_name), local_pos
# Check for function definition: sde add :
func_token = peek()
if not func_token or func_token[0] != 'IDENTIFIER':
return None, pos
func_name = func_token[1]
consume() # Consume function name
# Check for assignment operator
assign_token = peek()
if not assign_token or assign_token[0] != 'ASSIGN':
return None, pos
consume() # Consume ':'
# Get function body until 'end'
body_tokens = []
while local_pos < len(tokens):
current_token = tokens[local_pos]
if current_token[0] == 'IDENTIFIER' and current_token[1] == 'end':
break
body_tokens.append(current_token)
local_pos += 1
# Check for 'end'
if local_pos < len(tokens) and tokens[local_pos][0] == 'IDENTIFIER' and tokens[local_pos][1] == 'end':
consume() # Consume 'end'
return ('FUNCTION_DEF', func_name, body_tokens), local_pos
return None, pos
# Check for function definition: sdef < name > [ params ] : ...
elif token[0] == 'IDENTIFIER' and token[1] == 'sdef':
if pos + 3 < len(tokens):
if (tokens[pos + 1][0] == 'OPERATOR' and tokens[pos + 1][1] == '<' and
tokens[pos + 2][0] == 'IDENTIFIER' and
tokens[pos + 3][0] == 'OPERATOR' and tokens[pos + 3][1] == '>'):
func_name = tokens[pos + 2][1] # Extract name
local_pos = pos + 4
# Check for parameters: [ param1 , param2 , ... ]
params = []
if local_pos < len(tokens) and tokens[local_pos][0] == 'PAREN' and tokens[local_pos][1] == '[':
local_pos += 1
# Parse parameters
while local_pos < len(tokens) and not (tokens[local_pos][0] == 'PAREN' and tokens[local_pos][1] == ']'):
if tokens[local_pos][0] == 'IDENTIFIER':
params.append(tokens[local_pos][1])
elif tokens[local_pos][0] == 'SEPARATOR' and tokens[local_pos][1] == ',':
pass # Skip comma
local_pos += 1
if local_pos < len(tokens) and tokens[local_pos][0] == 'PAREN' and tokens[local_pos][1] == ']':
local_pos += 1
# Check for assignment operator
if local_pos < len(tokens) and tokens[local_pos][0] == 'ASSIGN' and tokens[local_pos][1] == ':':
local_pos += 1
# Collect body tokens until 'end'
body_tokens = []
while local_pos < len(tokens):
current_token = tokens[local_pos]
if current_token[0] == 'IDENTIFIER' and current_token[1] == 'end':
local_pos += 1
break
body_tokens.append(current_token)
local_pos += 1
return ('FUNCTION_DEF', func_name, params, body_tokens), local_pos
# Check for class definition: sclass < name > : ...
elif token[0] == 'IDENTIFIER' and token[1] == 'sclass':
if pos + 3 < len(tokens):
if (tokens[pos + 1][0] == 'OPERATOR' and tokens[pos + 1][1] == '<' and
tokens[pos + 2][0] == 'IDENTIFIER' and
tokens[pos + 3][0] == 'OPERATOR' and tokens[pos + 3][1] == '>'):
class_name = tokens[pos + 2][1] # Extract name
local_pos = pos + 4
# Check for assignment operator
if local_pos < len(tokens) and tokens[local_pos][0] == 'ASSIGN' and tokens[local_pos][1] == ':':
local_pos += 1
# Collect body tokens until 'end' (class end)
body_tokens = []
end_count = 0
while local_pos < len(tokens):
current_token = tokens[local_pos]
if current_token[0] == 'IDENTIFIER' and current_token[1] == 'smethod':
# 遇到新的方法定义,增加 end 计数
end_count += 1
elif current_token[0] == 'IDENTIFIER' and current_token[1] == 'end':
# 遇到 end 语句
end_count -= 1
# 如果 end_count 为 -1,说明是类的结束
if end_count == -1:
local_pos += 1
break
body_tokens.append(current_token)
local_pos += 1
return ('CLASS_DEF', class_name, body_tokens), local_pos
# Check for dcd run command: dcd : run : function_name : [params]
elif token[0] == 'IDENTIFIER' and token[1] == 'dcd':
# Handle dcd run command
consume() # Consume 'dcd'
# Check for ':'
next_token = peek()
if not (next_token and next_token[0] == 'ASSIGN' and next_token[1] == ':'):
return None, pos
consume() # Consume ':'
# Check for 'run'
next_token = peek()
if not (next_token and next_token[0] == 'IDENTIFIER' and next_token[1] == 'run'):
return None, pos
consume() # Consume 'run'
# Check for ':'
next_token = peek()
if not (next_token and next_token[0] == 'ASSIGN' and next_token[1] == ':'):
return None, pos
consume() # Consume ':'
# Get function name
func_token = peek()
if not (func_token and func_token[0] == 'IDENTIFIER'):
return None, pos
func_name = func_token[1]
consume() # Consume function name
# Check for parameters: : [ param1 , param2 , ... ]
args = []
next_token = peek()
if next_token and next_token[0] == 'ASSIGN' and next_token[1] == ':':
consume() # Consume ':'
next_token = peek()
if next_token and next_token[0] == 'PAREN' and next_token[1] == '[':
consume() # Consume '['
# Parse parameters
while True:
arg_token = peek()
if not arg_token:
break
if arg_token[0] == 'PAREN' and arg_token[1] == ']':
consume() # Consume ']'
break
if arg_token[0] in ['STRING', 'IDENTIFIER', 'NUMBER']:
args.append(arg_token)
consume() # Consume argument
elif (arg_token[0] == 'SEPARATOR' and arg_token[1] == ',') or (arg_token[0] == 'UNKNOWN' and arg_token[1] == ','):
consume() # Consume comma
else:
consume() # Consume other tokens
return ('DCD_RUN', func_name, args), local_pos
# Check for request statement: request : method<url headers data>
elif token[0] == 'IDENTIFIER' and token[1] == 'request':
consume() # Consume 'request'
if peek() and peek()[0] == 'ASSIGN':
consume() # Consume ':'
# Get HTTP method
method_token = peek()
if not method_token or method_token[0] != 'IDENTIFIER':
return None, pos
method = method_token[1].upper() # Convert to uppercase
consume() # Consume method name
# Check for arguments in angle brackets
args = []
has_opened_angle = False
# Handle the special case where '<' and '-' are merged into '<-'
if peek() and peek()[0] == 'OPERATOR' and peek()[1] == '<':
consume() # Consume '<'
has_opened_angle = True
elif peek() and peek()[0] == 'OPERATOR' and peek()[1] == '<-':
# Special case: split '<-' into '<' and '-'
args.append(('OPERATOR', '-'))
local_pos += 1 # Consume the entire '<-' token
has_opened_angle = True
if has_opened_angle:
# Parse arguments until '>' - treat each token as a separate argument
while peek() and not (peek()[0] == 'OPERATOR' and peek()[1] == '>'):
arg_token = consume()
if arg_token:
args.append(arg_token)
if not (peek() and peek()[0] == 'OPERATOR' and peek()[1] == '>'):
return None, pos
consume() # Consume '>'
return ('REQUEST', method, args), local_pos
# Check for sre statement: sre : expression
elif token[0] == 'IDENTIFIER' and token[1] == 'sre':
consume() # Consume 'sre'
if peek() and peek()[0] == 'ASSIGN':
consume() # Consume ':'
# Parse the expression to return
expr, new_pos = self.interpreter.parse_expression(tokens, local_pos)
if expr:
local_pos = new_pos
return ('SRE', expr), local_pos
# Check for class instantiation or method call
elif token[0] == 'IDENTIFIER':
identifier = token[1]
# Check if this is a class instantiation: ClassName : new : [args]
if (peek(1) and peek(1)[0] == 'ASSIGN' and peek(1)[1] == ':' and
peek(2) and peek(2)[0] == 'IDENTIFIER' and peek(2)[1] == 'new'):
consume() # Consume class name
consume() # Consume ':'
consume() # Consume 'new'
# Check for arguments
args = []
if peek() and peek()[0] == 'ASSIGN' and peek()[1] == ':':
consume() # Consume ':'
if peek() and peek()[0] == 'PAREN' and peek()[1] == '[':
consume() # Consume '['
# Parse arguments
while True:
arg_token = peek()
if not arg_token:
break
if arg_token[0] == 'PAREN' and arg_token[1] == ']':
consume() # Consume ']'
break
if arg_token[0] in ['STRING', 'IDENTIFIER', 'NUMBER']:
args.append(arg_token)
consume() # Consume argument
elif (arg_token[0] == 'SEPARATOR' and arg_token[1] == ',') or (arg_token[0] == 'UNKNOWN' and arg_token[1] == ','):
consume() # Consume comma
else:
consume() # Consume other tokens
return ('CLASS_INSTANTIATION', identifier, args), local_pos
# Check if this is a method call: instance : method : [args]
elif peek(1) and peek(1)[0] == 'ASSIGN' and peek(1)[1] == ':':
# Look ahead to see if the next token is an identifier (method name)
next_token = peek(2)
if next_token and next_token[0] == 'IDENTIFIER':
consume() # Consume instance name
consume() # Consume ':'
method_token = consume() # Consume method name
method_name = method_token[1]
# Check for arguments
args = []
if peek() and peek()[0] == 'ASSIGN' and peek()[1] == ':':
consume() # Consume ':'
if peek() and peek()[0] == 'PAREN' and peek()[1] == '[':
consume() # Consume '['
# Parse arguments
while True:
arg_token = peek()
if not arg_token:
break
if arg_token[0] == 'PAREN' and arg_token[1] == ']':
consume() # Consume ']'
break
if arg_token[0] in ['STRING', 'IDENTIFIER', 'NUMBER']:
args.append(arg_token)
consume() # Consume argument
elif (arg_token[0] == 'SEPARATOR' and arg_token[1] == ',') or (arg_token[0] == 'UNKNOWN' and arg_token[1] == ','):
consume() # Consume comma
else:
consume() # Consume other tokens
return ('METHOD_CALL', identifier, method_name, args), local_pos
# Direct assignment: a : 1
elif token[0] == 'IDENTIFIER' and peek(1) and peek(1)[0] == 'ASSIGN' and token[1] != 'dcd':
# Check if this is not a time statement (let time plugin handle it)
# Also check if this is not a sif or swhile statement (let siew plugin handle it)
# Also check if this is not a suibtn statement (let sbtn plugin handle it)
# Also check if this is not a web_get, web_post, web_put or web_delete statement (let web plugin handle it)
# Also check if this is not a qr_text, qr_ascii or qr_png statement (let qrcode plugin handle it)
# Also check if this is not a progress, spinner or loading_bar statement (let progress plugin handle it)
# Also check if this is not a dice, coin, rps or guess_num statement (let game plugin handle it)
# Also check if this is not a file_write, file_read, file_append, file_delete or dir_list statement (let fileio plugin handle it)
if token[1] != 'time' and token[1] not in ['sif', 'swhile', 'suibtn', 'sysinfo', 'md5', 'sha256', 'base64_enc', 'base64_dec', 'rot13', 'list_create', 'list_add', 'list_show', 'list_len', 'list_get', 'list_remove', 'map_create', 'map_set', 'map_get', 'map_has', 'map_keys', 'map_values', 'map_clear', 'richtext', 'style', 'rainbow_text', 'typewriter', 'marquee', 'clear_text', 'color_block', 'qr_text', 'qr_ascii', 'qr_png', 'progress', 'spinner', 'loading_bar', 'dice', 'coin', 'rps', 'guess_num', 'file_write', 'file_read', 'file_append', 'file_delete', 'dir_list']:
var_name = consume()[1]
consume() # Consume ':'
# Check if this is a web_get, web_post, web_put or web_delete statement
if local_pos < len(tokens) and tokens[local_pos][0] == 'IDENTIFIER' and tokens[local_pos][1] in ['web_get', 'web_post', 'web_put', 'web_delete']:
# Return None to let web plugin handle it
return None, pos
# Check if this is a scui statement (let scui plugin handle it)
if var_name == 'scui':
# Return None to let scui plugin handle it
return None, pos
# Check if this is a richtext statement (let richtext plugin handle it)
if var_name in ['richtext', 'style', 'rainbow_text', 'typewriter', 'marquee', 'clear_text', 'color_block']:
# Return None to let richtext plugin handle it
return None, pos
expr, new_pos = self.interpreter.parse_expression(tokens, local_pos)
if expr:
local_pos = new_pos
return ('ASSIGN', var_name, expr), local_pos
return None, pos
def execute_statement(self, stmt):
"""Execute basic statements"""
if stmt[0] == 'ASSIGN' or stmt[0] == 'ASSIGNMENT':
var_name = stmt[1]
value = self.interpreter.evaluate_expression(stmt[2])
self.interpreter.variables[var_name] = value
return True
elif stmt[0] == 'PRINT':
value = self.interpreter.evaluate_expression(stmt[1])
print(value)
return True
elif stmt[0] == 'COLOR_OUTPUT':
color_token = stmt[1]
text_token = stmt[2]
# Evaluate text
text = self.interpreter.evaluate_expression(text_token)
# Determine color code
color_code = '0' # 默认颜色
# 根据颜色类型处理
if color_token[0] == 'STRING':
color_str = color_token[1]
# 检查是否是预定义颜色名称
if color_str in self.color_names:
color_code = self.color_names[color_str]
# 检查是否是RGB格式 (rgb(255,0,0))
elif color_str.startswith('rgb(') and color_str.endswith(')'):
try:
rgb_values = color_str[4:-1].split(',')
r = int(rgb_values[0].strip())
g = int(rgb_values[1].strip())
b = int(rgb_values[2].strip())
# 使用ANSI 256色或RGB颜色
color_code = f'38;2;{r};{g};{b}'
except Exception as e:
print(f"Error: Invalid RGB format '{color_str}'")
return False
# 检查是否是16进制格式 (#FF0000)
elif color_str.startswith('#') and (len(color_str) == 7 or len(color_str) == 4):
try:
# 转换为RGB
hex_str = color_str[1:]
if len(hex_str) == 3:
# 简写形式 #RGB → #RRGGBB
hex_str = ''.join(c*2 for c in hex_str)
r = int(hex_str[0:2], 16)
g = int(hex_str[2:4], 16)
b = int(hex_str[4:6], 16)
# 使用ANSI 256色或RGB颜色
color_code = f'38;2;{r};{g};{b}'
except Exception as e:
print(f"Error: Invalid hex color format '{color_str}'")
return False
else:
print(f"Error: Unknown color '{color_str}'")
return False
# 输出彩色文本
print(f"\033[{color_code}m{text}\033[0m")
return True
elif stmt[0] == 'IF':
condition = self.interpreter.evaluate_expression(stmt[1])
if condition:
for body_stmt in stmt[2]:
self.execute_statement(body_stmt)
return True
elif stmt[0] == 'IF_ELSE':
if_condition = stmt[1]
if_body = stmt[2]
elif_clauses = stmt[3]
else_body = stmt[4]
# 检查if条件
if self.evaluate_condition(if_condition):
for body_stmt in if_body:
self.execute_statement(body_stmt)
return True
# 检查elif子句
for elif_condition, elif_body in elif_clauses:
if self.evaluate_condition(elif_condition):
for body_stmt in elif_body:
self.execute_statement(body_stmt)
return True
# 检查else子句
if else_body:
for body_stmt in else_body:
self.execute_statement(body_stmt)
return True
elif stmt[0] == 'WHILE':
condition_tokens = stmt[1]
body = stmt[2]
while self.evaluate_condition(condition_tokens):
for body_stmt in body:
self.execute_statement(body_stmt)
return True
elif stmt[0] == 'FUNCTION_DEF':
# 处理不同格式的函数定义
if len(stmt) == 3:
# 传统格式: sde func : ...
func_name = stmt[1]
func_body = stmt[2]
params = []
elif len(stmt) == 4:
# 新格式: sdef <func> [params] : ...
func_name = stmt[1]
params = stmt[2]
func_body = stmt[3]
else:
return False
# 存储函数
self.functions[func_name] = {
'params': params,
'body': func_body
}
# 也存储在解释器变量中以保持兼容性
self.interpreter.variables[func_name] = {
'type': 'function',
'params': params,
'body': func_body
}
if hasattr(self.interpreter, 'debug_mode') and self.interpreter.debug_mode:
print(f"Debug: Defined function '{func_name}' with params {params}")
return True
elif stmt[0] == 'FUNCTION_CALL':
# 处理函数调用
if len(stmt) == 2:
# 传统格式: sde run<func>
func_name = stmt[1]
args = []
elif len(stmt) == 3:
# 新格式: 带参数的调用
func_name = stmt[1]
args = stmt[2]
else:
return False
return self.handle_function_call(func_name, args)
elif stmt[0] == 'CLASS_DEF':
# 处理类定义
class_name = stmt[1]
body_tokens = stmt[2]
return self.handle_class_def(class_name, body_tokens)
elif stmt[0] == 'DCD_RUN':
# 处理 dcd run 命令
func_name = stmt[1]
args = stmt[2]
return self.handle_function_call(func_name, args)
elif stmt[0] == 'CLASS_INSTANTIATION':
# 处理类实例化
class_name = stmt[1]
args = stmt[2]
return self.handle_class_instantiation(class_name, args)
elif stmt[0] == 'SRE':
# Handle return statement: sre : expression
value = self.interpreter.evaluate_expression(stmt[1])
# Store the return value in a special variable
self.interpreter.variables['__return_value__'] = value
# Return the value to indicate that we want to return from the current function
return value
elif stmt[0] == 'METHOD_CALL':
# 处理方法调用
instance_name = stmt[1]
method_name = stmt[2]
args = stmt[3]
return self.handle_method_call(instance_name, method_name, args)
elif stmt[0] == 'START':
# Run another SCL file
file_path_token = stmt[1]
file_path = self.interpreter.evaluate_expression(file_path_token)
# Check if file exists
import os
if not os.path.exists(file_path):
print(f"Error: File {file_path} not found")
return False
try:
# Read the file content
with open(file_path, 'r', encoding='utf-8') as f:
file_content = f.read()
# Execute the file content
print(f"Running file: {file_path}")
success = self.interpreter.execute(file_content, file_path)
if not success:
print(f"Error: Failed to run file {file_path}")
return False
return True
except Exception as e:
print(f"Error running file {file_path}: {e}")
import traceback
traceback.print_exc()
return False
elif stmt[0] == 'REQUEST':
# 处理 HTTP 请求
method = stmt[1]
args = stmt[2]
# Evaluate arguments - each arg is a single token
eval_args = []
for arg_token in args:
eval_args.append(self.interpreter.evaluate_expression(arg_token))
if not eval_args:
print("Error: No URL provided for request")
return False
url = str(eval_args[0])
headers = None
data = None
# Parse optional headers and data
if len(eval_args) > 1:
# For simplicity, we'll treat the second argument as headers if it's a dictionary
# (Note: SCL doesn't support direct dictionary creation, so this is limited)
headers = eval_args[1]
if len(eval_args) > 2:
# Third argument as data
data = eval_args[2]
try:
response = None
# Make the request with various options to handle proxy issues
try:
if method == 'GET':
response = requests.get(url, headers=headers, timeout=5, proxies={}, verify=False, allow_redirects=True)
elif method == 'POST':
response = requests.post(url, headers=headers, data=data, timeout=5, proxies={}, verify=False, allow_redirects=True)
elif method == 'PUT':
response = requests.put(url, headers=headers, data=data, timeout=5, proxies={}, verify=False, allow_redirects=True)
elif method == 'DELETE':
response = requests.delete(url, headers=headers, timeout=5, proxies={}, verify=False, allow_redirects=True)
else:
print(f"Error: Unsupported HTTP method '{method}'")
return False
except Exception as e:
# If all else fails, try with even more options
print("Warning: Request failed, trying with more options...")
session = requests.Session()
session.trust_env = False # Disable environment proxy settings
if method == 'GET':
response = session.get(url, headers=headers, timeout=5, verify=False, allow_redirects=True)
elif method == 'POST':
response = session.post(url, headers=headers, data=data, timeout=5, verify=False, allow_redirects=True)
elif method == 'PUT':
response = session.put(url, headers=headers, data=data, timeout=5, verify=False, allow_redirects=True)
elif method == 'DELETE':
response = session.delete(url, headers=headers, timeout=5, verify=False, allow_redirects=True)
else:
print(f"Error: Unsupported HTTP method '{method}'")
return False
# Print response status code
print(f"Status Code: {response.status_code}")
# Print response headers
print("Headers:")
for key, value in response.headers.items():
print(f" {key}: {value}")
# Print response content
print("\nResponse Content:")
print(response.text)
# Store response in variables for further processing
self.interpreter.variables['response_status'] = response.status_code
self.interpreter.variables['response_text'] = response.text
return True
except requests.exceptions.RequestException as e:
print(f"Error making HTTP request: {e}")
return False
except Exception as e:
print(f"Error in request operation: {e}")
import traceback
traceback.print_exc()
return False
return False
def handle_function_call(self, func_name, args):
"""Handle function call"""
# 首先从 self.functions 中查找
if func_name in self.functions:
func = self.functions[func_name]
params = func['params']
body = func['body']
# 尝试从解释器变量中查找
elif func_name in self.interpreter.variables:
func_data = self.interpreter.variables[func_name]
# 检查是否是函数
if isinstance(func_data, dict) and func_data.get('type') == 'function':
params = func_data['params']
body = func_data['body']
# 检查是否是传统格式的函数(直接存储为列表)
elif isinstance(func_data, list):
params = []
body = func_data
else:
print(f"Error: '{func_name}' is not a function")
return False
else:
print(f"Error: Function '{func_name}' not defined")
return False
# 创建新的变量作用域
old_vars = self.interpreter.variables.copy()
# 绑定参数到参数名
for i, param in enumerate(params):
if i < len(args):
# 检查参数是否已经是一个值(不是表达式令牌)
if isinstance(args[i], (int, float, str, bool)):
arg_value = args[i]
else:
arg_value = self.interpreter.evaluate_expression(args[i])
self.interpreter.variables[param] = arg_value
if hasattr(self.interpreter, 'debug_mode') and self.interpreter.debug_mode:
print(f"Debug: Bound parameter '{param}' to value '{arg_value}'")
else:
self.interpreter.variables[param] = 0
if hasattr(self.interpreter, 'debug_mode') and self.interpreter.debug_mode:
print(f"Debug: Bound parameter '{param}' to default value 0")
# 执行函数体
success = True
return_value = None
pos = 0
while pos < len(body):
stmt, new_pos = self.interpreter.parse_statement(body, pos)
if stmt:
result = self.execute_statement(stmt)
# Check if result is not a boolean - this means we encountered an sre statement
if not isinstance(result, bool):
return_value = result
break
if not result:
success = False
break
pos = new_pos
else:
pos += 1
# 恢复变量作用域
old_return_value = old_vars.get('__return_value__')
self.interpreter.variables = old_vars
if old_return_value is not None:
self.interpreter.variables['__return_value__'] = old_return_value
# Return the return value if we have one, otherwise return success
if return_value is not None:
return return_value
return success
def handle_class_def(self, class_name, body_tokens):
"""Handle class definition"""
# 解析类体以提取方法和属性
methods = {}
attributes = {}
# 从体令牌中解析方法
pos = 0
while pos < len(body_tokens):
# 跳过空令牌、换行和其他分隔符
while pos < len(body_tokens) and body_tokens[pos][1] in ['\n', ' ', '\t']:
pos += 1
if pos >= len(body_tokens):
break
# 检查是否是方法定义
if body_tokens[pos][0] == 'IDENTIFIER' and body_tokens[pos][1] == 'smethod':
# 检查是否有方法名
if (pos + 3 < len(body_tokens) and
body_tokens[pos + 1][0] == 'OPERATOR' and body_tokens[pos + 1][1] == '<' and
body_tokens[pos + 2][0] == 'IDENTIFIER' and
body_tokens[pos + 3][0] == 'OPERATOR' and body_tokens[pos + 3][1] == '>'):
method_name = body_tokens[pos + 2][1]
pos += 4
# 跳过空格和换行
while pos < len(body_tokens) and body_tokens[pos][1] in ['\n', ' ', '\t']:
pos += 1
# 解析参数
params = []
if pos < len(body_tokens) and body_tokens[pos][0] == 'PAREN' and body_tokens[pos][1] == '[':
pos += 1
while pos < len(body_tokens) and not (body_tokens[pos][0] == 'PAREN' and body_tokens[pos][1] == ']'):
if body_tokens[pos][0] == 'IDENTIFIER':
params.append(body_tokens[pos][1])
pos += 1
if pos < len(body_tokens) and body_tokens[pos][0] == 'PAREN' and body_tokens[pos][1] == ']':
pos += 1
# 跳过空格和换行
while pos < len(body_tokens) and body_tokens[pos][1] in ['\n', ' ', '\t']:
pos += 1
# 解析方法体
if pos < len(body_tokens) and body_tokens[pos][0] == 'ASSIGN' and body_tokens[pos][1] == ':':
pos += 1
# 跳过空格和换行
while pos < len(body_tokens) and body_tokens[pos][1] in ['\n', ' ', '\t']:
pos += 1
method_body = []
while pos < len(body_tokens):
if body_tokens[pos][0] == 'IDENTIFIER' and body_tokens[pos][1] == 'end':
pos += 1
break
method_body.append(body_tokens[pos])
pos += 1
methods[method_name] = {
'params': params,
'body': method_body
}
else:
# 不是有效的方法定义,跳过
pos += 1
else:
# 不是方法定义,跳过
pos += 1
self.classes[class_name] = {
'methods': methods,
'attributes': attributes
}
# 也存储在解释器变量中
self.interpreter.variables[class_name] = {
'type': 'class',
'methods': methods,
'attributes': attributes
}
if hasattr(self.interpreter, 'debug_mode') and self.interpreter.debug_mode:
print(f"Debug: Defined class '{class_name}' with methods {list(methods.keys())}")
return True
def handle_class_instantiation(self, class_name, args):
"""Handle class instantiation"""
if class_name not in self.classes:
print(f"Error: Class '{class_name}' not defined")
return False
class_def = self.classes[class_name]
# 创建实例
instance = {
'class': class_name,
'methods': class_def['methods'].copy(),
'attributes': class_def['attributes'].copy()
}
# 存储实例在变量中
instance_name = f"{class_name.lower()}_instance"
if args:
# 如果提供了参数,使用第一个参数作为实例名
instance_name = self.interpreter.evaluate_expression(args[0])
self.interpreter.variables[instance_name] = instance
if hasattr(self.interpreter, 'debug_mode') and self.interpreter.debug_mode:
print(f"Debug: Created instance of class '{class_name}' as '{instance_name}'")
return True
def handle_method_call(self, instance_name, method_name, args):
"""Handle method call"""
if instance_name not in self.interpreter.variables:
print(f"Error: Instance '{instance_name}' not found")
return False
instance = self.interpreter.variables[instance_name]
if 'methods' not in instance or method_name not in instance['methods']:
print(f"Error: Method '{method_name}' not found in instance")
return False
method = instance['methods'][method_name]
params = method['params']
body = method['body']
# 创建新的变量作用域
old_vars = self.interpreter.variables.copy()
# 添加 'this' 引用
self.interpreter.variables['this'] = instance
# 绑定参数到参数名
for i, param in enumerate(params):
if i < len(args):
self.interpreter.variables[param] = self.interpreter.evaluate_expression(args[i])
else:
self.interpreter.variables[param] = 0
# 执行方法体
success = True
pos = 0
while pos < len(body):
stmt, new_pos = self.interpreter.parse_statement(body, pos)
if stmt:
if not self.execute_statement(stmt):
success = False
break
pos = new_pos
else:
pos += 1
# 恢复变量作用域
self.interpreter.variables = old_vars
return True
def evaluate_condition(self, condition_tokens):
"""Evaluate a condition from tokens"""
if len(condition_tokens) >= 3:
left = condition_tokens[0]
op = condition_tokens[1]
right = condition_tokens[2]
left_value = self.interpreter.evaluate_expression(left)
right_value = self.interpreter.evaluate_expression(right)
if op[1] == '>':
return left_value > right_value
elif op[1] == '<':
return left_value < right_value
elif op[1] == '==':
return left_value == right_value
elif op[1] == '!=':
return left_value != right_value
elif op[1] == '>=':
return left_value >= right_value
elif op[1] == '<=':
return left_value <= right_value
elif op[1] == '&': # Logical AND
return left_value and right_value
elif op[1] == '|': # Logical OR
return left_value or right_value
return False