Cable/Implementations

From Esolang
Jump to navigation Jump to search
import operator
import re

# ---------------- OPS ----------------
ops = {
    "+=": operator.add,
    "-=": operator.sub,
    "*=": operator.mul,
    "//=": operator.floordiv,
    "%=": operator.mod,
}

# ---------------- HELPERS ----------------
def parse_string_literal(s):
    """Extract string literal from quotes and handle escape sequences."""
    if s.startswith('"') and s.endswith('"'):
        content = s[1:-1]
        # Handle escape sequences
        content = content.replace('\\n', '\n')
        content = content.replace('\\t', '\t')
        content = content.replace('\\\\', '\\')
        return content
    return None

def eval_expression(expr, variables):
    """Evaluate an expression that may contain operators and parentheses."""
    expr = expr.strip()
    
    # Check if it's just a string literal first - if so, return it directly
    string_val = parse_string_literal(expr)
    if string_val is not None:
        return string_val
    
    # Handle parentheses recursively
    while '(' in expr:
        # Find innermost parentheses
        match = re.search(r'\(([^()]+)\)', expr)
        if match:
            inner = match.group(1)
            result = eval_expression(inner, variables)
            expr = expr[:match.start()] + str(result) + expr[match.end():]
        else:
            break
    
    # Handle comparison operators (return 0 or 1)
    for op in ['==', '!=', '<=', '>=', '<', '>']:
        if op in expr:
            parts = expr.split(op, 1)
            if len(parts) == 2:
                left = eval_expression(parts[0].strip(), variables)
                right = eval_expression(parts[1].strip(), variables)
                comparisons = {
                    "==": left == right,
                    "!=": left != right,
                    "<": left < right,
                    "<=": left <= right,
                    ">": left > right,
                    ">=": left >= right,
                }
                return 1 if comparisons[op] else 0
    
    # Handle string/int concatenation with +
    if '+' in expr:
        # Need to carefully parse to handle string literals
        parts = []
        current = ""
        in_string = False
        
        for i, ch in enumerate(expr):
            if ch == '"':
                in_string = not in_string
                current += ch
            elif ch == '+' and not in_string:
                if current.strip():
                    parts.append(current.strip())
                current = ""
            else:
                current += ch
        
        if current.strip():
            parts.append(current.strip())
        
        if len(parts) > 1:
            # Evaluate each part and concatenate
            result = eval_expression(parts[0], variables)
            for part in parts[1:]:
                right = eval_expression(part, variables)
                # String concatenation or integer addition
                if isinstance(result, str) or isinstance(right, str):
                    result = str(result) + str(right)
                else:
                    result = result + right
            return result
    
    # Handle arithmetic operators (left to right for same precedence)
    # Multiplication and division first
    for op_str, op_func in [('*', operator.mul), ('//', operator.floordiv), ('%', operator.mod)]:
        if op_str in expr:
            parts = expr.split(op_str, 1)
            if len(parts) == 2:
                left = eval_expression(parts[0].strip(), variables)
                right = eval_expression(parts[1].strip(), variables)
                return op_func(left, right)
    
    # Then subtraction (addition handled above for string concat)
    if '-' in expr:
        idx = expr.rfind('-')
        if idx > 0:  # Make sure it's not a negative sign at start
            left = eval_expression(expr[:idx].strip(), variables)
            right = eval_expression(expr[idx+1:].strip(), variables)
            return operator.sub(left, right)
    
    # Base case: resolve single value
    return resolve(expr, variables)

def resolve(token, variables):
    """Resolve a token to its value (int or string)."""
    token = token.strip()
    
    # String literal
    string_val = parse_string_literal(token)
    if string_val is not None:
        return string_val
    
    # Integer
    if token.lstrip("-").isdigit():
        return int(token)
    
    # Variable
    if token in variables:
        return variables[token]
    
    raise ValueError(f"Unknown value: {token}")

def count_blocks(s):
    depth = 0
    count = 0
    for c in s:
        if c == "[":
            if depth == 0:
                count += 1
            depth += 1
        elif c == "]":
            depth -= 1
    return count

def extract_first_block(s):
    if not s.startswith("["):
        return None, s
    depth = 0
    for i, ch in enumerate(s):
        if ch == "[":
            depth += 1
        elif ch == "]":
            depth -= 1
            if depth == 0:
                return s[1:i], s[i + 1:]
    return None, s

def parse_print_expression(expr, variables):
    """Parse PRINT expression that may contain string concatenation."""
    return str(eval_expression(expr, variables))

# ---------------- INTERPRETER ----------------
prgm = """
[A = 1]
[Duplicate][Append [Print A][A += 1][Newline][If A == 10][Delete][Duplicate]]
"""
prgm = prgm.strip()
prgm = re.sub(r'\]\s*\[', '][', prgm)
variables = {}

while count_blocks(prgm) > 0:
    block, prgm = extract_first_block(prgm)
    if not block:
        break
    
    block = block.strip()
    parts = block.split()
    
    # ---------- ASSIGNMENTS ----------
    if len(parts) >= 3 and any(op in parts[1] for op in ['=', '+=', '-=', '*=', '//=', '%=']):
        var = parts[0]
        op = parts[1]
        expr = ' '.join(parts[2:])
        
        if op == '=':
            variables[var] = eval_expression(expr, variables)
        elif op == '+=':
            current = variables.get(var, 0)
            value = eval_expression(expr, variables)
            # Handle string concatenation
            if isinstance(current, str) or isinstance(value, str):
                variables[var] = str(current) + str(value)
            else:
                variables[var] = current + value
        elif op == '-=':
            variables[var] = variables.get(var, 0) - eval_expression(expr, variables)
        elif op == '*=':
            variables[var] = variables.get(var, 0) * eval_expression(expr, variables)
        elif op == '//=':
            variables[var] = variables.get(var, 0) // eval_expression(expr, variables)
        elif op == '%=':
            variables[var] = variables.get(var, 0) % eval_expression(expr, variables)
    else:
        lower_block = block.lower()
        
        # ---------- INTEGER ----------
        if lower_block.startswith("integer"):
            var = parts[1]
            if var in variables:
                val = variables[var]
                # Convert to int
                if isinstance(val, str):
                    try:
                        variables[var] = int(val)
                    except ValueError:
                        variables[var] = 0  # Default to 0 if conversion fails
                # If already int, keep it as is
        
        # ---------- LOWER ----------
        elif lower_block.startswith("lower"):
            var = parts[1]
            if var in variables:
                val = variables[var]
                if isinstance(val, str):
                    variables[var] = val.lower()
                # If int, keep as int
        
        # ---------- UPPER ----------
        elif lower_block.startswith("upper"):
            var = parts[1]
            if var in variables:
                val = variables[var]
                if isinstance(val, str):
                    variables[var] = val.upper()
                # If int, keep as int
        # ---------- INPUT ----------
        elif lower_block.startswith("input"):
            var = parts[1]
            variables[var] = input()
        
        # ---------- DELETE ----------
        elif lower_block.startswith("delete"):
            _, prgm = extract_first_block(prgm)
        
        # ---------- APPEND ----------
        elif lower_block.startswith("append"):
            _, rest = block.split(" ", 1)
            prgm = rest + prgm
        
        # ---------- IF ----------
        elif lower_block.startswith("if"):
            condition = block[2:].strip()
            if not eval_expression(condition, variables):
                _, prgm = extract_first_block(prgm)
        
        # ---------- PRINT ----------
        elif lower_block.startswith("print"):
            expr = block[5:].strip()
            result = parse_print_expression(expr, variables)
            print(result, end = "")
        
        # ---------- NEWLINE ----------
        elif lower_block.startswith("newline"):
            print()
        
        # ---------- DUPLICATE ----------
        elif lower_block.startswith("duplicate"):
            parts = block.split()
            count = 2 if len(parts) == 1 else resolve(parts[1], variables)
            next_block, prgm = extract_first_block(prgm)
            if next_block is not None and count > 0:
                duplicated = "".join(f"[{next_block}]" for _ in range(count))
                prgm = duplicated + prgm

#print(prgm)
#print(variables)