# Copyright 2026 SigmaSRC, Inc. All Rights Reserved.

"""Run-time Fuel utilities.

These are the built-ins for Fuel.  The Fuel compiler assumes that
these are always available.  An import * from this module makes that so.

All these functions accept None string arguments and do the right
thing for them.

String indexing is 0-based.  This makes the language seem more real.

"""

import re
from sigma.util.fuelset import FuelSet

def concat(*args):
    "String concatenation.  No delimiter is inserted."
    return "".join([s for s in args if s is not None])

def substr(s, start, size=1):
    "Substring extraction."
    if start < 0:
        raise ValueError("start %s out of range" % repr(start))
    if size < 0:
        raise ValueError("size %s out of range" % repr(size))
    if s is None:
        return None
    else:
        return s[start:start+size]

def find(s, t):
    "Return the position of the first occurrence of t in s, or -1 if none."
    if s is None or t is None:
        return -1
    return s.find(t)

def lower(s):
    "Convert a string to lowercase."
    if s is None:
        return None
    else:
        return s.lower()

def upper(s):
    "Covert a string to uppercase."
    if s is None:
        return None
    else:
        return s.upper()

def strip(s):
    "Strip leading and trailing whitespace."
    if s is None:
        return None
    else:
        return s.strip()

def size(s):
    "Return string length."
    if s is None:
        return 0
    else:
        return len(s)

def split(s, delim=None):
    "Split a string.  Behaves like Python split method."
    return FuelSet(s.split(delim))

def format(msg, *args):
    """String formatting utility, like sprintf().

    When called with wrong arguments, it returns the str() of all
    arguments concatenated with spaces in between.

    """
    if args:
        try:
            msg = msg % args
        except:
            msg = "%s %s" % (msg, " ".join(map(str, args)))
    return msg

def replace(s, t, u):
    "Replace all occurrences of t in s by u."
    if s is None or t is None or u is None:
        return s
    else:
        return s.replace(t, u)

def match(regex, s):
    "Return True iff s matches regex.  (Anchored match.)"
    if s is None:
        return False
    return re.match(regex, s) is not None

def toint(s, base=10):
    """Convert a string to an int.  Return None (nil) if not an int.

    Optional base argument can specify an alternate conversion base
    (e.g. 8 or 16).
    """
    try:
        return int(s, base)
    except:
        return None

def bitwise_and(a, b):
    "Return a & b."
    return a & b

def bitwise_or(a, b):
    "Return a | b."
    return a | b

def bitwise_xor(a, b):
    "Return a ^ b."
    return a ^ b

def bitwise_not(a):
    "Return ~a."
    return ~a

def formatset(s, sep=", "):
    "Format the elements of a set."
    try:
        items = list(s)
    except:
        items = iter(s)
    return sep.join(map(str, items))
