<commit_before><?php

namespace o;


//// Global internal utility functions


// PHP to THT type
function v ($v) {

    $phpType = gettype($v);
    if ($phpType === 'object') {
       if ($v instanceof \Closure) {
           $phpType = 'Closure';
       } else if ($v instanceof \ONothing) {
           $v->error();
       } else {
            return $v;
       }
    }
    else if ($phpType === 'NULL') {
        Tht::error("Leaked `null` value found in transpiled PHP.");
    }

    $o = Runtime::$SINGLE[$phpType];
    $o->val = $v;

    return $o;
}

// THT to PHP type
// TODO: recursive unwrap for list and map values
function uv ($v) {
    return OMap::isa($v) || OList::isa($v) ? $v->val : $v;
}

// Assert Number type value
function vn ($v, $isAdd) {
    if (!is_numeric($v)) {
        $tag = $isAdd ? "Did you mean '~'?" : '';
        Tht::error("Can't use math on non-number value. $tag");
    }
    return $v;
}

// Convert camelCase to user_underscore_case (with u_ prefix)
function u_ ($s) {
    $out = preg_replace('/([^_])([A-Z])/', '$1_$2', $s);
    return 'u_' . strtolower($out);
}

// user_underscore_case back to camelCase (without u_ prefix)
function unu_ ($s) {
    $s = preg_replace('/^u_/', '', $s);
    return v($s)->u_to_camel_case();
}

// var has a u_ prefix
function hasu_ ($v) {
    return substr($v, 0, 2) === 'u_';
}



// Validate function arguments

// sig:
//   n = number
//   s = string
//   f = flag
//   l = list
//.  m = map
//   * = any

// NOTE: Fewer args are already handled by PHP, but we could possibly trap it here too.
// PERF: ~ 0.3 ms - not significant
function ARGS($sig, $arguments) {

    $err = '';
    
    if (count($arguments) > strlen($sig)) {
        $err = 'expects ' . strlen($sig) . ' arguments.  Got ' . count($arguments) . ' instead.';
    } 
    else {
        $i = 0;
        foreach ($arguments as $arg) {
            
            $s = $sig[$i];

            if ($s === '*') { continue; }
            if (is_null($arg)) { continue; }

            $t = gettype($arg);

            if ($t === 'integer' || $t === 'double' || $t === 'float') {
                $t = 'number';  
                if ($s === 's') {
                    // allow numbers to be cast as strings
                    continue;
                }
            }
            else if ($t === 'boolean') {
                $t = 'flag';
            }
            else if ($t === 'object') {
                $varg = v($arg);
                if ($varg->u_is_map()) {
                    $t = 'map';
                }
                else if ($varg->u_is_list()) {
                    $t = 'list';
                }
            }
 
            // Type mismatch
            if ($t !== Runtime::$SIG_TYPE_KEY_TO_LABEL[$s]) {
                $name = gettype($arg);
                // if ($name == 'object') {
                //     $name = get_class($arg);
                // }
                $err = "expects argument $i to be type `" . Runtime::$SIG_TYPE_KEY_TO_LABEL[$s] . "`.  Got a `" . $name . "` instead.";
                break;
            }
            $i += 1;
        }
    }

    if ($err) {
        $caller = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 3)[1]['function'];
        Tht::error("`$caller()`" . $err);
    }
}


class Runtime {

    static $TYPES = [ 'OList', 'OString', 'ONumber', 'OFlag', 'OFunction', 'ONothing' ];

    static $PHP_TO_TYPE = [
        'string'  => 'OString',
        'array'   => 'OList',
        'boolean' => 'OFlag',<commit_msg>update args()<commit_after><?php

namespace o;


//// Global internal utility functions


// PHP to THT type
function v ($v) {

    $phpType = gettype($v);
    if ($phpType === 'object') {
       if ($v instanceof \Closure) {
           $phpType = 'Closure';
       } else if ($v instanceof \ONothing) {
           $v->error();
       } else {
            return $v;
       }
    }
    else if ($phpType === 'NULL') {
        Tht::error("Leaked `null` value found in transpiled PHP.");
    }

    $o = Runtime::$SINGLE[$phpType];
    $o->val = $v;

    return $o;
}

// THT to PHP type
// TODO: recursive unwrap for list and map values
function uv ($v) {
    return OMap::isa($v) || OList::isa($v) ? $v->val : $v;
}

// Assert Number type value
function vn ($v, $isAdd) {
    if (!is_numeric($v)) {
        $tag = $isAdd ? "Did you mean '~'?" : '';
        Tht::error("Can't use math on non-number value. $tag");
    }
    return $v;
}

// Convert camelCase to user_underscore_case (with u_ prefix)
function u_ ($s) {
    $out = preg_replace('/([^_])([A-Z])/', '$1_$2', $s);
    return 'u_' . strtolower($out);
}

// user_underscore_case back to camelCase (without u_ prefix)
function unu_ ($s) {
    $s = preg_replace('/^u_/', '', $s);
    return v($s)->u_to_camel_case();
}

// var has a u_ prefix
function hasu_ ($v) {
    return substr($v, 0, 2) === 'u_';
}



// Validate function arguments

// sig:
//   n = number
//   s = string
//   f = flag
//   l = list
//.  m = map
//   * = any

// NOTE: Fewer args are already handled by PHP, but we could possibly trap it here too.
// PERF: ~ 0.3 ms - not significant
function ARGS($sig, $arguments) {

    $err = '';
    
    if (count($arguments) > strlen($sig)) {
        $err = 'expects ' . strlen($sig) . ' arguments.  Got ' . count($arguments) . ' instead.';
    } 
    else {
        $i = 0;
        foreach ($arguments as $arg) {
            
            $s = $sig[$i];

            if ($s === '*') { continue; }
            if (is_null($arg)) { continue; }

            $t = gettype($arg);

            if ($t === 'integer' || $t === 'double' || $t === 'float') {
                $t = 'number';  
                if ($s === 's') {
                    // allow numbers to be cast as strings
                    continue;
                }
            }
            else if ($t === 'boolean') {
                $t = 'flag';
            }
            else if ($t === 'object') {
                $varg = v($arg);
                if ($varg->u_is_map()) {
                    $t = 'map';
                }
                else if ($varg->u_is_list()) {
                    $t = 'list';
                }
            }
 
            // Type mismatch
            if ($t !== Runtime::$SIG_TYPE_KEY_TO_LABEL[$s]) {
                $name = $t;
                // if ($name == 'object') {
                //     $name = get_class($arg);
                // }
                $err = "expects argument $i to be type `" . Runtime::$SIG_TYPE_KEY_TO_LABEL[$s] . "`.  Got a `" . $name . "` instead.";
                break;
            }
            $i += 1;
        }
    }

    if ($err) {
        $caller = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 3)[1]['function'];
        Tht::error("`$caller()`" . $err);
    }
}


class Runtime {

    static $TYPES = [ 'OList', 'OString', 'ONumber', 'OFlag', 'OFunction', 'ONothing' ];

    static $PHP_TO_TYPE = [
        'string'  => 'OString',
        'array'   => 'OList',
        'boolean' => 'OFlag',
{'fraction_non_alphanumeric': 0.18366471177227864, 'fraction_numerical': 0.0028608210556429693, 'mean_word_length': 1.566813509544787, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 23, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4194142', 'n_tokens_mistral': 2389, 'n_tokens_neox': 2292, 'n_words': 600}