// oils_for_unix.mycpp.cc: translated from Python by mycpp

// #include "_gen/bin/oils_for_unix.mycpp.h"

#include "cpp/preamble.h"
// BEGIN mycpp output

#include "mycpp/runtime.h"

GLOBAL_STR(str0, "(");
GLOBAL_STR(str1, ")");
GLOBAL_STR(str2, "_");
GLOBAL_STR(str3, "T");
GLOBAL_STR(str4, "F");
GLOBAL_STR(str5, "<IntControlFlow %s %s>");
GLOBAL_STR(str6, "<ValueControlFlow %s %s>");
GLOBAL_STR(str7, "");
GLOBAL_STR(str8, "");
GLOBAL_STR(str9, "\n<html>\n  <head>\n     <title>oil AST</title>\n     <style>\n      .n { color: brown }\n      .s { font-weight: bold }\n      .o { color: darkgreen }\n     </style>\n  </head>\n  <body>\n    <pre>\n");
GLOBAL_STR(str10, "\n    </pre>\n  </body>\n</html>\n    ");
GLOBAL_STR(str11, "n");
GLOBAL_STR(str12, "s");
GLOBAL_STR(str13, "o");
GLOBAL_STR(str14, "o");
GLOBAL_STR(str15, "o");
GLOBAL_STR(str16, "<span class=\"%s\">");
GLOBAL_STR(str17, "</span>");
GLOBAL_STR(str18, " ");
GLOBAL_STR(str19, "\n");
GLOBAL_STR(str20, " ");
GLOBAL_STR(str21, "]");
GLOBAL_STR(str22, " ");
GLOBAL_STR(str23, " ");
GLOBAL_STR(str24, "\n");
GLOBAL_STR(str25, "\n");
GLOBAL_STR(str26, " ");
GLOBAL_STR(str27, "%s%s: [");
GLOBAL_STR(str28, "\n");
GLOBAL_STR(str29, "\n");
GLOBAL_STR(str30, "%s]");
GLOBAL_STR(str31, "%s%s: ");
GLOBAL_STR(str32, "\n");
GLOBAL_STR(str33, "\n");
GLOBAL_STR(str34, " ");
GLOBAL_STR(str35, "UNTYPED any");
GLOBAL_STR(str36, "...0x%s");
GLOBAL_STR(str37, " ");
GLOBAL_STR(str38, " ");
GLOBAL_STR(str39, " %s:");
GLOBAL_STR(str40, "UNTYPED any");
GLOBAL_STR(str41, "[");
GLOBAL_STR(str42, " ");
GLOBAL_STR(str43, "]");
GLOBAL_STR(str44, "...0x%s");
GLOBAL_STR(str45, "Running Oil in ---caper mode");
GLOBAL_STR(str46, "FANOS error: %s");
GLOBAL_STR(str47, "ERROR %s");
GLOBAL_STR(str48, "msg = %r");
GLOBAL_STR(str49, " ");
GLOBAL_STR(str50, "GETPID");
GLOBAL_STR(str51, "CHDIR");
GLOBAL_STR(str52, "SETENV");
GLOBAL_STR(str53, "MAIN");
GLOBAL_STR(str54, "oils-for-unix");
GLOBAL_STR(str55, "oil");
GLOBAL_STR(str56, "Missing required applet name.");
GLOBAL_STR(str57, "-h");
GLOBAL_STR(str58, "--help");
GLOBAL_STR(str59, "oils-usage");
GLOBAL_STR(str60, "-V");
GLOBAL_STR(str61, "--version");
GLOBAL_STR(str62, "---caper");
GLOBAL_STR(str63, "-");
GLOBAL_STR(str64, "ysh");
GLOBAL_STR(str65, "oil");
GLOBAL_STR(str66, "ysh");
GLOBAL_STR(str67, "sh");
GLOBAL_STR(str68, "osh");
GLOBAL_STR(str69, "true");
GLOBAL_STR(str70, "false");
GLOBAL_STR(str71, "readlink");
GLOBAL_STR(str72, "readlink not translated");
GLOBAL_STR(str73, "Invalid applet %r");
GLOBAL_STR(str74, "oils: %s");
GLOBAL_STR(str75, "");
GLOBAL_STR(str76, "oils I/O error (main): %s");
GLOBAL_STR(str77, "g");
GLOBAL_STR(str78, "a");
GLOBAL_STR(str79, "A");
GLOBAL_STR(str80, "n");
GLOBAL_STR(str81, "r");
GLOBAL_STR(str82, "x");
GLOBAL_STR(str83, "%s=%s");
GLOBAL_STR(str84, "-");
GLOBAL_STR(str85, "+");
GLOBAL_STR(str86, "-");
GLOBAL_STR(str87, "+");
GLOBAL_STR(str88, "-");
GLOBAL_STR(str89, "+");
GLOBAL_STR(str90, "n");
GLOBAL_STR(str91, "r");
GLOBAL_STR(str92, "x");
GLOBAL_STR(str93, "a");
GLOBAL_STR(str94, "A");
GLOBAL_STR(str95, "-");
GLOBAL_STR(str96, "declare -");
GLOBAL_STR(str97, "");
GLOBAL_STR(str98, " ");
GLOBAL_STR(str99, "=");
GLOBAL_STR(str100, "=()");
GLOBAL_STR(str101, ";");
GLOBAL_STR(str102, " ");
GLOBAL_STR(str103, "[");
GLOBAL_STR(str104, "]=");
GLOBAL_STR(str105, " ");
GLOBAL_STR(str106, "=(");
GLOBAL_STR(str107, "");
GLOBAL_STR(str108, ")");
GLOBAL_STR(str109, " ");
GLOBAL_STR(str110, "[");
GLOBAL_STR(str111, "]=");
GLOBAL_STR(str112, "=(");
GLOBAL_STR(str113, "");
GLOBAL_STR(str114, ")");
GLOBAL_STR(str115, "");
GLOBAL_STR(str116, "export_");
GLOBAL_STR(str117, "doesn't accept -f because it's dangerous.  (The code can usually be restructured with 'source')");
GLOBAL_STR(str118, "doesn't accept RHS with -n");
GLOBAL_STR(str119, "Got -a but RHS isn't an array");
GLOBAL_STR(str120, "Got -A but RHS isn't an associative array");
GLOBAL_STR(str121, "readonly");
GLOBAL_STR(str122, "new_var");
GLOBAL_STR(str123, "with -f expects function names");
GLOBAL_STR(str124, "declare -f %s");
GLOBAL_STR(str125, "doesn't implement flag -i (shopt --set ignore_flags_not_impl)");
GLOBAL_STR(str126, "Warning: OSH doesn't implement flags -l or -u (shopt --set ignore_flags_not_impl)");
GLOBAL_STR(str127, "-");
GLOBAL_STR(str128, "-");
GLOBAL_STR(str129, "-");
GLOBAL_STR(str130, "+");
GLOBAL_STR(str131, "+");
GLOBAL_STR(str132, "+");
GLOBAL_STR(str133, "unset");
GLOBAL_STR(str134, "Invalid shift argument %r");
GLOBAL_STR(str135, "got too many arguments");
GLOBAL_STR(str136, "compexport");
GLOBAL_STR(str137, "expected a -c string, like sh -c");
GLOBAL_STR(str138, "jlines");
GLOBAL_STR(str139, "tsv8");
GLOBAL_STR(str140, "TSV8 format not implemented");
GLOBAL_STR(str141, "cd");
GLOBAL_STR(str142, "cd");
GLOBAL_STR(str143, "requires an argument when a block is passed");
GLOBAL_STR(str144, "HOME");
GLOBAL_STR(str145, "got too many arguments");
GLOBAL_STR(str146, "-");
GLOBAL_STR(str147, "OLDPWD");
GLOBAL_STR(str148, "PWD");
GLOBAL_STR(str149, "cd %r: %s");
GLOBAL_STR(str150, "PWD");
GLOBAL_STR(str151, "OLDPWD");
GLOBAL_STR(str152, "%2d  %s");
GLOBAL_STR(str153, " ");
GLOBAL_STR(str154, "pushd");
GLOBAL_STR(str155, "pushd: no other directory");
GLOBAL_STR(str156, "got too many arguments");
GLOBAL_STR(str157, "pushd: %r: %s");
GLOBAL_STR(str158, "HOME");
GLOBAL_STR(str159, "PWD");
GLOBAL_STR(str160, "%s: directory stack is empty");
GLOBAL_STR(str161, "%s: %r: %s");
GLOBAL_STR(str162, "PWD");
GLOBAL_STR(str163, "pushd");
GLOBAL_STR(str164, "got extra argument");
GLOBAL_STR(str165, "popd");
GLOBAL_STR(str166, "HOME");
GLOBAL_STR(str167, "dirs");
GLOBAL_STR(str168, "HOME");
GLOBAL_STR(str169, "pwd");
GLOBAL_STR(str170, "try_");
GLOBAL_STR(str171, "code");
GLOBAL_STR(str172, "failed");
GLOBAL_STR(str173, "code");
GLOBAL_STR(str174, "error");
GLOBAL_STR(str175, "expected a message to display");
GLOBAL_STR(str176, "code");
GLOBAL_STR(str177, "status must be a non-zero integer");
GLOBAL_STR(str178, "boolstatus");
GLOBAL_STR(str179, "expected a command to run");
GLOBAL_STR(str180, "boolstatus expected status 0 or 1, got %d");
GLOBAL_STR(str181, "Expected capture group less than %d, got %d");
GLOBAL_STR(str182, "ERE captures don't have names (%r)");
GLOBAL_STR(str183, "No such group %r");
GLOBAL_STR(str184, "expected Int or Str");
GLOBAL_STR(str185, "No regex capture groups");
GLOBAL_STR(str186, "Couldn't open %r: %s");
GLOBAL_STR(str187, "len() expected Str, List, or Dict");
GLOBAL_STR(str188, "");
GLOBAL_STR(str189, "maybe() expected Str, but got %s");
GLOBAL_STR(str190, "Cannot convert %s to Int");
GLOBAL_STR(str191, "int() expected Bool, Int, Float, or Str");
GLOBAL_STR(str192, "Cannot convert %s to Float");
GLOBAL_STR(str193, "float() expected Int, Float, or Str");
GLOBAL_STR(str194, "str() expected Str, Int, or Float");
GLOBAL_STR(str195, "list() expected Dict, List, or Range");
GLOBAL_STR(str196, "dict() expected Dict or BashAssoc");
GLOBAL_STR(str197, "");
GLOBAL_STR(str198, "space");
GLOBAL_STR(str199, "start_pos");
GLOBAL_STR(str200, "end_pos");
GLOBAL_STR(str201, "expected str");
GLOBAL_STR(str202, "len");
GLOBAL_STR(str203, "get");
GLOBAL_STR(str204, "set");
GLOBAL_STR(str205, "unset");
GLOBAL_STR(str206, "subst");
GLOBAL_STR(str207, "keys");
GLOBAL_STR(str208, "slice");
GLOBAL_STR(str209, "append");
GLOBAL_STR(str210, "Invalid SparseArray operation %r");
GLOBAL_STR(str211, "builtin expects 'define', 'reset' or 'pp'");
GLOBAL_STR(str212, "Recursive 'hay eval' not allowed");
GLOBAL_STR(str213, "source");
GLOBAL_STR(str214, "children");
GLOBAL_STR(str215, "children");
GLOBAL_STR(str216, "children");
GLOBAL_STR(str217, "define");
GLOBAL_STR(str218, "define expected a name");
GLOBAL_STR(str219, "/");
GLOBAL_STR(str220, "got invalid path %r.  Parts can't be empty.");
GLOBAL_STR(str221, "eval");
GLOBAL_STR(str222, "expected variable name");
GLOBAL_STR(str223, ":");
GLOBAL_STR(str224, "eval expected a block");
GLOBAL_STR(str225, "reset");
GLOBAL_STR(str226, "pp");
GLOBAL_STR(str227, "\n");
GLOBAL_STR(str228, "haynode");
GLOBAL_STR(str229, "type");
GLOBAL_STR(str230, "expected at least 1 arg, or a literal block { }");
GLOBAL_STR(str231, "args");
GLOBAL_STR(str232, "command node requires a literal block argument");
GLOBAL_STR(str233, "expr");
GLOBAL_STR(str234, "location_str");
GLOBAL_STR(str235, "location_start_line");
GLOBAL_STR(str236, "code_str");
GLOBAL_STR(str237, "children");
GLOBAL_STR(str238, "_");
GLOBAL_STR(str239, "attrs");
GLOBAL_STR(str240, "e");
GLOBAL_STR(str241, "n");
GLOBAL_STR(str242, "echo");
GLOBAL_STR(str243, "");
GLOBAL_STR(str244, " ");
GLOBAL_STR(str245, "\n");
GLOBAL_STR(str246, "mapfile");
GLOBAL_STR(str247, "MAPFILE");
GLOBAL_STR(str248, "mapfile: read() error: %s");
GLOBAL_STR(str249, "osh I/O error: %s");
GLOBAL_STR(str250, "pp");
GLOBAL_STR(str251, "expected an action (proc, cell, etc.)");
GLOBAL_STR(str252, "cell");
GLOBAL_STR(str253, ":");
GLOBAL_STR(str254, "got invalid variable name %r");
GLOBAL_STR(str255, "Couldn't find a variable named %r");
GLOBAL_STR(str256, "%s = ");
GLOBAL_STR(str257, "\n");
GLOBAL_STR(str258, "asdl");
GLOBAL_STR(str259, "\n");
GLOBAL_STR(str260, "line");
GLOBAL_STR(str261, "(%s)   ");
GLOBAL_STR(str262, "gc-stats");
GLOBAL_STR(str263, "TODO");
GLOBAL_STR(str264, "proc");
GLOBAL_STR(str265, "Invalid proc %r");
GLOBAL_STR(str266, "proc_name\tdoc_comment");
GLOBAL_STR(str267, "");
GLOBAL_STR(str268, "\t");
GLOBAL_STR(str269, "got invalid action %r");
GLOBAL_STR(str270, "write");
GLOBAL_STR(str271, "fopen");
GLOBAL_STR(str272, "expected a block");
GLOBAL_STR(str273, "builtin expects 'read' or 'write'");
GLOBAL_STR(str274, "json8");
GLOBAL_STR(str275, "json");
GLOBAL_STR(str276, "write");
GLOBAL_STR(str277, "json_write");
GLOBAL_STR(str278, "write got too many args");
GLOBAL_STR(str279, "space");
GLOBAL_STR(str280, "%s write: %s");
GLOBAL_STR(str281, "\n");
GLOBAL_STR(str282, "read");
GLOBAL_STR(str283, "json_read");
GLOBAL_STR(str284, "_reply");
GLOBAL_STR(str285, "read got too many args");
GLOBAL_STR(str286, "read error: %s");
GLOBAL_STR(str287, "%s read: %s");
GLOBAL_STR(str288, "eval");
GLOBAL_STR(str289, "requires code string");
GLOBAL_STR(str290, "requires exactly 1 argument");
GLOBAL_STR(str291, " ");
GLOBAL_STR(str292, "eval");
GLOBAL_STR(str293, "eval");
GLOBAL_STR(str294, "source");
GLOBAL_STR(str295, "missing required argument");
GLOBAL_STR(str296, "///");
GLOBAL_STR(str297, "stdlib");
GLOBAL_STR(str298, "source failed: No builtin file %r");
GLOBAL_STR(str299, "source %r failed: %s");
GLOBAL_STR(str300, "source");
GLOBAL_STR(str301, "file");
GLOBAL_STR(str302, "alias");
GLOBAL_STR(str303, "an alias for %s");
GLOBAL_STR(str304, "a shell %s");
GLOBAL_STR(str305, "%s is %s");
GLOBAL_STR(str306, "file");
GLOBAL_STR(str307, "command");
GLOBAL_STR(str308, "%s: not found");
GLOBAL_STR(str309, "Can't run assignment builtin recursively");
GLOBAL_STR(str310, "%r isn't a shell builtin");
GLOBAL_STR(str311, "runproc");
GLOBAL_STR(str312, "requires arguments");
GLOBAL_STR(str313, "runproc: no proc named %r");
GLOBAL_STR(str314, "function");
GLOBAL_STR(str315, "alias");
GLOBAL_STR(str316, "builtin");
GLOBAL_STR(str317, "builtin");
GLOBAL_STR(str318, "builtin");
GLOBAL_STR(str319, "keyword");
GLOBAL_STR(str320, "keyword");
GLOBAL_STR(str321, "file");
GLOBAL_STR(str322, "type");
GLOBAL_STR(str323, "%s: not found");
GLOBAL_STR(str324, "promptVal() expected a single char, got %r");
GLOBAL_STR(str325, "^");
GLOBAL_STR(str326, "^");
GLOBAL_STR(str327, "$");
GLOBAL_STR(str328, "$");
GLOBAL_STR(str329, "expected pattern to be Eggex or Str");
GLOBAL_STR(str330, "expected pattern to be Eggex or Str");
GLOBAL_STR(str331, "expected Eggex or Str");
GLOBAL_STR(str332, "pos");
GLOBAL_STR(str333, "^");
GLOBAL_STR(str334, "^");
GLOBAL_STR(str335, "0");
GLOBAL_STR(str336, "expected expr to eval to a Str");
GLOBAL_STR(str337, "expected pattern to be Eggex or Str");
GLOBAL_STR(str338, "expected substitution to be Str or Expr");
GLOBAL_STR(str339, "count");
GLOBAL_STR(str340, "");
GLOBAL_STR(str341, "https://www.oilshell.org/release");
GLOBAL_STR(str342, "    %s/%s/doc/ref/chap-%s.html#%s");
GLOBAL_STR(str343, "no help topics match %r");
GLOBAL_STR(str344, "help");
GLOBAL_STR(str345, "help");
GLOBAL_STR(str346, "%s-chapters");
GLOBAL_STR(str347, "All docs: https://www.oilshell.org/release/%s/doc/");
GLOBAL_STR(str348, "");
GLOBAL_STR(str349, "source-guard");
GLOBAL_STR(str350, "requires a name");
GLOBAL_STR(str351, "(interactive) Reloading source file %r");
GLOBAL_STR(str352, "expected 'bin' or 'dialect'");
GLOBAL_STR(str353, "dialect");
GLOBAL_STR(str354, "expected dialect name");
GLOBAL_STR(str355, "_DIALECT");
GLOBAL_STR(str356, "Expected dialect %r, got %r");
GLOBAL_STR(str357, "Expected dialect %r");
GLOBAL_STR(str358, "bin");
GLOBAL_STR(str359, "bin %s");
GLOBAL_STR(str360, "expected 'bin' or 'dialect'");
GLOBAL_STR(str361, "# +");
GLOBAL_STR(str362, "osh printf doesn't support the %r flag");
GLOBAL_STR(str363, "eEfFgG");
GLOBAL_STR(str364, "osh printf doesn't support floating point");
GLOBAL_STR(str365, "c");
GLOBAL_STR(str366, "osh printf doesn't support single characters (bytes)");
GLOBAL_STR(str367, "Invalid printf format character");
GLOBAL_STR(str368, "Expected a printf format character");
GLOBAL_STR(str369, "");
GLOBAL_STR(str370, "printf got invalid width %r");
GLOBAL_STR(str371, "0");
GLOBAL_STR(str372, "");
GLOBAL_STR(str373, "printf got invalid precision %r");
GLOBAL_STR(str374, "");
GLOBAL_STR(str375, "s");
GLOBAL_STR(str376, "q");
GLOBAL_STR(str377, "b");
GLOBAL_STR(str378, "");
GLOBAL_STR(str379, "diouxX");
GLOBAL_STR(str380, "'\"");
GLOBAL_STR(str381, "Warning: %s");
GLOBAL_STR(str382, "printf expected an integer, got %r");
GLOBAL_STR(str383, "TZ");
GLOBAL_STR(str384, "TZ");
GLOBAL_STR(str385, "ouxX");
GLOBAL_STR(str386, "Can't format negative number with %%%s: %d");
GLOBAL_STR(str387, "o");
GLOBAL_STR(str388, "x");
GLOBAL_STR(str389, "X");
GLOBAL_STR(str390, "0");
GLOBAL_STR(str391, "-");
GLOBAL_STR(str392, "-");
GLOBAL_STR(str393, "");
GLOBAL_STR(str394, "0");
GLOBAL_STR(str395, "-");
GLOBAL_STR(str396, " ");
GLOBAL_STR(str397, " ");
GLOBAL_STR(str398, "%");
GLOBAL_STR(str399, "printf");
GLOBAL_STR(str400, "requires a format string");
GLOBAL_STR(str401, "printf");
GLOBAL_STR(str402, "");
GLOBAL_STR(str403, "jobs");
GLOBAL_STR(str404, "");
GLOBAL_STR(str405, "No job to put in the foreground");
GLOBAL_STR(str406, "Continue PID %d");
GLOBAL_STR(str407, "isn't implemented");
GLOBAL_STR(str408, "fork");
GLOBAL_STR(str409, "got unexpected argument %r");
GLOBAL_STR(str410, "expected a block");
GLOBAL_STR(str411, "forkwait");
GLOBAL_STR(str412, "got unexpected argument %r");
GLOBAL_STR(str413, "expected a block");
GLOBAL_STR(str414, "exec");
GLOBAL_STR(str415, "exec: %r not found");
GLOBAL_STR(str416, "unreachable");
GLOBAL_STR(str417, "wait");
GLOBAL_STR(str418, "wait");
GLOBAL_STR(str419, "");
GLOBAL_STR(str420, "%");
GLOBAL_STR(str421, "expected PID or jobspec, got %r");
GLOBAL_STR(str422, "%s isn't a child of this shell");
GLOBAL_STR(str423, "0%03o");
GLOBAL_STR(str424, "osh warning: umask with symbolic input isn't implemented");
GLOBAL_STR(str425, "umask: unexpected arguments");
GLOBAL_STR(str426, "unlimited");
GLOBAL_STR(str427, "-c");
GLOBAL_STR(str428, "core dump size");
GLOBAL_STR(str429, "-d");
GLOBAL_STR(str430, "data segment size");
GLOBAL_STR(str431, "-f");
GLOBAL_STR(str432, "file size");
GLOBAL_STR(str433, "-n");
GLOBAL_STR(str434, "file descriptors");
GLOBAL_STR(str435, "-s");
GLOBAL_STR(str436, "stack size");
GLOBAL_STR(str437, "-t");
GLOBAL_STR(str438, "CPU seconds");
GLOBAL_STR(str439, "-v");
GLOBAL_STR(str440, "address space size");
GLOBAL_STR(str441, "ulimit");
GLOBAL_STR(str442, "can only handle one resource at a time; got too many flags");
GLOBAL_STR(str443, "doesn't accept resource flags with -a");
GLOBAL_STR(str444, "got extra arg with -a");
GLOBAL_STR(str445, "%5s %15s %15s %7s  %s");
GLOBAL_STR(str446, "FLAG");
GLOBAL_STR(str447, "SOFT");
GLOBAL_STR(str448, "HARD");
GLOBAL_STR(str449, "FACTOR");
GLOBAL_STR(str450, "DESC");
GLOBAL_STR(str451, "unlimited");
GLOBAL_STR(str452, "expected a number or 'unlimited', got %r");
GLOBAL_STR(str453, "doesn't accept negative numbers, got %r");
GLOBAL_STR(str454, "detected integer overflow: %s");
GLOBAL_STR(str455, "got extra arg");
GLOBAL_STR(str456, "ulimit error: %s");
GLOBAL_STR(str457, "alias");
GLOBAL_STR(str458, "alias %s=%r");
GLOBAL_STR(str459, "=");
GLOBAL_STR(str460, "No alias named %r");
GLOBAL_STR(str461, "alias %s=%r");
GLOBAL_STR(str462, "unalias");
GLOBAL_STR(str463, "requires an argument");
GLOBAL_STR(str464, "No alias named %r");
GLOBAL_STR(str465, "%s=%s");
GLOBAL_STR(str466, "set");
GLOBAL_STR(str467, "shopt");
GLOBAL_STR(str468, "got invalid option %r");
GLOBAL_STR(str469, "hash");
GLOBAL_STR(str470, "got extra arguments after -r");
GLOBAL_STR(str471, "hash: %r not found");
GLOBAL_STR(str472, ":");
GLOBAL_STR(str473, "OPTIND");
GLOBAL_STR(str474, "OPTIND");
GLOBAL_STR(str475, "OPTARG");
GLOBAL_STR(str476, "OPTARG");
GLOBAL_STR(str477, "");
GLOBAL_STR(str478, "?");
GLOBAL_STR(str479, "-");
GLOBAL_STR(str480, "-");
GLOBAL_STR(str481, "?");
GLOBAL_STR(str482, "?");
GLOBAL_STR(str483, "getopts: option %r requires an argument.");
GLOBAL_STR(str484, "(getopts argv: %s)");
GLOBAL_STR(str485, " ");
GLOBAL_STR(str486, "?");
GLOBAL_STR(str487, "");
GLOBAL_STR(str488, "requires an argspec");
GLOBAL_STR(str489, "requires the name of a variable to set");
GLOBAL_STR(str490, "got invalid variable name %r");
GLOBAL_STR(str491, "shvar");
GLOBAL_STR(str492, "expected a block");
GLOBAL_STR(str493, "Expected name=value");
GLOBAL_STR(str494, "=");
GLOBAL_STR(str495, "Expected name=value");
GLOBAL_STR(str496, "PATH");
GLOBAL_STR(str497, "Could not find a context. Did you forget to 'ctx push'?");
GLOBAL_STR(str498, "Expected the context item '%s' to be a List");
GLOBAL_STR(str499, "ctx");
GLOBAL_STR(str500, "Expected a verb (push, set, emit)");
GLOBAL_STR(str501, "push");
GLOBAL_STR(str502, "set");
GLOBAL_STR(str503, "emit");
GLOBAL_STR(str504, "A target field is required");
GLOBAL_STR(str505, "Unknown verb '%s'");
GLOBAL_STR(str506, "push-registers");
GLOBAL_STR(str507, "expected a block");
GLOBAL_STR(str508, "append");
GLOBAL_STR(str509, "expected List or BashArray");
GLOBAL_STR(str510, "");
GLOBAL_STR(str511, "");
GLOBAL_STR(str512, "'");
GLOBAL_STR(str513, "");
GLOBAL_STR(str514, "");
GLOBAL_STR(str515, "Oils read error: %s");
GLOBAL_STR(str516, "Oils read I/O error: %s");
GLOBAL_STR(str517, "_reply");
GLOBAL_STR(str518, "got extra argument");
GLOBAL_STR(str519, "read");
GLOBAL_STR(str520, "doesn't accept typed args without --all, or --num-bytes");
GLOBAL_STR(str521, "read -t isn't implemented (except t=0)");
GLOBAL_STR(str522, "");
GLOBAL_STR(str523, "REPLY");
GLOBAL_STR(str524, "REPLY");
GLOBAL_STR(str525, "");
GLOBAL_STR(str526, "warning: bind isn't implemented");
GLOBAL_STR(str527, "is disabled because Oil wasn't compiled with 'readline'");
GLOBAL_STR(str528, "history");
GLOBAL_STR(str529, "Error writing HISTFILE %r: %s");
GLOBAL_STR(str530, "Error reading HISTFILE %r: %s");
GLOBAL_STR(str531, "couldn't find item %d");
GLOBAL_STR(str532, "got invalid argument %r");
GLOBAL_STR(str533, "got too many arguments");
GLOBAL_STR(str534, "%5d  %s\n");
GLOBAL_STR(str535, "1");
GLOBAL_STR(str536, "2");
GLOBAL_STR(str537, "3");
GLOBAL_STR(str538, "6");
GLOBAL_STR(str539, "9");
GLOBAL_STR(str540, "13");
GLOBAL_STR(str541, "14");
GLOBAL_STR(str542, "15");
GLOBAL_STR(str543, "SIG");
GLOBAL_STR(str544, "EXIT");
GLOBAL_STR(str545, "ERR");
GLOBAL_STR(str546, "RETURN");
GLOBAL_STR(str547, "DEBUG");
GLOBAL_STR(str548, "trap");
GLOBAL_STR(str549, "trap");
GLOBAL_STR(str550, "%s TrapState");
GLOBAL_STR(str551, "%d TrapState");
GLOBAL_STR(str552, "   %s");
GLOBAL_STR(str553, "requires a code string");
GLOBAL_STR(str554, "requires a signal or hook name");
GLOBAL_STR(str555, "0");
GLOBAL_STR(str556, "EXIT");
GLOBAL_STR(str557, "Invalid signal or hook %r");
GLOBAL_STR(str558, "-");
GLOBAL_STR(str559, "Signal or trap");
GLOBAL_STR(str560, "RETURN");
GLOBAL_STR(str561, "osh warning: The %r hook isn't implemented");
GLOBAL_STR(str562, "Signal %r can't be handled");
GLOBAL_STR(str563, "Signal or trap");
GLOBAL_STR(str564, " ");
GLOBAL_STR(str565, "");
GLOBAL_STR(str566, "");
GLOBAL_STR(str567, "");
GLOBAL_STR(str568, "");
GLOBAL_STR(str569, "\u001b[0;0m");
GLOBAL_STR(str570, "\u001b[1m");
GLOBAL_STR(str571, "\u001b[4m");
GLOBAL_STR(str572, "\u001b[7m");
GLOBAL_STR(str573, "\u001b[31m");
GLOBAL_STR(str574, "\u001b[32m");
GLOBAL_STR(str575, "\u001b[33m");
GLOBAL_STR(str576, "\u001b[34m");
GLOBAL_STR(str577, "\u001b[35m");
GLOBAL_STR(str578, "\u001b[36m");
GLOBAL_STR(str579, "");
GLOBAL_STR(str580, "\u0001");
GLOBAL_STR(str581, "\u0002");
GLOBAL_STR(str582, "\n");
GLOBAL_STR(str583, "\n");
GLOBAL_STR(str584, " %s\n");
GLOBAL_STR(str585, " ... and %d more\n");
GLOBAL_STR(str586, "%-");
GLOBAL_STR(str587, "s");
GLOBAL_STR(str588, " ");
GLOBAL_STR(str589, "\n");
GLOBAL_STR(str590, "\n");
GLOBAL_STR(str591, "%");
GLOBAL_STR(str592, "s");
GLOBAL_STR(str593, "... and %d more\n");
GLOBAL_STR(str594, " %-");
GLOBAL_STR(str595, "s ");
GLOBAL_STR(str596, "%s");
GLOBAL_STR(str597, "\n");
GLOBAL_STR(str598, "");
GLOBAL_STR(str599, " %s\n");
GLOBAL_STR(str600, " ... ");
GLOBAL_STR(str601, "%");
GLOBAL_STR(str602, "s");
GLOBAL_STR(str603, "... and %d more\n");
GLOBAL_STR(str604, "\u001b[%dA");
GLOBAL_STR(str605, "\u001b[%dC");
GLOBAL_STR(str606, "DISPLAY POS in _PrintCandidates = %d\n");
GLOBAL_STR(str607, "\n");
GLOBAL_STR(str608, "");
GLOBAL_STR(str609, " ");
GLOBAL_STR(str610, " ");
GLOBAL_STR(str611, " ");
GLOBAL_STR(str612, "\r\n");
GLOBAL_STR(str613, "\u001b[2K");
GLOBAL_STR(str614, "\u001b[1B");
GLOBAL_STR(str615, "\u001b[%dA");
GLOBAL_STR(str616, "tab: complete");
GLOBAL_STR(str617, "set horizontal-scroll-mode on");
GLOBAL_STR(str618, "");
GLOBAL_STR(str619, "invalid (state, ch) pair");
GLOBAL_STR(str620, "  (");
GLOBAL_STR(str621, " %s=%s");
GLOBAL_STR(str622, "1");
GLOBAL_STR(str623, "0");
GLOBAL_STR(str624, " )\n");
GLOBAL_STR(str625, "");
GLOBAL_STR(str626, "");
GLOBAL_STR(str627, "__fallback");
GLOBAL_STR(str628, "__first");
GLOBAL_STR(str629, "<completion.Lookup %s>");
GLOBAL_STR(str630, "[Commands]\n");
GLOBAL_STR(str631, "%s:\n");
GLOBAL_STR(str632, "[Patterns]\n");
GLOBAL_STR(str633, "%s:\n");
GLOBAL_STR(str634, "__fallback");
GLOBAL_STR(str635, "__first");
GLOBAL_STR(str636, "__first");
GLOBAL_STR(str637, "__fallback");
GLOBAL_STR(str638, "<Api %r %d-%d>");
GLOBAL_STR(str639, "???CompletionAction ");
GLOBAL_STR(str640, "UserAction ");
GLOBAL_STR(str641, "TestAction ");
GLOBAL_STR(str642, "DynamicWordsAction ");
GLOBAL_STR(str643, "FileSystemAction ");
GLOBAL_STR(str644, "");
GLOBAL_STR(str645, ".");
GLOBAL_STR(str646, "basename %r");
GLOBAL_STR(str647, "to_list %r");
GLOBAL_STR(str648, "dirname %r");
GLOBAL_STR(str649, "/");
GLOBAL_STR(str650, "TODO-complete-C");
GLOBAL_STR(str651, "[ShellFuncAction %s] ");
GLOBAL_STR(str652, "COMPREPLY");
GLOBAL_STR(str653, "COMP_ARGV");
GLOBAL_STR(str654, ":");
GLOBAL_STR(str655, "=");
GLOBAL_STR(str656, "COMP_WORDS");
GLOBAL_STR(str657, "COMP_CWORD");
GLOBAL_STR(str658, "COMP_LINE");
GLOBAL_STR(str659, "COMP_POINT");
GLOBAL_STR(str660, "Running completion function %r with %d arguments");
GLOBAL_STR(str661, "comp.first %r, commands_changed: %s");
GLOBAL_STR(str662, ", ");
GLOBAL_STR(str663, "Function %r returned 124, but the completion spec for %r wasn't changed");
GLOBAL_STR(str664, "COMPREPLY");
GLOBAL_STR(str665, "osh error: Ran function %r but COMPREPLY was unset");
GLOBAL_STR(str666, "osh error: COMPREPLY should be an array, got %s");
GLOBAL_STR(str667, "> %r");
GLOBAL_STR(str668, "VariablesAction ");
GLOBAL_STR(str669, "ExternalCommandAction ");
GLOBAL_STR(str670, "PATH");
GLOBAL_STR(str671, ":");
GLOBAL_STR(str672, "???Predicate ");
GLOBAL_STR(str673, "DefaultPredicate ");
GLOBAL_STR(str674, "<GlobPredicate %s %r>");
GLOBAL_STR(str675, "GlobPredicate ");
GLOBAL_STR(str676, "  actions: ");
GLOBAL_STR(str677, "\n");
GLOBAL_STR(str678, "  extra: ");
GLOBAL_STR(str679, "\n");
GLOBAL_STR(str680, "  else: ");
GLOBAL_STR(str681, "\n");
GLOBAL_STR(str682, "  predicate: ");
GLOBAL_STR(str683, "\n");
GLOBAL_STR(str684, "  prefix: %s\n");
GLOBAL_STR(str685, "  suffix: %s\n");
GLOBAL_STR(str686, "line: %r");
GLOBAL_STR(str687, "rl_slice from byte %d to %d: %r");
GLOBAL_STR(str688, "");
GLOBAL_STR(str689, "/");
GLOBAL_STR(str690, "/");
GLOBAL_STR(str691, "Completing redirect arg");
GLOBAL_STR(str692, "Error evaluating redirect word: %s");
GLOBAL_STR(str693, "Didn't get a string from redir arg");
GLOBAL_STR(str694, "");
GLOBAL_STR(str695, "");
GLOBAL_STR(str696, "Completing words");
GLOBAL_STR(str697, "After tilde detection");
GLOBAL_STR(str698, "words2:");
GLOBAL_STR(str699, " %s");
GLOBAL_STR(str700, "partial_argv: [%s]");
GLOBAL_STR(str701, ",");
GLOBAL_STR(str702, "alias_first: %s");
GLOBAL_STR(str703, "** DISPLAY_POS = %d");
GLOBAL_STR(str704, "display_pos %d");
GLOBAL_STR(str705, "");
GLOBAL_STR(str706, "Didn't find anything to complete");
GLOBAL_STR(str707, "Got 124, trying again ...");
GLOBAL_STR(str708, "Completing %r ... (Ctrl-C to cancel)");
GLOBAL_STR(str709, "filenames");
GLOBAL_STR(str710, "filenames");
GLOBAL_STR(str711, "filenames");
GLOBAL_STR(str712, "/");
GLOBAL_STR(str713, "nospace");
GLOBAL_STR(str714, "nospace");
GLOBAL_STR(str715, "nospace");
GLOBAL_STR(str716, "");
GLOBAL_STR(str717, " ");
GLOBAL_STR(str718, "");
GLOBAL_STR(str719, "es");
GLOBAL_STR(str720, "... %d match%s for %r in %d ms (Ctrl-C to cancel)");
GLOBAL_STR(str721, "");
GLOBAL_STR(str722, "es");
GLOBAL_STR(str723, "Found %d match%s for %r in %d ms");
GLOBAL_STR(str724, "Api %r %d %d");
GLOBAL_STR(str725, "osh: Ignoring 'exit' in completion plugin");
GLOBAL_STR(str726, "osh: Runtime error while completing: %s");
GLOBAL_STR(str727, "Runtime error while completing: %s");
GLOBAL_STR(str728, "osh: I/O error (completion): %s");
GLOBAL_STR(str729, "Ctrl-C in completion");
GLOBAL_STR(str730, "osh: Unhandled exception while completing: %s");
GLOBAL_STR(str731, "Unhandled exception while completing: %s");
GLOBAL_STR(str732, "msg");
GLOBAL_STR(str733, "source");
GLOBAL_STR(str734, "line_num");
GLOBAL_STR(str735, "line");
GLOBAL_STR(str736, "var_stack");
GLOBAL_STR(str737, "argv_stack");
GLOBAL_STR(str738, "debug_stack");
GLOBAL_STR(str739, "error");
GLOBAL_STR(str740, "status");
GLOBAL_STR(str741, "pid");
GLOBAL_STR(str742, "%d-osh-crash-dump.json");
GLOBAL_STR(str743, "[%d] Wrote crash dump to %s");
GLOBAL_STR(str744, "proc");
GLOBAL_STR(str745, "source");
GLOBAL_STR(str746, "?");
GLOBAL_STR(str747, "(");
GLOBAL_STR(str748, ")");
GLOBAL_STR(str749, " ");
GLOBAL_STR(str750, "(");
GLOBAL_STR(str751, "[%s]=%s");
GLOBAL_STR(str752, ")");
GLOBAL_STR(str753, " ");
GLOBAL_STR(str754, " ");
GLOBAL_STR(str755, " ");
GLOBAL_STR(str756, "\n");
GLOBAL_STR(str757, "argv0");
GLOBAL_STR(str758, "count");
GLOBAL_STR(str759, "pid");
GLOBAL_STR(str760, "metric_argv0");
GLOBAL_STR(str761, "%d.argv0.json");
GLOBAL_STR(str762, "[%d] Wrote metrics dump to %s");
GLOBAL_STR(str763, "");
GLOBAL_STR(str764, "");
GLOBAL_STR(str765, "");
GLOBAL_STR(str766, "");
GLOBAL_STR(str767, "SHX_indent");
GLOBAL_STR(str768, "SHX_punct");
GLOBAL_STR(str769, "SHX_pid_str");
GLOBAL_STR(str770, "PS4");
GLOBAL_STR(str771, "");
GLOBAL_STR(str772, "<ERROR: Can't parse PS4: %s>");
GLOBAL_STR(str773, "");
GLOBAL_STR(str774, "  ");
GLOBAL_STR(str775, "+");
GLOBAL_STR(str776, "|");
GLOBAL_STR(str777, "command %d:");
GLOBAL_STR(str778, "forkwait %d\n");
GLOBAL_STR(str779, "command sub %d\n");
GLOBAL_STR(str780, "proc sub %d\n");
GLOBAL_STR(str781, "here doc %d\n");
GLOBAL_STR(str782, "fork %d\n");
GLOBAL_STR(str783, "part %d\n");
GLOBAL_STR(str784, ";");
GLOBAL_STR(str785, "process %d: status %d\n");
GLOBAL_STR(str786, " %d");
GLOBAL_STR(str787, ">");
GLOBAL_STR(str788, "proc");
GLOBAL_STR(str789, "source");
GLOBAL_STR(str790, "wait");
GLOBAL_STR(str791, "\n");
GLOBAL_STR(str792, "<");
GLOBAL_STR(str793, " ");
GLOBAL_STR(str794, "\n");
GLOBAL_STR(str795, "!");
GLOBAL_STR(str796, "\n");
GLOBAL_STR(str797, ".");
GLOBAL_STR(str798, "exec");
GLOBAL_STR(str799, ".");
GLOBAL_STR(str800, "builtin");
GLOBAL_STR(str801, "\n");
GLOBAL_STR(str802, " ");
GLOBAL_STR(str803, " ");
GLOBAL_STR(str804, "=");
GLOBAL_STR(str805, "\n");
GLOBAL_STR(str806, "?");
GLOBAL_STR(str807, "%s[%d]");
GLOBAL_STR(str808, "%s[%s]");
GLOBAL_STR(str809, "+=");
GLOBAL_STR(str810, "=");
GLOBAL_STR(str811, "\n");
GLOBAL_STR(str812, "+");
GLOBAL_STR(str813, " ");
GLOBAL_STR(str814, "\n");
GLOBAL_STR(str815, "\n");
GLOBAL_STR(str816, " ...");
GLOBAL_STR(str817, "\n");
GLOBAL_STR(str818, "<%s %r>");
GLOBAL_STR(str819, "code");
GLOBAL_STR(str820, "message");
GLOBAL_STR(str821, "%s, got %s");
GLOBAL_STR(str822, " (line %d, offset %d-%d: %r)");
GLOBAL_STR(str823, "/usr/local/sbin");
GLOBAL_STR(str824, "/usr/local/bin");
GLOBAL_STR(str825, "/usr/sbin");
GLOBAL_STR(str826, "/usr/bin");
GLOBAL_STR(str827, "/sbin");
GLOBAL_STR(str828, "/bin");
GLOBAL_STR(str829, "Invalid control flow %r in pipeline / subshell / background");
GLOBAL_STR(str830, "%s builtin I/O error: %s");
GLOBAL_STR(str831, "%r ");
GLOBAL_STR(str832, "%s builtin I/O error: %s");
GLOBAL_STR(str833, "Command evaluated to an empty argv array");
GLOBAL_STR(str834, "Can't run assignment builtin recursively");
GLOBAL_STR(str835, "errexit was disabled for this construct");
GLOBAL_STR(str836, "");
GLOBAL_STR(str837, "Can't run a proc while errexit is disabled. Use 'try' or wrap it in a process with $0 myproc");
GLOBAL_STR(str838, "proc");
GLOBAL_STR(str839, "Unknown command %r while running hay");
GLOBAL_STR(str840, "%r appears to be external. External commands don't accept typed args (OILS-ERR-200)");
GLOBAL_STR(str841, "%r not found (OILS-ERR-100)");
GLOBAL_STR(str842, "for -Wreturn-type in C++");
GLOBAL_STR(str843, "pipeline");
GLOBAL_STR(str844, "status wouldn't be checked (strict_errexit)");
GLOBAL_STR(str845, "eval_unsafe_arith is off");
GLOBAL_STR(str846, "Command subs not allowed here because %s");
GLOBAL_STR(str847, "__cat");
GLOBAL_STR(str848, "osh I/O error (read): %s");
GLOBAL_STR(str849, "Command Sub exited with status %d");
GLOBAL_STR(str850, "");
GLOBAL_STR(str851, "\n");
GLOBAL_STR(str852, "Process subs not allowed here because status wouldn't be checked (strict_errexit)");
GLOBAL_STR(str853, "/dev/fd/%d");
GLOBAL_STR(str854, "/dev/fd/%d");
GLOBAL_STR(str855, "[FANOS] %s");
GLOBAL_STR(str856, "ERROR %s");
GLOBAL_STR(str857, "");
GLOBAL_STR(str858, "Connect stdin and stdout to one end of socketpair() and send control messages.  osh writes debug messages (like this one) to stderr.");
GLOBAL_STR(str859, "protocol error: %s");
GLOBAL_STR(str860, "EOF received");
GLOBAL_STR(str861, "received blob %r");
GLOBAL_STR(str862, " ");
GLOBAL_STR(str863, " ");
GLOBAL_STR(str864, "");
GLOBAL_STR(str865, "GETPID");
GLOBAL_STR(str866, "EVAL");
GLOBAL_STR(str867, "Expected 3 file descriptors");
GLOBAL_STR(str868, "received descriptor %d");
GLOBAL_STR(str869, "PARSE");
GLOBAL_STR(str870, "TODO:PARSE");
GLOBAL_STR(str871, "Invalid command %r");
GLOBAL_STR(str872, "Invalid command %r");
GLOBAL_STR(str873, "OK %s");
GLOBAL_STR(str874, "^C");
GLOBAL_STR(str875, "STATUS\t%r");
GLOBAL_STR(str876, "");
GLOBAL_STR(str877, "%");
GLOBAL_STR(str878, "%%");
GLOBAL_STR(str879, "%+");
GLOBAL_STR(str880, "<_FdFrame %s>");
GLOBAL_STR(str881, "r");
GLOBAL_STR(str882, "mylib.LineReader");
GLOBAL_STR(str883, "w");
GLOBAL_STR(str884, "mylib.Writer");
GLOBAL_STR(str885, "F_DUPFD fd %d: %s");
GLOBAL_STR(str886, "F_GETFD fd %d: %s");
GLOBAL_STR(str887, "dup2(%d, %d): %s");
GLOBAL_STR(str888, "Can't open %r: %s");
GLOBAL_STR(str889, "Error closing descriptor %d: %s");
GLOBAL_STR(str890, "dup2(%d, %d) error: %s");
GLOBAL_STR(str891, "<StdinFromPipe %d %d>");
GLOBAL_STR(str892, "<StdoutToPipe %d %d>");
GLOBAL_STR(str893, "osh: child %d failed to set its process group to %d: %s");
GLOBAL_STR(str894, "osh: parent failed to set process group for PID %d to %d: %s");
GLOBAL_STR(str895, "Hijacked: %s");
GLOBAL_STR(str896, "/bin/sh");
GLOBAL_STR(str897, "/bin/sh");
GLOBAL_STR(str898, "Can't execute %r: %s");
GLOBAL_STR(str899, "[process] %s");
GLOBAL_STR(str900, " ");
GLOBAL_STR(str901, "[subprog] %s");
GLOBAL_STR(str902, "");
GLOBAL_STR(str903, "oils I/O error (subprogram): %s");
GLOBAL_STR(str904, "[here doc writer]");
GLOBAL_STR(str905, "<Process %s %s>");
GLOBAL_STR(str906, "  ");
GLOBAL_STR(str907, "%%%d");
GLOBAL_STR(str908, "%d\n");
GLOBAL_STR(str909, "%s %d %7s ");
GLOBAL_STR(str910, "\n");
GLOBAL_STR(str911, "Fatal error in posix.fork()");
GLOBAL_STR(str912, "[%d] Done PID %d");
GLOBAL_STR(str913, "%d\n");
GLOBAL_STR(str914, "%%%d");
GLOBAL_STR(str915, "  ");
GLOBAL_STR(str916, "%s %d %7s ");
GLOBAL_STR(str917, "\n");
GLOBAL_STR(str918, "Pipeline in state %s");
GLOBAL_STR(str919, "Error setting up last part of pipeline: %s");
GLOBAL_STR(str920, "[%d] Done PGID %d");
GLOBAL_STR(str921, "/dev/tty");
GLOBAL_STR(str922, "osh: Failed to move process group %d to foreground: %s");
GLOBAL_STR(str923, "%-");
GLOBAL_STR(str924, "^%([0-9]+)$");
GLOBAL_STR(str925, "\n");
GLOBAL_STR(str926, "[process debug info]\n");
GLOBAL_STR(str927, "\n");
GLOBAL_STR(str928, "[pipeline debug info]\n");
GLOBAL_STR(str929, "osh: PID %d stopped, but osh didn't start it");
GLOBAL_STR(str930, "");
GLOBAL_STR(str931, "");
GLOBAL_STR(str932, "[PID %d] Stopped with signal %d");
GLOBAL_STR(str933, " \t\n\"'><=;|&(:");
GLOBAL_STR(str934, "/");
GLOBAL_STR(str935, "PATH");
GLOBAL_STR(str936, ":");
GLOBAL_STR(str937, "/");
GLOBAL_STR(str938, "got invalid option %r");
GLOBAL_STR(str939, "got invalid option %r");
GLOBAL_STR(str940, "invalid option %r (try shopt)");
GLOBAL_STR(str941, "SHELLOPTS");
GLOBAL_STR(str942, ":");
GLOBAL_STR(str943, "Syntax options must be set at the top level (outside any function)");
GLOBAL_STR(str944, "Warning: set -o verbose not implemented");
GLOBAL_STR(str945, "SHELLOPTS");
GLOBAL_STR(str946, "%s:%s");
GLOBAL_STR(str947, "SHELLOPTS");
GLOBAL_STR(str948, ":");
GLOBAL_STR(str949, ":");
GLOBAL_STR(str950, "SHELLOPTS");
GLOBAL_STR(str951, "set %so %s");
GLOBAL_STR(str952, "-");
GLOBAL_STR(str953, "+");
GLOBAL_STR(str954, "got invalid option %r");
GLOBAL_STR(str955, "shopt -%s %s");
GLOBAL_STR(str956, "s");
GLOBAL_STR(str957, "u");
GLOBAL_STR(str958, "<_ArgFrame %s %d at %x>");
GLOBAL_STR(str959, "argv");
GLOBAL_STR(str960, "num_shifted");
GLOBAL_STR(str961, "x");
GLOBAL_STR(str962, "r");
GLOBAL_STR(str963, "flags");
GLOBAL_STR(str964, "type");
GLOBAL_STR(str965, "Undef");
GLOBAL_STR(str966, "type");
GLOBAL_STR(str967, "Str");
GLOBAL_STR(str968, "value");
GLOBAL_STR(str969, "type");
GLOBAL_STR(str970, "BashArray");
GLOBAL_STR(str971, "value");
GLOBAL_STR(str972, "type");
GLOBAL_STR(str973, "BashAssoc");
GLOBAL_STR(str974, "value");
GLOBAL_STR(str975, "Can't determine working directory: %s");
GLOBAL_STR(str976, "-1");
GLOBAL_STR(str977, "call_source");
GLOBAL_STR(str978, "call_line_num");
GLOBAL_STR(str979, "call_line");
GLOBAL_STR(str980, "IFS");
GLOBAL_STR(str981, "UID");
GLOBAL_STR(str982, "EUID");
GLOBAL_STR(str983, "PPID");
GLOBAL_STR(str984, "HOSTNAME");
GLOBAL_STR(str985, "OSTYPE");
GLOBAL_STR(str986, "OPTIND");
GLOBAL_STR(str987, "1");
GLOBAL_STR(str988, "PS4");
GLOBAL_STR(str989, "${SHX_indent}${SHX_punct}${SHX_pid_str} ");
GLOBAL_STR(str990, "COMP_WORDBREAKS");
GLOBAL_STR(str991, "SHELLOPTS");
GLOBAL_STR(str992, "SHELLOPTS");
GLOBAL_STR(str993, "");
GLOBAL_STR(str994, "SHELLOPTS");
GLOBAL_STR(str995, "PWD");
GLOBAL_STR(str996, "PWD");
GLOBAL_STR(str997, "PWD");
GLOBAL_STR(str998, "PATH");
GLOBAL_STR(str999, "PATH");
GLOBAL_STR(str1000, "/bin:/usr/bin");
GLOBAL_STR(str1001, "OIL_VERSION");
GLOBAL_STR(str1002, "OILS_VERSION");
GLOBAL_STR(str1003, "LIB_OSH");
GLOBAL_STR(str1004, "///osh");
GLOBAL_STR(str1005, "LIB_YSH");
GLOBAL_STR(str1006, "///ysh");
GLOBAL_STR(str1007, "PWD");
GLOBAL_STR(str1008, "PS1");
GLOBAL_STR(str1009, "PS1");
GLOBAL_STR(str1010, "\\s-\\v\\$ ");
GLOBAL_STR(str1011, "ARGV");
GLOBAL_STR(str1012, "ARGV");
GLOBAL_STR(str1013, "");
GLOBAL_STR(str1014, "");
GLOBAL_STR(str1015, "<Mem");
GLOBAL_STR(str1016, "  -- %d --");
GLOBAL_STR(str1017, "  %s %s");
GLOBAL_STR(str1018, ">");
GLOBAL_STR(str1019, "\n");
GLOBAL_STR(str1020, "\n");
GLOBAL_STR(str1021, "Call");
GLOBAL_STR(str1022, "Source");
GLOBAL_STR(str1023, "Main");
GLOBAL_STR(str1024, "type");
GLOBAL_STR(str1025, "func_name");
GLOBAL_STR(str1026, "type");
GLOBAL_STR(str1027, "source_name");
GLOBAL_STR(str1028, "type");
GLOBAL_STR(str1029, "dollar0");
GLOBAL_STR(str1030, "0");
GLOBAL_STR(str1031, "0");
GLOBAL_STR(str1032, "0");
GLOBAL_STR(str1033, "nameref %r is undefined");
GLOBAL_STR(str1034, "nameref %r contains invalid variable name %r");
GLOBAL_STR(str1035, "Circular nameref %s");
GLOBAL_STR(str1036, " -> ");
GLOBAL_STR(str1037, "Can't assign to place that's no longer on the call stack.");
GLOBAL_STR(str1038, "Container place not implemented");
GLOBAL_STR(str1039, "Can't assign to readonly value %r");
GLOBAL_STR(str1040, "Can't assign to readonly value %r");
GLOBAL_STR(str1041, "Only strings can be exported (strict_array)");
GLOBAL_STR(str1042, "nameref must be a string");
GLOBAL_STR(str1043, "Can't assign to readonly array");
GLOBAL_STR(str1044, "Can't assign to items in a string");
GLOBAL_STR(str1045, "Value of type %s can't be indexed");
GLOBAL_STR(str1046, "Can't assign to readonly associative array");
GLOBAL_STR(str1047, "_status");
GLOBAL_STR(str1048, "_error");
GLOBAL_STR(str1049, "_this_dir");
GLOBAL_STR(str1050, "PIPESTATUS");
GLOBAL_STR(str1051, "_pipeline_status");
GLOBAL_STR(str1052, "_process_sub_status");
GLOBAL_STR(str1053, "BASH_REMATCH");
GLOBAL_STR(str1054, "FUNCNAME");
GLOBAL_STR(str1055, "source");
GLOBAL_STR(str1056, "main");
GLOBAL_STR(str1057, "BASH_SOURCE");
GLOBAL_STR(str1058, "BASH_LINENO");
GLOBAL_STR(str1059, "0");
GLOBAL_STR(str1060, "LINENO");
GLOBAL_STR(str1061, "BASHPID");
GLOBAL_STR(str1062, "_");
GLOBAL_STR(str1063, "SECONDS");
GLOBAL_STR(str1064, "Can't unset readonly variable %r");
GLOBAL_STR(str1065, "%r isn't an array");
GLOBAL_STR(str1066, "$%s isn't defined");
GLOBAL_STR(str1067, "$%s should be a string");
GLOBAL_STR(str1068, "$%s should be a string, got %s");
GLOBAL_STR(str1069, "$%s doesn't look like an integer, got %r");
GLOBAL_STR(str1070, "EOF");
GLOBAL_STR(str1071, "/");
GLOBAL_STR(str1072, "~");
GLOBAL_STR(str1073, "  ");
GLOBAL_STR(str1074, "\n  ");
GLOBAL_STR(str1075, "\t");
GLOBAL_STR(str1076, "\t");
GLOBAL_STR(str1077, " ");
GLOBAL_STR(str1078, "^");
GLOBAL_STR(str1079, "~");
GLOBAL_STR(str1080, "\n");
GLOBAL_STR(str1081, "  ");
GLOBAL_STR(str1082, "\n  ");
GLOBAL_STR(str1083, "\t");
GLOBAL_STR(str1084, "\t");
GLOBAL_STR(str1085, " ");
GLOBAL_STR(str1086, "^\n");
GLOBAL_STR(str1087, "%s:%d: Token starting at column %d is too long: %d bytes (%s)\n");
GLOBAL_STR(str1088, "[ interactive ]");
GLOBAL_STR(str1089, "[ headless ]");
GLOBAL_STR(str1090, "[ -c flag ]");
GLOBAL_STR(str1091, "[ stdin%s ]");
GLOBAL_STR(str1092, "[ %s word at ? ]");
GLOBAL_STR(str1093, "[ %s word at line %d of %s ]");
GLOBAL_STR(str1094, "?");
GLOBAL_STR(str1095, "?");
GLOBAL_STR(str1096, "line %d of %s");
GLOBAL_STR(str1097, "[ var %s at %s ]");
GLOBAL_STR(str1098, "line %d of %s");
GLOBAL_STR(str1099, "[ contents of var %r at %s ]");
GLOBAL_STR(str1100, "[ expansion of alias %r ]");
GLOBAL_STR(str1101, "[ %s in %s ]");
GLOBAL_STR(str1102, "-- %s");
GLOBAL_STR(str1103, "[??? no location ???] %s%s\n");
GLOBAL_STR(str1104, "%s:%d\n");
GLOBAL_STR(str1105, "\n");
GLOBAL_STR(str1106, "%s:%d: %s%s\n");
GLOBAL_STR(str1107, "");
GLOBAL_STR(str1108, "");
GLOBAL_STR(str1109, "");
GLOBAL_STR(str1110, "errexit PID %d: ");
GLOBAL_STR(str1111, "none");
GLOBAL_STR(str1112, "AST not printed.");
GLOBAL_STR(str1113, "%8d %s");
GLOBAL_STR(str1114, "%8d total tokens");
GLOBAL_STR(str1115, "%8d unique tokens IDs");
GLOBAL_STR(str1116, "%8d %s");
GLOBAL_STR(str1117, "%8d total tokens");
GLOBAL_STR(str1118, "%8d tokens with LazyVal()");
GLOBAL_STR(str1119, "%8d unique tokens IDs");
GLOBAL_STR(str1120, "%8d %s");
GLOBAL_STR(str1121, "text");
GLOBAL_STR(str1122, "abbrev-text");
GLOBAL_STR(str1123, "html");
GLOBAL_STR(str1124, "abbrev-html");
GLOBAL_STR(str1125, "abbrev-");
GLOBAL_STR(str1126, "\n");
GLOBAL_STR(str1127, "\n");
GLOBAL_STR(str1128, "");
GLOBAL_STR(str1129, "history: %s");
GLOBAL_STR(str1130, "\n");
GLOBAL_STR(str1131, "%s %s %s\n");
GLOBAL_STR(str1132, "~~~ %s ~~~\n");
GLOBAL_STR(str1133, "\n");
GLOBAL_STR(str1134, "_devbuild/help/%s");
GLOBAL_STR(str1135, "\n");
GLOBAL_STR(str1136, "Oils %s\t\thttps://www.oilshell.org/\n");
GLOBAL_STR(str1137, "\n");
GLOBAL_STR(str1138, "\n");
GLOBAL_STR(str1139, "");
GLOBAL_STR(str1140, " 0x%s");
GLOBAL_STR(str1141, "");
GLOBAL_STR(str1142, "\n");
GLOBAL_STR(str1143, "\n");
GLOBAL_STR(str1144, " ");
GLOBAL_STR(str1145, "[]");
GLOBAL_STR(str1146, "[");
GLOBAL_STR(str1147, ",");
GLOBAL_STR(str1148, "]");
GLOBAL_STR(str1149, "{}");
GLOBAL_STR(str1150, "{");
GLOBAL_STR(str1151, ",");
GLOBAL_STR(str1152, ":");
GLOBAL_STR(str1153, "}");
GLOBAL_STR(str1154, "null");
GLOBAL_STR(str1155, "true");
GLOBAL_STR(str1156, "false");
GLOBAL_STR(str1157, "[ -->%s ]");
GLOBAL_STR(str1158, "Can't encode List%s in object cycle");
GLOBAL_STR(str1159, "{ -->%s }");
GLOBAL_STR(str1160, "Can't encode Dict%s in object cycle");
GLOBAL_STR(str1161, "[");
GLOBAL_STR(str1162, ",");
GLOBAL_STR(str1163, "null");
GLOBAL_STR(str1164, "]");
GLOBAL_STR(str1165, "{");
GLOBAL_STR(str1166, ",");
GLOBAL_STR(str1167, ":");
GLOBAL_STR(str1168, "}");
GLOBAL_STR(str1169, "<%s%s>");
GLOBAL_STR(str1170, "Can't serialize object of type %s");
GLOBAL_STR(str1171, "Single quotes aren't part of JSON; you may want 'json8 read'");
GLOBAL_STR(str1172, "Comments aren't part of JSON; you may want 'json8 read'");
GLOBAL_STR(str1173, "Pure JSON does not accept j\"\" prefix");
GLOBAL_STR(str1174, "Invalid UTF-8 in %s string literal");
GLOBAL_STR(str1175, "J8 Lines can't have unescaped ASCII control chars");
GLOBAL_STR(str1176, "Unexpected EOF while lexing %s string");
GLOBAL_STR(str1177, "Bad backslash escape in %s string");
GLOBAL_STR(str1178, "%s strings can't have unescaped ASCII control chars");
GLOBAL_STR(str1179, "Invalid UTF-8 in %s string literal");
GLOBAL_STR(str1180, "Code point can't be greater than U+10ffff");
GLOBAL_STR(str1181, "\\u{%s} escape is illegal because it's in the surrogate range");
GLOBAL_STR(str1182, "\\y%s escapes not allowed in u'' strings");
GLOBAL_STR(str1183, "J8");
GLOBAL_STR(str1184, "JSON");
GLOBAL_STR(str1185, "");
GLOBAL_STR(str1186, "Expected %s, got %s");
GLOBAL_STR(str1187, "t");
GLOBAL_STR(str1188, "Unexpected EOF while parsing %s");
GLOBAL_STR(str1189, "Invalid token while parsing %s: %s");
GLOBAL_STR(str1190, "Unexpected trailing input");
GLOBAL_STR(str1191, "t");
GLOBAL_STR(str1192, "Unexpected EOF while parsing %s");
GLOBAL_STR(str1193, "Invalid token while parsing %s: %s");
GLOBAL_STR(str1194, "Unexpected trailing input");
GLOBAL_STR(str1195, "%s tok_id %s %d-%d");
GLOBAL_STR(str1196, "Unexpected text after J8 Line (%s)");
GLOBAL_STR(str1197, "Unexpected trailing input in J8 Lines");
GLOBAL_STR(str1198, "\n");
GLOBAL_STR(str1199, "(");
GLOBAL_STR(str1200, ")");
GLOBAL_STR(str1201, "   ");
GLOBAL_STR(str1202, "");
GLOBAL_STR(str1203, "");
GLOBAL_STR(str1204, "");
GLOBAL_STR(str1205, "");
GLOBAL_STR(str1206, " ");
GLOBAL_STR(str1207, " ");
GLOBAL_STR(str1208, "[]");
GLOBAL_STR(str1209, "[");
GLOBAL_STR(str1210, ",");
GLOBAL_STR(str1211, "]");
GLOBAL_STR(str1212, "{}");
GLOBAL_STR(str1213, ": ");
GLOBAL_STR(str1214, "{");
GLOBAL_STR(str1215, ",");
GLOBAL_STR(str1216, " ");
GLOBAL_STR(str1217, "}");
GLOBAL_STR(str1218, "BashArray");
GLOBAL_STR(str1219, "(");
GLOBAL_STR(str1220, ")");
GLOBAL_STR(str1221, "null");
GLOBAL_STR(str1222, "(");
GLOBAL_STR(str1223, " ");
GLOBAL_STR(str1224, "");
GLOBAL_STR(str1225, ")");
GLOBAL_STR(str1226, "BashAssoc");
GLOBAL_STR(str1227, "(");
GLOBAL_STR(str1228, ")");
GLOBAL_STR(str1229, "[");
GLOBAL_STR(str1230, "]=");
GLOBAL_STR(str1231, "(");
GLOBAL_STR(str1232, " ");
GLOBAL_STR(str1233, "");
GLOBAL_STR(str1234, " ");
GLOBAL_STR(str1235, ")");
GLOBAL_STR(str1236, "null");
GLOBAL_STR(str1237, "true");
GLOBAL_STR(str1238, "false");
GLOBAL_STR(str1239, " .. ");
GLOBAL_STR(str1240, "[");
GLOBAL_STR(str1241, "...");
GLOBAL_STR(str1242, "]");
GLOBAL_STR(str1243, "{");
GLOBAL_STR(str1244, "...");
GLOBAL_STR(str1245, "}");
GLOBAL_STR(str1246, "<");
GLOBAL_STR(str1247, ">");
GLOBAL_STR(str1248, "-");
GLOBAL_STR(str1249, "_");
GLOBAL_STR(str1250, "<_Attributes %s>");
GLOBAL_STR(str1251, "<args.Reader %r %d>");
GLOBAL_STR(str1252, "got too many arguments");
GLOBAL_STR(str1253, "expected argument to %r");
GLOBAL_STR(str1254, "-");
GLOBAL_STR(str1255, "expected integer after %s, got %r");
GLOBAL_STR(str1256, "-");
GLOBAL_STR(str1257, "got invalid integer for %s: %s");
GLOBAL_STR(str1258, "-");
GLOBAL_STR(str1259, "expected number after %r, got %r");
GLOBAL_STR(str1260, "-");
GLOBAL_STR(str1261, "got invalid float for %s: %s");
GLOBAL_STR(str1262, "-");
GLOBAL_STR(str1263, "got invalid argument %r to %r, expected one of: %s");
GLOBAL_STR(str1264, "-");
GLOBAL_STR(str1265, "|");
GLOBAL_STR(str1266, "0");
GLOBAL_STR(str1267, "F");
GLOBAL_STR(str1268, "false");
GLOBAL_STR(str1269, "False");
GLOBAL_STR(str1270, "1");
GLOBAL_STR(str1271, "T");
GLOBAL_STR(str1272, "true");
GLOBAL_STR(str1273, "Talse");
GLOBAL_STR(str1274, "got invalid argument to boolean flag: %r");
GLOBAL_STR(str1275, "-");
GLOBAL_STR(str1276, "-");
GLOBAL_STR(str1277, "Invalid option %r");
GLOBAL_STR(str1278, "Expected argument for action");
GLOBAL_STR(str1279, "Invalid action name %r");
GLOBAL_STR(str1280, "--");
GLOBAL_STR(str1281, "--");
GLOBAL_STR(str1282, "=");
GLOBAL_STR(str1283, "got invalid flag %r");
GLOBAL_STR(str1284, "-");
GLOBAL_STR(str1285, "0");
GLOBAL_STR(str1286, "Z");
GLOBAL_STR(str1287, "-");
GLOBAL_STR(str1288, "doesn't accept flag %s");
GLOBAL_STR(str1289, "-");
GLOBAL_STR(str1290, "+");
GLOBAL_STR(str1291, "+");
GLOBAL_STR(str1292, "doesn't accept option %s");
GLOBAL_STR(str1293, "+");
GLOBAL_STR(str1294, "-");
GLOBAL_STR(str1295, "--");
GLOBAL_STR(str1296, "--");
GLOBAL_STR(str1297, "got invalid flag %r");
GLOBAL_STR(str1298, "-");
GLOBAL_STR(str1299, "+");
GLOBAL_STR(str1300, "got invalid flag %r");
GLOBAL_STR(str1301, "-");
GLOBAL_STR(str1302, "got unexpected typed args");
GLOBAL_STR(str1303, "+");
GLOBAL_STR(str1304, "");
GLOBAL_STR(str1305, "<LineLexer at pos %d of line %r>");
GLOBAL_STR(str1306, "");
GLOBAL_STR(str1307, "");
GLOBAL_STR(str1308, "");
GLOBAL_STR(str1309, "for -Wreturn-type in C++");
GLOBAL_STR(str1310, "for -Wreturn-type in C++");
GLOBAL_STR(str1311, "<Trail %s %s %s %s>");
GLOBAL_STR(str1312, "> ");
GLOBAL_STR(str1313, "Here docs aren't allowed in expressions");
GLOBAL_STR(str1314, "\n");
GLOBAL_STR(str1315, "");
GLOBAL_STR(str1316, "^D");
GLOBAL_STR(str1317, "got unexpected typed args");
GLOBAL_STR(str1318, "Expected at least %d typed args, but only got %d");
GLOBAL_STR(str1319, "Arg %d should be a Str");
GLOBAL_STR(str1320, "Arg %d should be a Bool");
GLOBAL_STR(str1321, "Arg %d should be an Int");
GLOBAL_STR(str1322, "Arg %d should be a Float");
GLOBAL_STR(str1323, "Arg %d should be a BashArray");
GLOBAL_STR(str1324, "Arg %d should be a SparseArray");
GLOBAL_STR(str1325, "Arg %d should be a List");
GLOBAL_STR(str1326, "Arg %d should be a Dict");
GLOBAL_STR(str1327, "Arg %d should be a Place");
GLOBAL_STR(str1328, "Arg %d should be a Match");
GLOBAL_STR(str1329, "Arg %d should be an Eggex");
GLOBAL_STR(str1330, "Arg %d should be IO");
GLOBAL_STR(str1331, "Arg %d should be a Expr");
GLOBAL_STR(str1332, "Arg %d should be a Command");
GLOBAL_STR(str1333, "Arg %d should be a Command");
GLOBAL_STR(str1334, "Arg %d should be a LiteralBlock");
GLOBAL_STR(str1335, "Expected a block arg");
GLOBAL_STR(str1336, "Named arg %r should be a Str");
GLOBAL_STR(str1337, "Named arg %r should be a Bool");
GLOBAL_STR(str1338, "Named arg %r should be a Int");
GLOBAL_STR(str1339, "Named arg %r should be a Float");
GLOBAL_STR(str1340, "Named arg %r should be a List");
GLOBAL_STR(str1341, "Named arg %r should be a Dict");
GLOBAL_STR(str1342, "Expected %d typed args, but got %d");
GLOBAL_STR(str1343, ", ");
GLOBAL_STR(str1344, "Got unexpected named args: %s");
GLOBAL_STR(str1345, "The [ operator doesn't apply to this expression");
GLOBAL_STR(str1346, "Expected ]]");
GLOBAL_STR(str1347, "Unexpected trailing word %s");
GLOBAL_STR(str1348, "Invalid argument to unary operator");
GLOBAL_STR(str1349, "Expected ), got %s");
GLOBAL_STR(str1350, "Unexpected token in boolean expression (%s)");
GLOBAL_STR(str1351, "");
GLOBAL_STR(str1352, "Expected %d, got %d");
GLOBAL_STR(str1353, "Step can't be 0");
GLOBAL_STR(str1354, "Invalid step %d for ascending integer range");
GLOBAL_STR(str1355, "Invalid step %d for descending integer range");
GLOBAL_STR(str1356, "Invalid step %d for ascending character range");
GLOBAL_STR(str1357, "Invalid step %d for descending character range");
GLOBAL_STR(str1358, "Mismatched cases in character range");
GLOBAL_STR(str1359, "");
GLOBAL_STR(str1360, "0");
GLOBAL_STR(str1361, "0");
GLOBAL_STR(str1362, "");
GLOBAL_STR(str1363, "Can't append array to string");
GLOBAL_STR(str1364, "Can't append string to array");
GLOBAL_STR(str1365, "Can't append to value of type %s");
GLOBAL_STR(str1366, "Assignment builtin %r not configured");
GLOBAL_STR(str1367, "%s builtin I/O error: %s");
GLOBAL_STR(str1368, "%r ");
GLOBAL_STR(str1369, "%s builtin I/O: %s");
GLOBAL_STR(str1370, "%s failed with status %d");
GLOBAL_STR(str1371, "Brace expansion not allowed (try adding quotes)");
GLOBAL_STR(str1372, "Can't redirect to zero files");
GLOBAL_STR(str1373, "Can't redirect to more than one file");
GLOBAL_STR(str1374, "Redirect descriptor can't be empty");
GLOBAL_STR(str1375, "-");
GLOBAL_STR(str1376, "-");
GLOBAL_STR(str1377, "Invalid descriptor %r.  Expected D, -, or D- where D is an integer");
GLOBAL_STR(str1378, "\n");
GLOBAL_STR(str1379, "Unknown redirect op");
GLOBAL_STR(str1380, "Unknown redirect type");
GLOBAL_STR(str1381, "for -Wreturn-type in C++");
GLOBAL_STR(str1382, "strict_errexit only allows simple commands in conditionals (got %s). ");
GLOBAL_STR(str1383, "strict_errexit only allows a single command.  Hint: use 'try'.");
GLOBAL_STR(str1384, "strict_errexit only allows simple commands in conditionals (got %s). ");
GLOBAL_STR(str1385, "Destructuring assignment expected List");
GLOBAL_STR(str1386, "Got %d places on the left, but %d values on right");
GLOBAL_STR(str1387, "Destructuring assignment expected List");
GLOBAL_STR(str1388, "Got %d places on the left, but %d values on the right");
GLOBAL_STR(str1389, "List index should be Int");
GLOBAL_STR(str1390, "Dict index should be Str");
GLOBAL_STR(str1391, "obj[index] expected List or Dict");
GLOBAL_STR(str1392, "");
GLOBAL_STR(str1393, "ShAssignment builtins don't accept blocks");
GLOBAL_STR(str1394, "|& isn't supported");
GLOBAL_STR(str1395, "");
GLOBAL_STR(str1396, "I/O error during = keyword: %s");
GLOBAL_STR(str1397, "I/O error during = keyword: %s");
GLOBAL_STR(str1398, "%r expected a small integer, got %r");
GLOBAL_STR(str1399, "Invalid control flow at top level");
GLOBAL_STR(str1400, "warning: ");
GLOBAL_STR(str1401, "List iteration expects at most 2 loop variables");
GLOBAL_STR(str1402, "Range iteration expects at most 2 loop variables");
GLOBAL_STR(str1403, "Stdin iteration expects at most 2 loop variables");
GLOBAL_STR(str1404, "for loop expected List, Dict, Range, or Stdin");
GLOBAL_STR(str1405, "Argv iteration expects at most 2 loop variables");
GLOBAL_STR(str1406, "Function %s was already defined (redefine_proc_func)");
GLOBAL_STR(str1407, "Proc %s was already defined (redefine_proc_func)");
GLOBAL_STR(str1408, "Func %s was already defined (redefine_proc_func)");
GLOBAL_STR(str1409, "failglob: ");
GLOBAL_STR(str1410, "I/O error applying redirect: %s");
GLOBAL_STR(str1411, "Fatal error popping redirect: %s");
GLOBAL_STR(str1412, "trap");
GLOBAL_STR(str1413, "failglob: ");
GLOBAL_STR(str1414, "optimizing");
GLOBAL_STR(str1415, "");
GLOBAL_STR(str1416, "Simple optimized");
GLOBAL_STR(str1417, "after opt:");
GLOBAL_STR(str1418, "");
GLOBAL_STR(str1419, "Loop and control flow can't be in different processes");
GLOBAL_STR(str1420, "fatal: ");
GLOBAL_STR(str1421, "Unexpected control flow in block");
GLOBAL_STR(str1422, "EXIT");
GLOBAL_STR(str1423, "trap EXIT");
GLOBAL_STR(str1424, "DEBUG");
GLOBAL_STR(str1425, "trap DEBUG");
GLOBAL_STR(str1426, "ERR");
GLOBAL_STR(str1427, "trap ERR");
GLOBAL_STR(str1428, "Unexpected %r (in proc call)");
GLOBAL_STR(str1429, "Attempted to exit from completion hook.");
GLOBAL_STR(str1430, "Couldn't find terminator for here doc that starts here");
GLOBAL_STR(str1431, "\t");
GLOBAL_STR(str1432, "Invalid here doc delimiter");
GLOBAL_STR(str1433, "%s != %s");
GLOBAL_STR(str1434, "array LHS");
GLOBAL_STR(str1435, "Environment binding shouldn't look like an array assignment");
GLOBAL_STR(str1436, "Expected = in environment binding, got +=");
GLOBAL_STR(str1437, "Environment bindings can't contain array literals");
GLOBAL_STR(str1438, "Commands can't contain array literals");
GLOBAL_STR(str1439, "procs must be defined at the top level");
GLOBAL_STR(str1440, "funcs must be defined at the top level");
GLOBAL_STR(str1441, "shell functions can't be defined inside proc or func");
GLOBAL_STR(str1442, "%r was already declared");
GLOBAL_STR(str1443, "setvar couldn't find matching 'var %s' (OILS-ERR-10)");
GLOBAL_STR(str1444, "Expected word type %s, got %s");
GLOBAL_STR(str1445, "{");
GLOBAL_STR(str1446, "}");
GLOBAL_STR(str1447, "Invalid token after redirect operator");
GLOBAL_STR(str1448, "=word isn't allowed.  Hint: add a space after =, or quote it");
GLOBAL_STR(str1449, "Space required before (");
GLOBAL_STR(str1450, "Unexpected left paren (might need a space before it)");
GLOBAL_STR(str1451, "Empty arg list not allowed");
GLOBAL_STR(str1452, " ");
GLOBAL_STR(str1453, " ");
GLOBAL_STR(str1454, "");
GLOBAL_STR(str1455, "AFTER expansion:");
GLOBAL_STR(str1456, "Unexpected typed args");
GLOBAL_STR(str1457, "Use var/setvar to assign in YSH");
GLOBAL_STR(str1458, "Unexpected typed args");
GLOBAL_STR(str1459, "Control flow shouldn't have redirects");
GLOBAL_STR(str1460, "Control flow shouldn't have environment bindings");
GLOBAL_STR(str1461, "Shell-style returns not allowed here");
GLOBAL_STR(str1462, "Typed return is only allowed inside func");
GLOBAL_STR(str1463, "Typed return expects one argument");
GLOBAL_STR(str1464, "Typed return doesn't take named arguments");
GLOBAL_STR(str1465, "Unexpected typed args");
GLOBAL_STR(str1466, "Unexpected argument to %r");
GLOBAL_STR(str1467, "Invalid word in for loop");
GLOBAL_STR(str1468, "Invalid word after for expression");
GLOBAL_STR(str1469, "Expected loop variable (a constant word)");
GLOBAL_STR(str1470, ",");
GLOBAL_STR(str1471, "Loop variables look like x, y (fix spaces)");
GLOBAL_STR(str1472, "Invalid loop variable name %r");
GLOBAL_STR(str1473, "Unexpected word after 3 loop variables");
GLOBAL_STR(str1474, "Expected { after iterable expression");
GLOBAL_STR(str1475, "Reserved syntax");
GLOBAL_STR(str1476, "Reserved syntax");
GLOBAL_STR(str1477, "Surround this word with either parens or quotes (parse_bare_word)");
GLOBAL_STR(str1478, "Expected at most 2 loop variables");
GLOBAL_STR(str1479, "Unexpected word after for loop variable");
GLOBAL_STR(str1480, "Bash for loops aren't allowed (parse_dparen)");
GLOBAL_STR(str1481, "Expected a condition");
GLOBAL_STR(str1482, "Expected case pattern");
GLOBAL_STR(str1483, "Expected ;; or esac");
GLOBAL_STR(str1484, "Expected case pattern");
GLOBAL_STR(str1485, "This is a constant string.  You may want a variable like $x (parse_bare_word)");
GLOBAL_STR(str1486, "Expected a word to match against");
GLOBAL_STR(str1487, "Bash [[ not allowed in YSH (parse_dbracket)");
GLOBAL_STR(str1488, "Bash (( not allowed in YSH (parse_dparen, see OILS-ERR-14 for wart)");
GLOBAL_STR(str1489, "Unexpected word while parsing compound command (%s)");
GLOBAL_STR(str1490, "Invalid function name");
GLOBAL_STR(str1491, "Expected ) in function definition");
GLOBAL_STR(str1492, "Invalid KSH-style function name");
GLOBAL_STR(str1493, "Unexpected word when parsing command");
GLOBAL_STR(str1494, "proc is a YSH keyword, but this is OSH.");
GLOBAL_STR(str1495, "Expected 'proc' after 'typed'");
GLOBAL_STR(str1496, "typed is a YSH keyword, but this is OSH.");
GLOBAL_STR(str1497, "func is a YSH keyword, but this is OSH.");
GLOBAL_STR(str1498, "const can't be inside proc or func.  Use var instead.");
GLOBAL_STR(str1499, "Unexpected right brace");
GLOBAL_STR(str1500, "Unexpected = (Hint: use var/setvar, or quote it)");
GLOBAL_STR(str1501, "Unexpected EOF while parsing command");
GLOBAL_STR(str1502, "Invalid word while parsing command");
GLOBAL_STR(str1503, "Invalid word while parsing command line (%s)");
GLOBAL_STR(str1504, "Invalid word while parsing command list");
GLOBAL_STR(str1505, "Unterminated here doc began here");
GLOBAL_STR(str1506, "\\");
GLOBAL_STR(str1507, "*");
GLOBAL_STR(str1508, "?");
GLOBAL_STR(str1509, "[");
GLOBAL_STR(str1510, "]");
GLOBAL_STR(str1511, "\\*?[]-:!()|");
GLOBAL_STR(str1512, "\\?*+{}^$.()|[]");
GLOBAL_STR(str1513, "\\");
GLOBAL_STR(str1514, "Unexpected escaped character %r");
GLOBAL_STR(str1515, "");
GLOBAL_STR(str1516, "Malformed character class; treating as literal");
GLOBAL_STR(str1517, "Got unescaped right bracket");
GLOBAL_STR(str1518, "Got unescaped trailing backslash");
GLOBAL_STR(str1519, ".|^$()+*?[]{}\\");
GLOBAL_STR(str1520, "\\");
GLOBAL_STR(str1521, "\\");
GLOBAL_STR(str1522, "\\[");
GLOBAL_STR(str1523, "\\]");
GLOBAL_STR(str1524, "\\\\");
GLOBAL_STR(str1525, "^");
GLOBAL_STR(str1526, ".");
GLOBAL_STR(str1527, ".*");
GLOBAL_STR(str1528, "[");
GLOBAL_STR(str1529, "^");
GLOBAL_STR(str1530, "\\-");
GLOBAL_STR(str1531, "\\]");
GLOBAL_STR(str1532, "]");
GLOBAL_STR(str1533, "-");
GLOBAL_STR(str1534, "]");
GLOBAL_STR(str1535, "");
GLOBAL_STR(str1536, "GlobToERE()");
GLOBAL_STR(str1537, "  %s");
GLOBAL_STR(str1538, "Error expanding glob %r: %s");
GLOBAL_STR(str1539, "-");
GLOBAL_STR(str1540, "history length = %d");
GLOBAL_STR(str1541, "!");
GLOBAL_STR(str1542, "Couldn't parse historical command %r: %s");
GLOBAL_STR(str1543, "^");
GLOBAL_STR(str1544, "No first word in %r");
GLOBAL_STR(str1545, "$");
GLOBAL_STR(str1546, "No last word in %r");
GLOBAL_STR(str1547, "*");
GLOBAL_STR(str1548, "Couldn't find words in %r");
GLOBAL_STR(str1549, "%s: not found");
GLOBAL_STR(str1550, "");
GLOBAL_STR(str1551, "?");
GLOBAL_STR(str1552, "%r found no results");
GLOBAL_STR(str1553, "");
GLOBAL_STR(str1554, "! %s");
GLOBAL_STR(str1555, "<Error: %s> ");
GLOBAL_STR(str1556, "Unbalanced \\[ and \\]");
GLOBAL_STR(str1557, "$");
GLOBAL_STR(str1558, "#");
GLOBAL_STR(str1559, "$");
GLOBAL_STR(str1560, "hostname");
GLOBAL_STR(str1561, "user");
GLOBAL_STR(str1562, "D");
GLOBAL_STR(str1563, "\\D{} not in promptVal()");
GLOBAL_STR(str1564, "$");
GLOBAL_STR(str1565, "$");
GLOBAL_STR(str1566, "u");
GLOBAL_STR(str1567, "user");
GLOBAL_STR(str1568, "h");
GLOBAL_STR(str1569, "hostname");
GLOBAL_STR(str1570, ".");
GLOBAL_STR(str1571, "H");
GLOBAL_STR(str1572, "hostname");
GLOBAL_STR(str1573, "s");
GLOBAL_STR(str1574, "v");
GLOBAL_STR(str1575, "A");
GLOBAL_STR(str1576, "%H:%M");
GLOBAL_STR(str1577, "D");
GLOBAL_STR(str1578, "%X");
GLOBAL_STR(str1579, "w");
GLOBAL_STR(str1580, "PWD");
GLOBAL_STR(str1581, "HOME");
GLOBAL_STR(str1582, "W");
GLOBAL_STR(str1583, "PWD");
GLOBAL_STR(str1584, "PWD is not a string");
GLOBAL_STR(str1585, "\\%s is invalid or unimplemented in $PS1");
GLOBAL_STR(str1586, "\u0001");
GLOBAL_STR(str1587, "\u0002");
GLOBAL_STR(str1588, "D");
GLOBAL_STR(str1589, "$");
GLOBAL_STR(str1590, "\\$");
GLOBAL_STR(str1591, "Invalid token %r %r");
GLOBAL_STR(str1592, "");
GLOBAL_STR(str1593, "");
GLOBAL_STR(str1594, "<ERROR: Can't parse PS1: %s>");
GLOBAL_STR(str1595, "renderPrompt");
GLOBAL_STR(str1596, "renderPrompt() should return Str, got %s");
GLOBAL_STR(str1597, "PS1");
GLOBAL_STR(str1598, "ysh");
GLOBAL_STR(str1599, "ysh ");
GLOBAL_STR(str1600, "PROMPT_COMMAND");
GLOBAL_STR(str1601, "Undefined variable %r");
GLOBAL_STR(str1602, "Can't use [] on value of type %s");
GLOBAL_STR(str1603, "");
GLOBAL_STR(str1604, "Can't use [] on value of type %s");
GLOBAL_STR(str1605, "");
GLOBAL_STR(str1606, "Invalid variable name %r (parse_sh_arith is off)");
GLOBAL_STR(str1607, "dynamic LHS");
GLOBAL_STR(str1608, "got invalid LHS expression");
GLOBAL_STR(str1609, "Invalid var ref expression");
GLOBAL_STR(str1610, "0x");
GLOBAL_STR(str1611, "Invalid hex constant %r");
GLOBAL_STR(str1612, "0");
GLOBAL_STR(str1613, "Invalid octal constant %r");
GLOBAL_STR(str1614, "#");
GLOBAL_STR(str1615, "Invalid base for numeric constant %r");
GLOBAL_STR(str1616, "a");
GLOBAL_STR(str1617, "A");
GLOBAL_STR(str1618, "@");
GLOBAL_STR(str1619, "_");
GLOBAL_STR(str1620, "Invalid digits for numeric constant %r");
GLOBAL_STR(str1621, "Digits %r out of range for base %d");
GLOBAL_STR(str1622, "Parse error in recursive arithmetic");
GLOBAL_STR(str1623, "Invalid integer constant %r");
GLOBAL_STR(str1624, "Invalid integer constant %r");
GLOBAL_STR(str1625, "Invalid integer constant %r");
GLOBAL_STR(str1626, "Undefined value in arithmetic context");
GLOBAL_STR(str1627, "Expected a value convertible to integer, got %s");
GLOBAL_STR(str1628, "0");
GLOBAL_STR(str1629, "Undefined variable %r");
GLOBAL_STR(str1630, "Divide by zero");
GLOBAL_STR(str1631, "Divide by zero");
GLOBAL_STR(str1632, "Value of type Str can't be indexed (strict_arith)");
GLOBAL_STR(str1633, "Value of type Undef can't be indexed (strict_arith)");
GLOBAL_STR(str1634, "Value of type %s can't be indexed");
GLOBAL_STR(str1635, "Divide by zero");
GLOBAL_STR(str1636, "Divide by zero");
GLOBAL_STR(str1637, "Exponent can't be a negative number");
GLOBAL_STR(str1638, "for -Wreturn-type in C++");
GLOBAL_STR(str1639, "Assoc array keys must be strings: $x 'x' \"$x\" etc. (OILS-ERR-101)");
GLOBAL_STR(str1640, "Invalid variable name %r");
GLOBAL_STR(str1641, "Invalid LHS to modify");
GLOBAL_STR(str1642, "-v expected name or name[index]");
GLOBAL_STR(str1643, "-v got BashArray and invalid index %r");
GLOBAL_STR(str1644, "-v got invalid negative index %s");
GLOBAL_STR(str1645, "Expected BashArray or BashAssoc");
GLOBAL_STR(str1646, "%s isn't implemented");
GLOBAL_STR(str1647, " \t\n");
GLOBAL_STR(str1648, "IFS");
GLOBAL_STR(str1649, "IFS shouldn't be an array");
GLOBAL_STR(str1650, " \t\n");
GLOBAL_STR(str1651, "IFS");
GLOBAL_STR(str1652, " ");
GLOBAL_STR(str1653, "");
GLOBAL_STR(str1654, "IFS shouldn't be an array");
GLOBAL_STR(str1655, "for -Wreturn-type in C++");
GLOBAL_STR(str1656, "SPAN %s");
GLOBAL_STR(str1657, "");
GLOBAL_STR(str1658, "\\");
GLOBAL_STR(str1659, "\\");
GLOBAL_STR(str1660, "Invalid transition from %r with %r");
GLOBAL_STR(str1661, "i %d byte %r ch %s current: %s next: %s %s");
GLOBAL_STR(str1662, "UTF-8 decode: Overlong");
GLOBAL_STR(str1663, "UTF-8 decode: Surrogate range");
GLOBAL_STR(str1664, "UTF-8 decode: Integer too large");
GLOBAL_STR(str1665, "UTF-8 decode: Bad encoding");
GLOBAL_STR(str1666, "UTF-8 decode: Truncated bytes");
GLOBAL_STR(str1667, "%s at offset %d in string of %d bytes");
GLOBAL_STR(str1668, "%s at offset %d in string of %d bytes");
GLOBAL_STR(str1669, "Invalid start of UTF-8 sequence");
GLOBAL_STR(str1670, "");
GLOBAL_STR(str1671, "%s can't have an argument");
GLOBAL_STR(str1672, "");
GLOBAL_STR(str1673, "%s can't have an argument");
GLOBAL_STR(str1674, "");
GLOBAL_STR(str1675, "%s can't have an argument");
GLOBAL_STR(str1676, "");
GLOBAL_STR(str1677, "%s can't have an argument");
GLOBAL_STR(str1678, "");
GLOBAL_STR(str1679, "<_GlobReplacer regex %r r %r>");
GLOBAL_STR(str1680, "(%s)");
GLOBAL_STR(str1681, "Error matching regex %r: %s");
GLOBAL_STR(str1682, "^");
GLOBAL_STR(str1683, "$");
GLOBAL_STR(str1684, "\r");
GLOBAL_STR(str1685, "<INVALID CR>");
GLOBAL_STR(str1686, "\n");
GLOBAL_STR(str1687, "<INVALID NEWLINE>");
GLOBAL_STR(str1688, " `~!$&*()[]{}\\|;'\"<>?");
GLOBAL_STR(str1689, "Left-hand side of this assignment is invalid");
GLOBAL_STR(str1690, "Token can't be used in prefix position");
GLOBAL_STR(str1691, "Token can't be used in infix position");
GLOBAL_STR(str1692, "Parser expected %s, got %s");
GLOBAL_STR(str1693, "Unexpected end of input");
GLOBAL_STR(str1694, "POSIX shell arithmetic isn't allowed (parse_sh_arith)");
GLOBAL_STR(str1695, "");
GLOBAL_STR(str1696, "");
GLOBAL_STR(str1697, "");
GLOBAL_STR(str1698, "");
GLOBAL_STR(str1699, "");
GLOBAL_STR(str1700, "");
GLOBAL_STR(str1701, "");
GLOBAL_STR(str1702, "EOF");
GLOBAL_STR(str1703, "T %s");
GLOBAL_STR(str1704, "Code point can't be greater than U+10ffff");
GLOBAL_STR(str1705, "%s escape is illegal because it's in the surrogate range");
GLOBAL_STR(str1706, "");
GLOBAL_STR(str1707, " \t");
GLOBAL_STR(str1708, " \n\r\t");
GLOBAL_STR(str1709, "--");
GLOBAL_STR(str1710, "");
GLOBAL_STR(str1711, "--");
GLOBAL_STR(str1712, "BASH_SOURCE");
GLOBAL_STR(str1713, "FUNCNAME");
GLOBAL_STR(str1714, "BASH_LINENO");
GLOBAL_STR(str1715, "0");
GLOBAL_STR(str1716, "0");
GLOBAL_STR(str1717, "Assignment builtin expected NAME=value, got %r");
GLOBAL_STR(str1718, "+");
GLOBAL_STR(str1719, "\\");
GLOBAL_STR(str1720, "\\\\");
GLOBAL_STR(str1721, "");
GLOBAL_STR(str1722, "Can't substitute into word");
GLOBAL_STR(str1723, "for -Wreturn-type in C++");
GLOBAL_STR(str1724, "");
GLOBAL_STR(str1725, "Array slice can't have negative length: %d");
GLOBAL_STR(str1726, "Can't slice associative arrays");
GLOBAL_STR(str1727, "Slice op expected Str or BashArray");
GLOBAL_STR(str1728, "i");
GLOBAL_STR(str1729, "e");
GLOBAL_STR(str1730, "f");
GLOBAL_STR(str1731, "n");
GLOBAL_STR(str1732, "u");
GLOBAL_STR(str1733, "x");
GLOBAL_STR(str1734, "C");
GLOBAL_STR(str1735, "");
GLOBAL_STR(str1736, "HOME");
GLOBAL_STR(str1737, "Error expanding tilde (e.g. invalid user)");
GLOBAL_STR(str1738, "~");
GLOBAL_STR(str1739, "Can't assign to special variable");
GLOBAL_STR(str1740, "???");
GLOBAL_STR(str1741, "Hint: operator %s means a variable can't be %s");
GLOBAL_STR(str1742, "unset");
GLOBAL_STR(str1743, "empty");
GLOBAL_STR(str1744, ": %r");
GLOBAL_STR(str1745, "");
GLOBAL_STR(str1746, "Var %s is %s%s");
GLOBAL_STR(str1747, "warning: ");
GLOBAL_STR(str1748, "Length op expected Str, BashArray, BashAssoc");
GLOBAL_STR(str1749, "Keys op expected Str");
GLOBAL_STR(str1750, "Indirect expansion of array");
GLOBAL_STR(str1751, "Indirect expansion of assoc array");
GLOBAL_STR(str1752, "Var Ref op expected Str");
GLOBAL_STR(str1753, "Unary op expected Str, BashArray, BashAssoc");
GLOBAL_STR(str1754, "extended globs not supported in ${x//GLOB/}");
GLOBAL_STR(str1755, "");
GLOBAL_STR(str1756, "Pat Sub op expected Str, BashArray, BashAssoc");
GLOBAL_STR(str1757, "warning: ");
GLOBAL_STR(str1758, "");
GLOBAL_STR(str1759, "\u0001");
GLOBAL_STR(str1760, "");
GLOBAL_STR(str1761, "\u0002");
GLOBAL_STR(str1762, "");
GLOBAL_STR(str1763, "Can't use @P on %s");
GLOBAL_STR(str1764, " ");
GLOBAL_STR(str1765, "Can't use @Q on %s");
GLOBAL_STR(str1766, "a");
GLOBAL_STR(str1767, "A");
GLOBAL_STR(str1768, "r");
GLOBAL_STR(str1769, "x");
GLOBAL_STR(str1770, "n");
GLOBAL_STR(str1771, "");
GLOBAL_STR(str1772, "Var op %r not implemented");
GLOBAL_STR(str1773, "Can't index string with @");
GLOBAL_STR(str1774, "Can't index string with *");
GLOBAL_STR(str1775, "Can't index string %r with integer");
GLOBAL_STR(str1776, "Index op expected BashArray, BashAssoc");
GLOBAL_STR(str1777, "");
GLOBAL_STR(str1778, "");
GLOBAL_STR(str1779, "$");
GLOBAL_STR(str1780, "Undefined variable %r");
GLOBAL_STR(str1781, "Undefined array %r");
GLOBAL_STR(str1782, "Array %r can't be referred to as a scalar (without @ or *)");
GLOBAL_STR(str1783, "Test operation not allowed with ${!array[@]}");
GLOBAL_STR(str1784, "Not implemented");
GLOBAL_STR(str1785, "Illegal array word part (strict_array)");
GLOBAL_STR(str1786, " ");
GLOBAL_STR(str1787, "");
GLOBAL_STR(str1788, "Array %r can't be referred to as a scalar (without @ or *)");
GLOBAL_STR(str1789, "@(");
GLOBAL_STR(str1790, "|");
GLOBAL_STR(str1791, ")");
GLOBAL_STR(str1792, "Extended globs and arrays can't appear in the same word");
GLOBAL_STR(str1793, "*");
GLOBAL_STR(str1794, "Unexpected array literal");
GLOBAL_STR(str1795, "Unexpected associative array literal");
GLOBAL_STR(str1796, "(");
GLOBAL_STR(str1797, ")");
GLOBAL_STR(str1798, "ZSH var subs are parsed, but can't be evaluated");
GLOBAL_STR(str1799, "");
GLOBAL_STR(str1800, "");
GLOBAL_STR(str1801, "");
GLOBAL_STR(str1802, "Extended glob %r matched no files");
GLOBAL_STR(str1803, "Extended glob not allowed in this word");
GLOBAL_STR(str1804, "This word should yield a string, but it contains an array");
GLOBAL_STR(str1805, " ");
GLOBAL_STR(str1806, "extended glob not allowed in this word");
GLOBAL_STR(str1807, "");
GLOBAL_STR(str1808, "");
GLOBAL_STR(str1809, "");
GLOBAL_STR(str1810, "<Runtime error: %s>");
GLOBAL_STR(str1811, "<I/O error: %s>");
GLOBAL_STR(str1812, "<Ctrl-C>");
GLOBAL_STR(str1813, "");
GLOBAL_STR(str1814, "");
GLOBAL_STR(str1815, "");
GLOBAL_STR(str1816, "");
GLOBAL_STR(str1817, "Pattern %r matched no files");
GLOBAL_STR(str1818, "");
GLOBAL_STR(str1819, "LHS array not allowed in assignment builtin");
GLOBAL_STR(str1820, "-");
GLOBAL_STR(str1821, "+");
GLOBAL_STR(str1822, "f");
GLOBAL_STR(str1823, "F");
GLOBAL_STR(str1824, "Pattern %r matched no files");
GLOBAL_STR(str1825, "");
GLOBAL_STR(str1826, "Static: part_vals after _EvalWordToParts:");
GLOBAL_STR(str1827, "  %s");
GLOBAL_STR(str1828, "");
GLOBAL_STR(str1829, "Static: frames after _MakeWordFrames:");
GLOBAL_STR(str1830, "  %s");
GLOBAL_STR(str1831, "");
GLOBAL_STR(str1832, "");
GLOBAL_STR(str1833, "part_vals after _EvalWordToParts:");
GLOBAL_STR(str1834, "  %s");
GLOBAL_STR(str1835, "");
GLOBAL_STR(str1836, "frames after _MakeWordFrames:");
GLOBAL_STR(str1837, "  %s");
GLOBAL_STR(str1838, "__NO_COMMAND_SUB__");
GLOBAL_STR(str1839, "__NO_PROCESS_SUB__");
GLOBAL_STR(str1840, "Slice length: Add explicit zero, or omit : for N (strict_parse_slice)");
GLOBAL_STR(str1841, "Expected : or } in slice");
GLOBAL_STR(str1842, "Expected } after replacement string, got %s");
GLOBAL_STR(str1843, "Expected ] to close subscript");
GLOBAL_STR(str1844, "Expected } to close ${");
GLOBAL_STR(str1845, "Expected } to close ${");
GLOBAL_STR(str1846, "Expected a constant argument");
GLOBAL_STR(str1847, "Expected } to close ${");
GLOBAL_STR(str1848, "Expected } to close ${");
GLOBAL_STR(str1849, "Unexpected token in ${} (%s)");
GLOBAL_STR(str1850, "VOp2");
GLOBAL_STR(str1851, "Unexpected token in ${} (%s)");
GLOBAL_STR(str1852, "VOp3");
GLOBAL_STR(str1853, "Expected } to close ${");
GLOBAL_STR(str1854, "Expected } after length expression");
GLOBAL_STR(str1855, "TODO: ${.myproc builtin sub}");
GLOBAL_STR(str1856, "Unexpected token in ${}");
GLOBAL_STR(str1857, "\\");
GLOBAL_STR(str1858, "Strings with backslashes should look like r'\\n' or u'\\n' or b'\\n'");
GLOBAL_STR(str1859, "Use \\xhh or \\u{...} instead of octal escapes in YSH strings");
GLOBAL_STR(str1860, "Invalid hex escape in YSH string (must be \\xHH)");
GLOBAL_STR(str1861, "Invalid char escape in C-style string literal (OILS-ERR-11)");
GLOBAL_STR(str1862, "Unexpected EOF in single-quoted string that began here");
GLOBAL_STR(str1863, "%s escapes not allowed in u'' strings");
GLOBAL_STR(str1864, "'");
GLOBAL_STR(str1865, "Unexpected token after YSH single-quoted string");
GLOBAL_STR(str1866, "\"");
GLOBAL_STR(str1867, "'");
GLOBAL_STR(str1868, "Unexpected EOF reading extended glob that began here");
GLOBAL_STR(str1869, "Expected ) to close bash regex group");
GLOBAL_STR(str1870, "Expected word after ( opening bash regex group");
GLOBAL_STR(str1871, "Invalid char escape in double quoted string (OILS-ERR-12)");
GLOBAL_STR(str1872, "Literal $ should be quoted like \\$");
GLOBAL_STR(str1873, "Invalid backtick: use $(cmd) or \\` in YSH strings");
GLOBAL_STR(str1874, "Unexpected EOF reading double-quoted string that began here");
GLOBAL_STR(str1875, "Use $(cmd) instead of backticks (parse_backticks)");
GLOBAL_STR(str1876, "Unexpected EOF while looking for closing backtick");
GLOBAL_STR(str1877, "");
GLOBAL_STR(str1878, "backticks");
GLOBAL_STR(str1879, "Invalid proc name %s");
GLOBAL_STR(str1880, "Unexpected token after arithmetic expression (%s != %s)");
GLOBAL_STR(str1881, "Expected second ) to end arith sub");
GLOBAL_STR(str1882, "Expected second ) to end arith statement");
GLOBAL_STR(str1883, "Expected ; here");
GLOBAL_STR(str1884, "Expected ; here");
GLOBAL_STR(str1885, "Expected ) to end for loop expression");
GLOBAL_STR(str1886, "Expected ( after =");
GLOBAL_STR(str1887, "Unexpected token in array literal");
GLOBAL_STR(str1888, "Expected associative array pair");
GLOBAL_STR(str1889, "Invalid char escape in unquoted word (OILS-ERR-13)");
GLOBAL_STR(str1890, "Unexpected token after array literal");
GLOBAL_STR(str1891, "Unexpected token after array splice");
GLOBAL_STR(str1892, "Unexpected token after Expr splice");
GLOBAL_STR(str1893, "TODO: @{.myproc builtin sub}");
GLOBAL_STR(str1894, "Literal @ starting a word must be quoted (parse_at_all)");
GLOBAL_STR(str1895, "/");
GLOBAL_STR(str1896, "Literal $ should be quoted like \\$");
GLOBAL_STR(str1897, "Unexpected token after @()");
GLOBAL_STR(str1898, "Invalid token in bash regex");
GLOBAL_STR(str1899, "Word has unbalanced { }.  Maybe add a space or quote it like \\{");
GLOBAL_STR(str1900, "Unexpected parts after triple quoted string");
GLOBAL_STR(str1901, "Unexpected token while parsing arithmetic: %r");
GLOBAL_STR(str1902, "Invalid blank line in multiline mode");
GLOBAL_STR(str1903, "r");
GLOBAL_STR(str1904, "u");
GLOBAL_STR(str1905, "b");
GLOBAL_STR(str1906, "Expected var name");
GLOBAL_STR(str1907, "Expected end of var ref expression");
GLOBAL_STR(str1908, "%s: type=%d, tok=%r");
GLOBAL_STR(str1909, "too much input");
GLOBAL_STR(str1910, "bad input");
GLOBAL_STR(str1911, "&");
GLOBAL_STR(str1912, "&amp;");
GLOBAL_STR(str1913, "<");
GLOBAL_STR(str1914, "&lt;");
GLOBAL_STR(str1915, ">");
GLOBAL_STR(str1916, "&gt;");
GLOBAL_STR(str1917, ".");
GLOBAL_STR(str1918, "/");
GLOBAL_STR(str1919, "/");
GLOBAL_STR(str1920, "/");
GLOBAL_STR(str1921, "%s/%s");
GLOBAL_STR(str1922, "/");
GLOBAL_STR(str1923, "");
GLOBAL_STR(str1924, "/");
GLOBAL_STR(str1925, "/");
GLOBAL_STR(str1926, "/");
GLOBAL_STR(str1927, ".");
GLOBAL_STR(str1928, "");
GLOBAL_STR(str1929, "/");
GLOBAL_STR(str1930, "//");
GLOBAL_STR(str1931, "///");
GLOBAL_STR(str1932, "/");
GLOBAL_STR(str1933, ".");
GLOBAL_STR(str1934, "..");
GLOBAL_STR(str1935, "..");
GLOBAL_STR(str1936, "/");
GLOBAL_STR(str1937, "Empty file with EOF token on invalid line:");
GLOBAL_STR(str1938, "%s");
GLOBAL_STR(str1939, "%5d %-20s %r");
GLOBAL_STR(str1940, "(%d tokens)");
GLOBAL_STR(str1941, "SPID %d = %r");
GLOBAL_STR(str1942, "Invalid here doc delimiter");
GLOBAL_STR(str1943, "<<<");
GLOBAL_STR(str1944, " '''");
GLOBAL_STR(str1945, " \"\"\"");
GLOBAL_STR(str1946, "'''\n");
GLOBAL_STR(str1947, "\"\"\"\n");
GLOBAL_STR(str1948, "setvar ");
GLOBAL_STR(str1949, "set ");
GLOBAL_STR(str1950, "setvar ");
GLOBAL_STR(str1951, " = ");
GLOBAL_STR(str1952, "''");
GLOBAL_STR(str1953, ",");
GLOBAL_STR(str1954, "[");
GLOBAL_STR(str1955, "]");
GLOBAL_STR(str1956, "test");
GLOBAL_STR(str1957, "Got [ without ]");
GLOBAL_STR(str1958, ".");
GLOBAL_STR(str1959, "source");
GLOBAL_STR(str1960, "do {");
GLOBAL_STR(str1961, "shell {");
GLOBAL_STR(str1962, "}");
GLOBAL_STR(str1963, "proc %s ");
GLOBAL_STR(str1964, "{");
GLOBAL_STR(str1965, "}");
GLOBAL_STR(str1966, "for %s in @ARGV ");
GLOBAL_STR(str1967, "while !");
GLOBAL_STR(str1968, "} ");
GLOBAL_STR(str1969, "{");
GLOBAL_STR(str1970, "} ");
GLOBAL_STR(str1971, " {");
GLOBAL_STR(str1972, "}");
GLOBAL_STR(str1973, " (");
GLOBAL_STR(str1974, ") ");
GLOBAL_STR(str1975, "{");
GLOBAL_STR(str1976, " {");
GLOBAL_STR(str1977, "}");
GLOBAL_STR(str1978, "}\n");
GLOBAL_STR(str1979, "}");
GLOBAL_STR(str1980, "''");
GLOBAL_STR(str1981, "'");
GLOBAL_STR(str1982, "'");
GLOBAL_STR(str1983, "\"");
GLOBAL_STR(str1984, "\"");
GLOBAL_STR(str1985, "@ARGV");
GLOBAL_STR(str1986, "\n");
GLOBAL_STR(str1987, "'%s'");
GLOBAL_STR(str1988, "$[join(ARGV)]");
GLOBAL_STR(str1989, "$[join(ARGV)]");
GLOBAL_STR(str1990, "$Argc");
GLOBAL_STR(str1991, "$(");
GLOBAL_STR(str1992, ")");
GLOBAL_STR(str1993, "Undefined variable %r");
GLOBAL_STR(str1994, "List index should be Int");
GLOBAL_STR(str1995, "List index out of range: %d");
GLOBAL_STR(str1996, "Dict index should be Str");
GLOBAL_STR(str1997, "Dict entry not found: %r");
GLOBAL_STR(str1998, "obj[index] expected List or Dict");
GLOBAL_STR(str1999, "Expr splice ");
GLOBAL_STR(str2000, "<Runtime error: %s>");
GLOBAL_STR(str2001, "<I/O error: %s>");
GLOBAL_STR(str2002, "<Ctrl-C>");
GLOBAL_STR(str2003, "Fatal error calling Eggex conversion func %r from this Match accessor");
GLOBAL_STR(str2004, "");
GLOBAL_STR(str2005, "Splice ");
GLOBAL_STR(str2006, "Negation expected Int or Float");
GLOBAL_STR(str2007, "~ expected Int");
GLOBAL_STR(str2008, "for C++ compiler");
GLOBAL_STR(str2009, "Divide by zero");
GLOBAL_STR(str2010, "Divide by zero");
GLOBAL_STR(str2011, "Binary operator expected numbers, got %s and %s (OILS-ERR-201)");
GLOBAL_STR(str2012, "Left operand should be Int");
GLOBAL_STR(str2013, "Right operand should be Int");
GLOBAL_STR(str2014, "Divide by zero");
GLOBAL_STR(str2015, "Divisor can't be negative");
GLOBAL_STR(str2016, "Divide by zero");
GLOBAL_STR(str2017, "Exponent can't be a negative number");
GLOBAL_STR(str2018, "Expected Str ++ Str or List ++ List, got %s ++ %s");
GLOBAL_STR(str2019, "Comparison operator expected numbers, got %s and %s");
GLOBAL_STR(str2020, "Mismatched types");
GLOBAL_STR(str2021, "Mismatched types");
GLOBAL_STR(str2022, "LHS must be Str");
GLOBAL_STR(str2023, "RHS must be Str");
GLOBAL_STR(str2024, "LHS must be Str");
GLOBAL_STR(str2025, "RHS must be Str");
GLOBAL_STR(str2026, "~== expects a string on the left");
GLOBAL_STR(str2027, "true");
GLOBAL_STR(str2028, "false");
GLOBAL_STR(str2029, "~== expects Str, Int, or Bool on the right");
GLOBAL_STR(str2030, "Shouldn't have been bound");
GLOBAL_STR(str2031, "Expected a function or method");
GLOBAL_STR(str2032, "index out of range");
GLOBAL_STR(str2033, "Str index expected Int or Slice");
GLOBAL_STR(str2034, "List index out of range: %d");
GLOBAL_STR(str2035, "List index expected Int or Slice");
GLOBAL_STR(str2036, "Dict index expected Str");
GLOBAL_STR(str2037, "Dict entry not found: %r");
GLOBAL_STR(str2038, "Subscript expected Str, List, or Dict");
GLOBAL_STR(str2039, "Dict entry %r not found");
GLOBAL_STR(str2040, "Dot operator expected Dict");
GLOBAL_STR(str2041, "Method %r does not exist on type %s");
GLOBAL_STR(str2042, "Fat arrow => expects method or function");
GLOBAL_STR(str2043, "_EvalExpr()");
GLOBAL_STR(str2044, "");
GLOBAL_STR(str2045, "Slice begin should be Int");
GLOBAL_STR(str2046, "Slice end should be Int");
GLOBAL_STR(str2047, "Range begin should be Int");
GLOBAL_STR(str2048, "Range end should be Int");
GLOBAL_STR(str2049, "Dict keys must be strings");
GLOBAL_STR(str2050, "List comprehension reserved but not implemented");
GLOBAL_STR(str2051, "Generator expression reserved but not implemented");
GLOBAL_STR(str2052, "Lambda reserved but not implemented");
GLOBAL_STR(str2053, "Eggex char class splice expected Str");
GLOBAL_STR(str2054, "Use unquoted char literal for byte %d, which is >= 128 (avoid confusing a set of bytes with a sequence)");
GLOBAL_STR(str2055, "Expected %r to be a func");
GLOBAL_STR(str2056, "Expected eggex flags %r, but got %r");
GLOBAL_STR(str2057, "Eggex splice expected Str or Eggex");
GLOBAL_STR(str2058, "Use === to be exact, or ~== to convert types");
GLOBAL_STR(str2059, "");
GLOBAL_STR(str2060, " (%s)");
GLOBAL_STR(str2061, "Unexpected token in expression mode%s");
GLOBAL_STR(str2062, "Expected ) to close");
GLOBAL_STR(str2063, "Expected ) to close");
GLOBAL_STR(str2064, "Unexpected token in array literal");
GLOBAL_STR(str2065, "Syntax error in expression (near %s)");
GLOBAL_STR(str2066, "d");
GLOBAL_STR(str2067, "d");
GLOBAL_STR(str2068, "w");
GLOBAL_STR(str2069, "w");
GLOBAL_STR(str2070, "word");
GLOBAL_STR(str2071, "w");
GLOBAL_STR(str2072, "s");
GLOBAL_STR(str2073, "s");
GLOBAL_STR(str2074, "alnum");
GLOBAL_STR(str2075, "cntrl");
GLOBAL_STR(str2076, "lower");
GLOBAL_STR(str2077, "space");
GLOBAL_STR(str2078, "alpha");
GLOBAL_STR(str2079, "digit");
GLOBAL_STR(str2080, "print");
GLOBAL_STR(str2081, "upper");
GLOBAL_STR(str2082, "blank");
GLOBAL_STR(str2083, "graph");
GLOBAL_STR(str2084, "punct");
GLOBAL_STR(str2085, "xdigit");
GLOBAL_STR(str2086, "Range start/end shouldn't have more than one character");
GLOBAL_STR(str2087, "Positional arg can't appear in group of named args");
GLOBAL_STR(str2088, "Only 1 subscript is accepted");
GLOBAL_STR(str2089, "Invalid trailing comma");
GLOBAL_STR(str2090, "Places in containers not implemented yet");
GLOBAL_STR(str2091, "Units suffix not implemented");
GLOBAL_STR(str2092, "unix suffix implemented");
GLOBAL_STR(str2093, "In expressions, remove $ and use `%s`, or sometimes \"$%s\"");
GLOBAL_STR(str2094, "_");
GLOBAL_STR(str2095, "");
GLOBAL_STR(str2096, "Decimal int constant is too large");
GLOBAL_STR(str2097, "Binary int constant is too large");
GLOBAL_STR(str2098, "Octal int constant is too large");
GLOBAL_STR(str2099, "Hex int constant is too large");
GLOBAL_STR(str2100, "Subscript/Attribute not allowed on this LHS expression");
GLOBAL_STR(str2101, "Can't assign to this attribute expr");
GLOBAL_STR(str2102, "Can't assign to this expression");
GLOBAL_STR(str2103, "Multiple assignment must use =");
GLOBAL_STR(str2104, "ERE");
GLOBAL_STR(str2105, "Invalid block expression argument");
GLOBAL_STR(str2106, "Str");
GLOBAL_STR(str2107, "Ref");
GLOBAL_STR(str2108, "Word params may only have type Str or Ref");
GLOBAL_STR(str2109, "Unexpected type parameters");
GLOBAL_STR(str2110, "Only 1 block param is allowed");
GLOBAL_STR(str2111, "Rest param isn't allowed for blocks");
GLOBAL_STR(str2112, "Command");
GLOBAL_STR(str2113, "Block param must have type Command");
GLOBAL_STR(str2114, "Unexpected type parameters");
GLOBAL_STR(str2115, "Quoted range char can't be empty");
GLOBAL_STR(str2116, "This kind of class literal term isn't implemented");
GLOBAL_STR(str2117, "dot");
GLOBAL_STR(str2118, "Can't negate this symbol");
GLOBAL_STR(str2119, "%r isn't a character class");
GLOBAL_STR(str2120, "Can't negate this symbol");
GLOBAL_STR(str2121, "%r isn't a character class");
GLOBAL_STR(str2122, "%start");
GLOBAL_STR(str2123, "%end");
GLOBAL_STR(str2124, "Unexpected token %r in regex");
GLOBAL_STR(str2125, "Backtracking with !! isn't implemented (requires Python/PCRE)");
GLOBAL_STR(str2126, "Perl-style repetition isn't implemented with libc");
GLOBAL_STR(str2127, "");
GLOBAL_STR(str2128, "");
GLOBAL_STR(str2129, "Default values can't be mutable");
GLOBAL_STR(str2130, "Default val for word param must be Str");
GLOBAL_STR(str2131, "Default value for block should be Command or Null");
GLOBAL_STR(str2132, "Spread expected a List");
GLOBAL_STR(str2133, "Spread expected a Dict");
GLOBAL_STR(str2134, "Can't accept both block expression and block literal");
GLOBAL_STR(str2135, "proc %r wasn't passed word param %r");
GLOBAL_STR(str2136, "proc %r takes %d words, but got %d");
GLOBAL_STR(str2137, "%r wasn't passed typed param %r");
GLOBAL_STR(str2138, "%r takes %d typed args, but got %d");
GLOBAL_STR(str2139, "%r wasn't passed named param %r");
GLOBAL_STR(str2140, "%r takes %d named args, but got %d");
GLOBAL_STR(str2141, "Func %r takes no positional args, but got %d");
GLOBAL_STR(str2142, "Func %r takes no named args, but got %d");
GLOBAL_STR(str2143, "Proc %r takes no word args, but got %d");
GLOBAL_STR(str2144, "Proc %r takes no typed args, but got %d");
GLOBAL_STR(str2145, "Proc %r takes no named args, but got %d");
GLOBAL_STR(str2146, "%r wasn't passed block param %r");
GLOBAL_STR(str2147, "Proc %r doesn't accept a block argument");
GLOBAL_STR(str2148, "IntControlFlow in func");
GLOBAL_STR(str2149, "unreachable");
GLOBAL_STR(str2150, "d");
GLOBAL_STR(str2151, "[:digit:]");
GLOBAL_STR(str2152, "w");
GLOBAL_STR(str2153, "[:alpha:][:digit:]_");
GLOBAL_STR(str2154, "s");
GLOBAL_STR(str2155, "[:space:]");
GLOBAL_STR(str2156, "ERE can't express char code %d");
GLOBAL_STR(str2157, "Can't use char %d as start of range in ERE syntax");
GLOBAL_STR(str2158, "-");
GLOBAL_STR(str2159, "Can't use char %d as end of range in ERE syntax");
GLOBAL_STR(str2160, "Perl classes can't be negated in ERE");
GLOBAL_STR(str2161, "%s");
GLOBAL_STR(str2162, "POSIX classes can't be negated in ERE");
GLOBAL_STR(str2163, "[:%s:]");
GLOBAL_STR(str2164, ".");
GLOBAL_STR(str2165, "^");
GLOBAL_STR(str2166, "$");
GLOBAL_STR(str2167, "|");
GLOBAL_STR(str2168, "POSIX EREs don't have groups without capture, so this node needs () around it.");
GLOBAL_STR(str2169, "+");
GLOBAL_STR(str2170, "*");
GLOBAL_STR(str2171, "?");
GLOBAL_STR(str2172, "{%s}");
GLOBAL_STR(str2173, "{%s,%s}");
GLOBAL_STR(str2174, "(");
GLOBAL_STR(str2175, ")");
GLOBAL_STR(str2176, "(");
GLOBAL_STR(str2177, ")");
GLOBAL_STR(str2178, "[^%s]");
GLOBAL_STR(str2179, "[%s]");
GLOBAL_STR(str2180, "[^[:%s:]]");
GLOBAL_STR(str2181, "[[:%s:]]");
GLOBAL_STR(str2182, "[");
GLOBAL_STR(str2183, "^");
GLOBAL_STR(str2184, "]");
GLOBAL_STR(str2185, "\\\\");
GLOBAL_STR(str2186, "^");
GLOBAL_STR(str2187, "-");
GLOBAL_STR(str2188, "]");
GLOBAL_STR(str2189, "");
GLOBAL_STR(str2190, "Flag can't be negated");
GLOBAL_STR(str2191, "i");
GLOBAL_STR(str2192, "reg_icase");
GLOBAL_STR(str2193, "i");
GLOBAL_STR(str2194, "reg_newline");
GLOBAL_STR(str2195, "n");
GLOBAL_STR(str2196, "Invalid regex flag %r");
GLOBAL_STR(str2197, "");
GLOBAL_STR(str2198, "i");
GLOBAL_STR(str2199, "n");
GLOBAL_STR(str2200, "");
GLOBAL_STR(str2201, "null");
GLOBAL_STR(str2202, "true");
GLOBAL_STR(str2203, "false");
GLOBAL_STR(str2204, "%sgot a List, which can't be stringified. Perhaps use @ instead of $, or use join()");
GLOBAL_STR(str2205, "%sexpected Null, Bool, Int, Float, Eggex");
GLOBAL_STR(str2206, "");
GLOBAL_STR(str2207, "%sexpected List");
GLOBAL_STR(str2208, "Shouldn't have called this");
GLOBAL_STR(str2209, "I/O error in for <> loop: %s");
GLOBAL_STR(str2210, "\n");
GLOBAL_STR(str2211, "Equality isn't defined on Float");
GLOBAL_STR(str2212, "Can't compare two values of type %s");
GLOBAL_STR(str2213, "LHS of 'in' should be Str");
GLOBAL_STR(str2214, "RHS of 'in' should be Dict");
GLOBAL_STR(str2215, "Expected Str or Regex for RHS of ~");
GLOBAL_STR(str2216, "LHS must be a string");
GLOBAL_STR(str2217, "");
GLOBAL_STR(str2218, "!");
GLOBAL_STR(str2219, "--");
GLOBAL_STR(str2220, "--dir");
GLOBAL_STR(str2221, "--exists");
GLOBAL_STR(str2222, "--file");
GLOBAL_STR(str2223, "--symlink");
GLOBAL_STR(str2224, "Expected unary operator, got %r (2 args)");
GLOBAL_STR(str2225, "-a");
GLOBAL_STR(str2226, "-o");
GLOBAL_STR(str2227, "!");
GLOBAL_STR(str2228, "(");
GLOBAL_STR(str2229, ")");
GLOBAL_STR(str2230, "Expected binary operator, got %r (3 args)");
GLOBAL_STR(str2231, "should be invoked as 'test' (simple_test_builtin)");
GLOBAL_STR(str2232, "]");
GLOBAL_STR(str2233, "missing closing ]");
GLOBAL_STR(str2234, "should only have 3 arguments or fewer (simple_test_builtin)");
GLOBAL_STR(str2235, "!");
GLOBAL_STR(str2236, "(");
GLOBAL_STR(str2237, ")");
GLOBAL_STR(str2238, "(test) ");
GLOBAL_STR(str2239, "(test) ");
GLOBAL_STR(str2240, "FixedWordsAction ");
GLOBAL_STR(str2241, "DynamicProcDictAction ");
GLOBAL_STR(str2242, "DynamicStrDictAction ");
GLOBAL_STR(str2243, "function %r not found");
GLOBAL_STR(str2244, "osh warning: complete -C not implemented");
GLOBAL_STR(str2245, "alias");
GLOBAL_STR(str2246, "binding");
GLOBAL_STR(str2247, "vi-delete");
GLOBAL_STR(str2248, "builtin");
GLOBAL_STR(str2249, "command");
GLOBAL_STR(str2250, "directory");
GLOBAL_STR(str2251, "export");
GLOBAL_STR(str2252, "file");
GLOBAL_STR(str2253, "function");
GLOBAL_STR(str2254, "job");
GLOBAL_STR(str2255, "jobs-not-implemented");
GLOBAL_STR(str2256, "keyword");
GLOBAL_STR(str2257, "user");
GLOBAL_STR(str2258, "variable");
GLOBAL_STR(str2259, "helptopic");
GLOBAL_STR(str2260, "setopt");
GLOBAL_STR(str2261, "shopt");
GLOBAL_STR(str2262, "signal");
GLOBAL_STR(str2263, "TODO:signals");
GLOBAL_STR(str2264, "stopped");
GLOBAL_STR(str2265, "jobs-not-implemented");
GLOBAL_STR(str2266, "plusdirs");
GLOBAL_STR(str2267, "default");
GLOBAL_STR(str2268, "dirnames");
GLOBAL_STR(str2269, "No actions defined in completion: %s");
GLOBAL_STR(str2270, " ");
GLOBAL_STR(str2271, "!");
GLOBAL_STR(str2272, "");
GLOBAL_STR(str2273, "");
GLOBAL_STR(str2274, "complete");
GLOBAL_STR(str2275, "__fallback");
GLOBAL_STR(str2276, "__first");
GLOBAL_STR(str2277, "expected 1 or more commands");
GLOBAL_STR(str2278, "compgen");
GLOBAL_STR(str2279, "");
GLOBAL_STR(str2280, "");
GLOBAL_STR(str2281, "compgen");
GLOBAL_STR(str2282, "");
GLOBAL_STR(str2283, "compopt");
GLOBAL_STR(str2284, "compopt: not currently executing a completion function");
GLOBAL_STR(str2285, "compadjust");
GLOBAL_STR(str2286, "cur");
GLOBAL_STR(str2287, "prev");
GLOBAL_STR(str2288, "words");
GLOBAL_STR(str2289, "cword");
GLOBAL_STR(str2290, "Invalid output variable name %r");
GLOBAL_STR(str2291, "COMP_ARGV");
GLOBAL_STR(str2292, "COMP_ARGV should be an array");
GLOBAL_STR(str2293, ":");
GLOBAL_STR(str2294, "=");
GLOBAL_STR(str2295, "=");
GLOBAL_STR(str2296, "");
GLOBAL_STR(str2297, "words");
GLOBAL_STR(str2298, "words");
GLOBAL_STR(str2299, "");
GLOBAL_STR(str2300, "--");
GLOBAL_STR(str2301, "=");
GLOBAL_STR(str2302, "=");
GLOBAL_STR(str2303, "true");
GLOBAL_STR(str2304, "false");
GLOBAL_STR(str2305, "split");
GLOBAL_STR(str2306, "cur");
GLOBAL_STR(str2307, "cur");
GLOBAL_STR(str2308, "prev");
GLOBAL_STR(str2309, "prev");
GLOBAL_STR(str2310, "cword");
GLOBAL_STR(str2311, "cword");
GLOBAL_STR(str2312, "-E");
GLOBAL_STR(str2313, "-A");
GLOBAL_STR(str2314, "command");
GLOBAL_STR(str2315, "-D");
GLOBAL_STR(str2316, "-A");
GLOBAL_STR(str2317, "file");
GLOBAL_STR(str2318, "foo.py");
GLOBAL_STR(str2319, "foo");
GLOBAL_STR(str2320, "bar.py");
GLOBAL_STR(str2321, "m%d");
GLOBAL_STR(str2322, "");
GLOBAL_STR(str2323, "");
GLOBAL_STR(str2324, "slowc");
GLOBAL_STR(str2325, "vi");
GLOBAL_STR(str2326, "emacs");
GLOBAL_STR(str2327, "set editing-mode ");
GLOBAL_STR(str2328, "Warning: Can't set option %r because shell wasn't compiled with GNU readline");
GLOBAL_STR(str2329, "vi");
GLOBAL_STR(str2330, "emacs");
GLOBAL_STR(str2331, "osh");
GLOBAL_STR(str2332, "HISTFILE");
GLOBAL_STR(str2333, "YSH_HISTFILE");
GLOBAL_STR(str2334, ".local/share/oils/%s_history");
GLOBAL_STR(str2335, "main");
GLOBAL_STR(str2336, "%s usage error: %s");
GLOBAL_STR(str2337, "%s-usage");
GLOBAL_STR(str2338, "cat-em");
GLOBAL_STR(str2339, "cat-em: %r not found");
GLOBAL_STR(str2340, "ysh");
GLOBAL_STR(str2341, "ysh:all");
GLOBAL_STR(str2342, "--one-pass-parse requires noexec (-n)");
GLOBAL_STR(str2343, "completion");
GLOBAL_STR(str2344, "history");
GLOBAL_STR(str2345, "");
GLOBAL_STR(str2346, "OILS_DEBUG_DIR");
GLOBAL_STR(str2347, "%d-osh.log");
GLOBAL_STR(str2348, "%s: Couldn't open %r: %s");
GLOBAL_STR(str2349, "OILS_TRACE_DIR");
GLOBAL_STR(str2350, "");
GLOBAL_STR(str2351, "OILS_TRACE_DUMPS");
GLOBAL_STR(str2352, "");
GLOBAL_STR(str2353, "OILS_TRACE_STREAMS");
GLOBAL_STR(str2354, "");
GLOBAL_STR(str2355, "%Y-%m-%d %H:%M:%S");
GLOBAL_STR(str2356, "%s [%d] Oils started with argv %s");
GLOBAL_STR(str2357, "Writing logs to %r");
GLOBAL_STR(str2358, "OILS_HIJACK_SHEBANG");
GLOBAL_STR(str2359, "");
GLOBAL_STR(str2360, "OILS_CRASH_DUMP_DIR");
GLOBAL_STR(str2361, "");
GLOBAL_STR(str2362, "%s: Failed to get home dir from $HOME or getpwuid()");
GLOBAL_STR(str2363, "startsWith");
GLOBAL_STR(str2364, "endsWith");
GLOBAL_STR(str2365, "trim");
GLOBAL_STR(str2366, "trimStart");
GLOBAL_STR(str2367, "trimEnd");
GLOBAL_STR(str2368, "upper");
GLOBAL_STR(str2369, "lower");
GLOBAL_STR(str2370, "find");
GLOBAL_STR(str2371, "replace");
GLOBAL_STR(str2372, "search");
GLOBAL_STR(str2373, "leftMatch");
GLOBAL_STR(str2374, "fullMatch");
GLOBAL_STR(str2375, "get");
GLOBAL_STR(str2376, "erase");
GLOBAL_STR(str2377, "keys");
GLOBAL_STR(str2378, "values");
GLOBAL_STR(str2379, "inc");
GLOBAL_STR(str2380, "accum");
GLOBAL_STR(str2381, "reverse");
GLOBAL_STR(str2382, "append");
GLOBAL_STR(str2383, "extend");
GLOBAL_STR(str2384, "pop");
GLOBAL_STR(str2385, "insert");
GLOBAL_STR(str2386, "remove");
GLOBAL_STR(str2387, "indexOf");
GLOBAL_STR(str2388, "join");
GLOBAL_STR(str2389, "group");
GLOBAL_STR(str2390, "start");
GLOBAL_STR(str2391, "end");
GLOBAL_STR(str2392, "eval");
GLOBAL_STR(str2393, "captureStdout");
GLOBAL_STR(str2394, "promptVal");
GLOBAL_STR(str2395, "time");
GLOBAL_STR(str2396, "strftime");
GLOBAL_STR(str2397, "setValue");
GLOBAL_STR(str2398, "export");
GLOBAL_STR(str2399, "parseHay");
GLOBAL_STR(str2400, "evalHay");
GLOBAL_STR(str2401, "_hay");
GLOBAL_STR(str2402, "len");
GLOBAL_STR(str2403, "type");
GLOBAL_STR(str2404, "repeat");
GLOBAL_STR(str2405, "_group");
GLOBAL_STR(str2406, "_match");
GLOBAL_STR(str2407, "_start");
GLOBAL_STR(str2408, "_end");
GLOBAL_STR(str2409, "join");
GLOBAL_STR(str2410, "maybe");
GLOBAL_STR(str2411, "evalExpr");
GLOBAL_STR(str2412, "bool");
GLOBAL_STR(str2413, "int");
GLOBAL_STR(str2414, "float");
GLOBAL_STR(str2415, "str");
GLOBAL_STR(str2416, "list");
GLOBAL_STR(str2417, "dict");
GLOBAL_STR(str2418, "runes");
GLOBAL_STR(str2419, "encodeRunes");
GLOBAL_STR(str2420, "bytes");
GLOBAL_STR(str2421, "encodeBytes");
GLOBAL_STR(str2422, "split");
GLOBAL_STR(str2423, "shSplit");
GLOBAL_STR(str2424, "glob");
GLOBAL_STR(str2425, "shvarGet");
GLOBAL_STR(str2426, "getVar");
GLOBAL_STR(str2427, "assert_");
GLOBAL_STR(str2428, "toJson8");
GLOBAL_STR(str2429, "toJson");
GLOBAL_STR(str2430, "fromJson8");
GLOBAL_STR(str2431, "fromJson");
GLOBAL_STR(str2432, "_a2sp");
GLOBAL_STR(str2433, "_d2sp");
GLOBAL_STR(str2434, "_opsp");
GLOBAL_STR(str2435, "_io");
GLOBAL_STR(str2436, "_guts");
GLOBAL_STR(str2437, "stdin");
GLOBAL_STR(str2438, " -i");
GLOBAL_STR(str2439, "");
GLOBAL_STR(str2440, "%s: Couldn't open %r: %s");
GLOBAL_STR(str2441, ".config/oils");
GLOBAL_STR(str2442, "%s/%src");
GLOBAL_STR(str2443, "%s/%src.d");
GLOBAL_STR(str2444, "*");
GLOBAL_STR(str2445, "%s warning: --rcfile ignored with --norc");
GLOBAL_STR(str2446, "%s warning: --rcdir ignored with --norc");
GLOBAL_STR(str2447, "nice");
GLOBAL_STR(str2448, "%s warning: --rcfile ignored in non-interactive shell");
GLOBAL_STR(str2449, "%s warning: --rcdir ignored in non-interactive shell");
GLOBAL_STR(str2450, "syntax-tree");
GLOBAL_STR(str2451, "syntax-tree");
GLOBAL_STR(str2452, "syntax-tree");
GLOBAL_STR(str2453, "tokens");
GLOBAL_STR(str2454, "lossless-cat");
GLOBAL_STR(str2455, "fmt");
GLOBAL_STR(str2456, "test");
GLOBAL_STR(str2457, "TODO");
GLOBAL_STR(str2458, "ysh-ify");
GLOBAL_STR(str2459, "deps");

namespace runtime {  // forward declare

  class TraversalState;

}  // forward declare namespace runtime

namespace vm {  // forward declare

  class ControlFlow;
  class IntControlFlow;
  class ValueControlFlow;
  class _Executor;
  class _AssignBuiltin;
  class _Builtin;
  class _Callable;
  class ctx_Redirect;
  class ctx_ProcessSub;
  class ctx_FlushStdout;

}  // forward declare namespace vm

namespace format {  // forward declare

  class ColorOutput;
  class TextOutput;
  class HtmlOutput;
  class AnsiOutput;
  class _PrettyPrinter;

}  // forward declare namespace format

namespace oils_for_unix {  // forward declare


}  // forward declare namespace oils_for_unix

namespace assign_osh {  // forward declare

  class Export;
  class Readonly;
  class NewVar;
  class Unset;
  class Shift;

}  // forward declare namespace assign_osh

namespace completion_ysh {  // forward declare

  class CompExport;

}  // forward declare namespace completion_ysh

namespace dirs_osh {  // forward declare

  class DirStack;
  class ctx_CdBlock;
  class Cd;
  class Pushd;
  class Popd;
  class Dirs;
  class Pwd;

}  // forward declare namespace dirs_osh

namespace error_ysh {  // forward declare

  class ctx_Try;
  class Try;
  class Failed;
  class Error;
  class BoolStatus;

}  // forward declare namespace error_ysh

namespace func_eggex {  // forward declare

  class _MatchCallable;
  class MatchFunc;
  class MatchMethod;

}  // forward declare namespace func_eggex

namespace func_hay {  // forward declare

  class ParseHay;
  class EvalHay;
  class BlockAsStr;
  class HayFunc;

}  // forward declare namespace func_hay

namespace func_misc {  // forward declare

  class Len;
  class Type;
  class Repeat;
  class Join;
  class Maybe;
  class Bool;
  class Int;
  class Float;
  class Str_;
  class List_;
  class Dict_;
  class Runes;
  class EncodeRunes;
  class Bytes;
  class EncodeBytes;
  class Split;
  class Glob;
  class Shvar_get;
  class GetVar;
  class Assert;
  class EvalExpr;
  class ToJson8;
  class FromJson8;
  class BashArrayToSparse;
  class DictToSparse;
  class SparseOp;

}  // forward declare namespace func_misc

namespace hay_ysh {  // forward declare

  class ctx_HayNode;
  class ctx_HayEval;
  class HayState;
  class Hay;
  class HayNode_;

}  // forward declare namespace hay_ysh

namespace io_osh {  // forward declare

  class Echo;
  class MapFile;
  class Cat;

}  // forward declare namespace io_osh

namespace io_ysh {  // forward declare

  class _Builtin;
  class Pp;
  class Write;
  class Fopen;

}  // forward declare namespace io_ysh

namespace json_ysh {  // forward declare

  class Json;

}  // forward declare namespace json_ysh

namespace meta_osh {  // forward declare

  class Eval;
  class Source;
  class Command;
  class Builtin;
  class RunProc;
  class Type;

}  // forward declare namespace meta_osh

namespace method_dict {  // forward declare

  class Keys;
  class Values;

}  // forward declare namespace method_dict

namespace method_io {  // forward declare

  class Eval;
  class CaptureStdout;
  class PromptVal;
  class Time;
  class Strftime;

}  // forward declare namespace method_io

namespace method_list {  // forward declare

  class Append;
  class Extend;
  class Pop;
  class Reverse;
  class IndexOf;

}  // forward declare namespace method_list

namespace method_other {  // forward declare

  class SetValue;

}  // forward declare namespace method_other

namespace method_str {  // forward declare

  class HasAffix;
  class Trim;
  class Upper;
  class Lower;
  class SearchMatch;
  class ctx_EvalReplace;
  class Replace;

}  // forward declare namespace method_str

namespace misc_osh {  // forward declare

  class Times;
  class Help;

}  // forward declare namespace misc_osh

namespace module_ysh {  // forward declare

  class IsMain;
  class SourceGuard;
  class Use;

}  // forward declare namespace module_ysh

namespace printf_osh {  // forward declare

  class _FormatStringParser;
  class _PrintfState;
  class Printf;

}  // forward declare namespace printf_osh

namespace process_osh {  // forward declare

  class Jobs;
  class Fg;
  class Bg;
  class Fork;
  class ForkWait;
  class Exec;
  class Wait;
  class Umask;
  class Ulimit;

}  // forward declare namespace process_osh

namespace pure_osh {  // forward declare

  class Boolean;
  class Alias;
  class UnAlias;
  class Set;
  class Shopt;
  class Hash;
  class GetOptsState;
  class GetOpts;

}  // forward declare namespace pure_osh

namespace pure_ysh {  // forward declare

  class ctx_Shvar;
  class Shvar;
  class ctx_Context;
  class Ctx;
  class PushRegisters;
  class Append;

}  // forward declare namespace pure_ysh

namespace read_osh {  // forward declare

  class ctx_TermAttrs;
  class Read;

}  // forward declare namespace read_osh

namespace readline_osh {  // forward declare

  class Bind;
  class History;

}  // forward declare namespace readline_osh

namespace trap_osh {  // forward declare

  class TrapState;
  class Trap;

}  // forward declare namespace trap_osh

namespace alloc {  // forward declare

  class ctx_SourceCode;
  class Arena;
  class LosslessArena;
  class DynamicArena;

}  // forward declare namespace alloc

namespace ansi {  // forward declare


}  // forward declare namespace ansi

namespace comp_ui {  // forward declare

  class PromptState;
  class State;
  class _IDisplay;
  class MinimalDisplay;
  class NiceDisplay;

}  // forward declare namespace comp_ui

namespace completion {  // forward declare

  class _RetryCompletion;
  class OptionState;
  class ctx_Completing;
  class Lookup;
  class Api;
  class CompletionAction;
  class UsersAction;
  class TestAction;
  class DynamicWordsAction;
  class FileSystemAction;
  class CommandAction;
  class ShellFuncAction;
  class VariablesAction;
  class ExportedVarsAction;
  class ExternalCommandAction;
  class _Predicate;
  class DefaultPredicate;
  class GlobPredicate;
  class UserSpec;
  class RootCompleter;
  class ReadlineCallback;

}  // forward declare namespace completion

namespace dev {  // forward declare

  class CrashDumper;
  class ctx_Tracer;
  class MultiTracer;
  class Tracer;

}  // forward declare namespace dev

namespace error {  // forward declare

  class _ErrorWithLocation;
  class Usage;
  class Parse;
  class FailGlob;
  class RedirectEval;
  class FatalRuntime;
  class Strict;
  class ErrExit;
  class Expr;
  class Structured;
  class AssertionErr;
  class TypeErrVerbose;
  class TypeErr;
  class Runtime;
  class Decode;
  class Encode;

}  // forward declare namespace error

namespace executor {  // forward declare

  class _ProcessSubFrame;
  class ShellExecutor;

}  // forward declare namespace executor

namespace main_loop {  // forward declare

  class ctx_Descriptors;
  class Headless;

}  // forward declare namespace main_loop

namespace num {  // forward declare


}  // forward declare namespace num

namespace process {  // forward declare

  class ctx_FileCloser;
  class _RedirFrame;
  class _FdFrame;
  class FdState;
  class ChildStateChange;
  class StdinFromPipe;
  class StdoutToPipe;
  class SetPgid;
  class ExternalProgram;
  class Thunk;
  class ExternalThunk;
  class SubProgramThunk;
  class _HereDocWriterThunk;
  class Job;
  class Process;
  class ctx_Pipe;
  class Pipeline;
  class ctx_TerminalControl;
  class JobControl;
  class JobList;
  class Waiter;

}  // forward declare namespace process

namespace state {  // forward declare

  class SearchPath;
  class ctx_Source;
  class ctx_DebugTrap;
  class ctx_ErrTrap;
  class ctx_Option;
  class ctx_AssignBuiltin;
  class ctx_YshExpr;
  class ctx_ErrExit;
  class OptHook;
  class MutableOpts;
  class _ArgFrame;
  class ctx_FuncCall;
  class ctx_ProcCall;
  class ctx_Temp;
  class ctx_Registers;
  class ctx_ThisDir;
  class Mem;

}  // forward declare namespace state

namespace ui {  // forward declare

  class ctx_Location;
  class ErrorFormatter;

}  // forward declare namespace ui

namespace util {  // forward declare

  class UserExit;
  class HistoryError;
  class _DebugFile;
  class NullDebugFile;
  class DebugFile;

}  // forward declare namespace util

namespace j8 {  // forward declare

  class InstancePrinter;
  class PrettyPrinter;
  class LexerDecoder;
  class _Parser;
  class Parser;
  class Nil8Parser;
  class J8LinesParser;

}  // forward declare namespace j8

namespace j8_lite {  // forward declare


}  // forward declare namespace j8_lite

namespace pretty {  // forward declare

  class PrettyPrinter;
  class _DocConstructor;

}  // forward declare namespace pretty

namespace args {  // forward declare

  class _Attributes;
  class Reader;
  class _Action;
  class _ArgAction;
  class SetToInt;
  class SetToFloat;
  class SetToString;
  class SetAttachedBool;
  class SetToTrue;
  class SetOption;
  class SetNamedOption;
  class SetAction;
  class SetNamedAction;

}  // forward declare namespace args

namespace flag_util {  // forward declare


}  // forward declare namespace flag_util

namespace lexer {  // forward declare

  class LineLexer;
  class Lexer;

}  // forward declare namespace lexer

namespace location {  // forward declare


}  // forward declare namespace location

namespace parse_lib {  // forward declare

  class _BaseTrail;
  class ctx_Alias;
  class Trail;
  class ParseContext;

}  // forward declare namespace parse_lib

namespace reader {  // forward declare

  class _Reader;
  class DisallowedLineReader;
  class FileLineReader;
  class VirtualLineReader;
  class InteractiveLineReader;

}  // forward declare namespace reader

namespace typed_args {  // forward declare

  class Reader;

}  // forward declare namespace typed_args

namespace arith_parse {  // forward declare


}  // forward declare namespace arith_parse

namespace bool_parse {  // forward declare

  class BoolParser;

}  // forward declare namespace bool_parse

namespace braces {  // forward declare

  class _NotARange;
  class _RangeParser;
  class _StackFrame;

}  // forward declare namespace braces

namespace cmd_eval {  // forward declare

  class Deps;
  class ctx_LoopLevel;
  class CommandEvaluator;

}  // forward declare namespace cmd_eval

namespace cmd_parse {  // forward declare

  class VarChecker;
  class ctx_VarChecker;
  class ctx_CmdMode;
  class CommandParser;

}  // forward declare namespace cmd_parse

namespace glob_ {  // forward declare

  class _GlobParser;
  class Globber;

}  // forward declare namespace glob_

namespace history {  // forward declare

  class Evaluator;

}  // forward declare namespace history

namespace prompt {  // forward declare

  class _PromptEvaluatorCache;
  class Evaluator;
  class UserPlugin;

}  // forward declare namespace prompt

namespace sh_expr_eval {  // forward declare

  class UnsafeArith;
  class ArithEvaluator;
  class BoolEvaluator;

}  // forward declare namespace sh_expr_eval

namespace split {  // forward declare

  class SplitContext;
  class _BaseSplitter;
  class IfsSplitter;

}  // forward declare namespace split

namespace string_ops {  // forward declare

  class GlobReplacer;

}  // forward declare namespace string_ops

namespace tdop {  // forward declare

  class TdopParser;

}  // forward declare namespace tdop

namespace word_ {  // forward declare

  class ctx_EmitDocToken;
  class ctx_Multiline;

}  // forward declare namespace word_

namespace word_compile {  // forward declare


}  // forward declare namespace word_compile

namespace word_eval {  // forward declare

  class StringWordEvaluator;
  class TildeEvaluator;
  class AbstractWordEvaluator;
  class NormalWordEvaluator;
  class CompletionWordEvaluator;

}  // forward declare namespace word_eval

namespace word_parse {  // forward declare

  class WordEmitter;
  class WordParser;

}  // forward declare namespace word_parse

namespace parse {  // forward declare

  class ParseError;
  class _StackItem;
  class Parser;

}  // forward declare namespace parse

namespace cgi {  // forward declare


}  // forward declare namespace cgi

namespace os_path {  // forward declare


}  // forward declare namespace os_path

namespace fmt {  // forward declare


}  // forward declare namespace fmt

namespace ysh_ify {  // forward declare

  class Cursor;
  class YshPrinter;

}  // forward declare namespace ysh_ify

namespace expr_eval {  // forward declare

  class ExprEvaluator;
  class EggexEvaluator;

}  // forward declare namespace expr_eval

namespace expr_parse {  // forward declare

  class ExprParser;
  class ctx_PNodeAllocator;

}  // forward declare namespace expr_parse

namespace expr_to_ast {  // forward declare

  class Transformer;

}  // forward declare namespace expr_to_ast

namespace func_proc {  // forward declare


}  // forward declare namespace func_proc

namespace regex_translate {  // forward declare


}  // forward declare namespace regex_translate

namespace val_ops {  // forward declare

  class Iterator;
  class StdinIterator;
  class ArrayIter;
  class RangeIterator;
  class ListIterator;
  class DictIterator;

}  // forward declare namespace val_ops

namespace bracket_osh {  // forward declare

  class _StringWordEmitter;
  class _WordEvaluator;
  class Test;

}  // forward declare namespace bracket_osh

namespace completion_osh {  // forward declare

  class _FixedWordsAction;
  class _DynamicProcDictAction;
  class _DynamicStrDictAction;
  class SpecBuilder;
  class Complete;
  class CompGen;
  class CompOpt;
  class CompAdjust;

}  // forward declare namespace completion_osh

namespace shell {  // forward declare

  class ShellOptHook;
  class ShellFiles;

}  // forward declare namespace shell

namespace runtime {  // declare

using hnode_asdl::hnode;
extern int NO_SPID;
hnode::Record* NewRecord(BigStr* node_type);
hnode::Leaf* NewLeaf(BigStr* s, hnode_asdl::color_t e_color);
class TraversalState {
 public:
  TraversalState();
  Dict<int, bool>* seen;
  Dict<int, int>* ref_count;

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassScanned(2, sizeof(TraversalState));
  }

  DISALLOW_COPY_AND_ASSIGN(TraversalState)
};

extern BigStr* TRUE_STR;
extern BigStr* FALSE_STR;

}  // declare namespace runtime

namespace vm {  // declare

using id_kind_asdl::Id;
class ControlFlow {
 public:

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassScanned(0, sizeof(ControlFlow));
  }

  DISALLOW_COPY_AND_ASSIGN(ControlFlow)
};

class IntControlFlow {
 public:
  IntControlFlow(syntax_asdl::Token* token, int arg);
  bool IsReturn();
  bool IsBreak();
  bool IsContinue();
  int StatusCode();
  runtime_asdl::flow_t HandleLoop();
  syntax_asdl::Token* token;
  int arg;

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassScanned(1, sizeof(IntControlFlow));
  }

  DISALLOW_COPY_AND_ASSIGN(IntControlFlow)
};

class ValueControlFlow {
 public:
  ValueControlFlow(syntax_asdl::Token* token, value_asdl::value_t* value);
  syntax_asdl::Token* token;
  value_asdl::value_t* value;

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassScanned(2, sizeof(ValueControlFlow));
  }

  DISALLOW_COPY_AND_ASSIGN(ValueControlFlow)
};

void InitUnsafeArith(state::Mem* mem, word_eval::NormalWordEvaluator* word_ev, sh_expr_eval::UnsafeArith* unsafe_arith);
void InitCircularDeps(sh_expr_eval::ArithEvaluator* arith_ev, sh_expr_eval::BoolEvaluator* bool_ev, expr_eval::ExprEvaluator* expr_ev, word_eval::NormalWordEvaluator* word_ev, cmd_eval::CommandEvaluator* cmd_ev, vm::_Executor* shell_ex, prompt::Evaluator* prompt_ev, value::IO* global_io, dev::Tracer* tracer);
class _Executor {
 public:
  _Executor();
  virtual void CheckCircularDeps();
  virtual int RunBuiltin(int builtin_id, cmd_value::Argv* cmd_val);
  virtual int RunSimpleCommand(cmd_value::Argv* cmd_val, runtime_asdl::CommandStatus* cmd_st, int run_flags);
  virtual int RunBackgroundJob(syntax_asdl::command_t* node);
  virtual void RunPipeline(command::Pipeline* node, runtime_asdl::CommandStatus* status_out);
  virtual int RunSubshell(syntax_asdl::command_t* node);
  virtual BigStr* RunCommandSub(syntax_asdl::CommandSub* cs_part);
  virtual BigStr* RunProcessSub(syntax_asdl::CommandSub* cs_part);
  virtual void PushRedirects(List<runtime_asdl::RedirValue*>* redirects, List<IOError_OSError*>* err_out);
  virtual void PopRedirects(int num_redirects, List<IOError_OSError*>* err_out);
  virtual void PushProcessSub();
  virtual void PopProcessSub(runtime_asdl::StatusArray* compound_st);
  cmd_eval::CommandEvaluator* cmd_ev;
  
  static constexpr uint32_t field_mask() {
    return maskbit(offsetof(_Executor, cmd_ev));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(_Executor));
  }

  DISALLOW_COPY_AND_ASSIGN(_Executor)
};

class _AssignBuiltin {
 public:
  _AssignBuiltin();
  virtual int Run(cmd_value::Assign* cmd_val);
  
  static constexpr uint32_t field_mask() {
    return kZeroMask;
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(_AssignBuiltin));
  }

  DISALLOW_COPY_AND_ASSIGN(_AssignBuiltin)
};

class _Builtin {
 public:
  _Builtin();
  virtual int Run(cmd_value::Argv* cmd_val);
  
  static constexpr uint32_t field_mask() {
    return kZeroMask;
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(_Builtin));
  }

  DISALLOW_COPY_AND_ASSIGN(_Builtin)
};

class _Callable {
 public:
  _Callable();
  virtual value_asdl::value_t* Call(typed_args::Reader* args);
  
  static constexpr uint32_t field_mask() {
    return kZeroMask;
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(_Callable));
  }

  DISALLOW_COPY_AND_ASSIGN(_Callable)
};

class ctx_Redirect {
 public:
  ctx_Redirect(vm::_Executor* shell_ex, int num_redirects, List<IOError_OSError*>* err_out);
  ~ctx_Redirect();
  vm::_Executor* shell_ex;
  List<IOError_OSError*>* err_out;
  int num_redirects;

  DISALLOW_COPY_AND_ASSIGN(ctx_Redirect)
};

class ctx_ProcessSub {
 public:
  ctx_ProcessSub(vm::_Executor* shell_ex, runtime_asdl::StatusArray* process_sub_status);
  ~ctx_ProcessSub();
  vm::_Executor* shell_ex;
  runtime_asdl::StatusArray* process_sub_status;

  DISALLOW_COPY_AND_ASSIGN(ctx_ProcessSub)
};

class ctx_FlushStdout {
 public:
  ctx_FlushStdout(List<IOError_OSError*>* err_out);
  ~ctx_FlushStdout();
  List<IOError_OSError*>* err_out;

  DISALLOW_COPY_AND_ASSIGN(ctx_FlushStdout)
};


}  // declare namespace vm

namespace format {  // declare

using hnode_asdl::hnode;
format::ColorOutput* DetectConsoleOutput(mylib::Writer* f);
class ColorOutput {
 public:
  ColorOutput(mylib::Writer* f);
  virtual format::ColorOutput* NewTempBuffer();
  virtual void FileHeader();
  virtual void FileFooter();
  virtual void PushColor(hnode_asdl::color_t e_color);
  virtual void PopColor();
  virtual void write(BigStr* s);
  void WriteRaw(Tuple2<BigStr*, int>* raw);
  int NumChars();
  Tuple2<BigStr*, int> GetRaw();
  mylib::Writer* f;
  int num_chars;
  
  static constexpr uint32_t field_mask() {
    return maskbit(offsetof(ColorOutput, f));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(ColorOutput));
  }

  DISALLOW_COPY_AND_ASSIGN(ColorOutput)
};

class TextOutput : public ::format::ColorOutput {
 public:
  TextOutput(mylib::Writer* f);
  virtual format::TextOutput* NewTempBuffer();
  virtual void PushColor(hnode_asdl::color_t e_color);
  virtual void PopColor();
  
  static constexpr uint32_t field_mask() {
    return ::format::ColorOutput::field_mask();
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(TextOutput));
  }

  DISALLOW_COPY_AND_ASSIGN(TextOutput)
};

class HtmlOutput : public ::format::ColorOutput {
 public:
  HtmlOutput(mylib::Writer* f);
  virtual format::HtmlOutput* NewTempBuffer();
  virtual void FileHeader();
  virtual void FileFooter();
  virtual void PushColor(hnode_asdl::color_t e_color);
  virtual void PopColor();
  virtual void write(BigStr* s);
  
  static constexpr uint32_t field_mask() {
    return ::format::ColorOutput::field_mask();
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(HtmlOutput));
  }

  DISALLOW_COPY_AND_ASSIGN(HtmlOutput)
};

class AnsiOutput : public ::format::ColorOutput {
 public:
  AnsiOutput(mylib::Writer* f);
  virtual format::AnsiOutput* NewTempBuffer();
  virtual void PushColor(hnode_asdl::color_t e_color);
  virtual void PopColor();
  
  static constexpr uint32_t field_mask() {
    return ::format::ColorOutput::field_mask();
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(AnsiOutput));
  }

  DISALLOW_COPY_AND_ASSIGN(AnsiOutput)
};

extern int INDENT;
class _PrettyPrinter {
 public:
  _PrettyPrinter(int max_col);
  bool _PrintWrappedArray(List<hnode_asdl::hnode_t*>* array, int prefix_len, format::ColorOutput* f, int indent);
  bool _PrintWholeArray(List<hnode_asdl::hnode_t*>* array, int prefix_len, format::ColorOutput* f, int indent);
  void _PrintRecord(hnode::Record* node, format::ColorOutput* f, int indent);
  void PrintNode(hnode_asdl::hnode_t* node, format::ColorOutput* f, int indent);
  int max_col;

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassScanned(0, sizeof(_PrettyPrinter));
  }

  DISALLOW_COPY_AND_ASSIGN(_PrettyPrinter)
};

bool _TrySingleLineObj(hnode::Record* node, format::ColorOutput* f, int max_chars);
bool _TrySingleLine(hnode_asdl::hnode_t* node, format::ColorOutput* f, int max_chars);
void PrintTree(hnode_asdl::hnode_t* node, format::ColorOutput* f);

}  // declare namespace format

namespace oils_for_unix {  // declare

using syntax_asdl::loc;
int CaperDispatch();
int AppBundleMain(List<BigStr*>* argv);
int main(List<BigStr*>* argv);

}  // declare namespace oils_for_unix

namespace assign_osh {  // declare

using runtime_asdl::scope_e;
using runtime_asdl::cmd_value;
using syntax_asdl::loc;
extern int _OTHER;
extern int _READONLY;
extern int _EXPORT;
int _PrintVariables(state::Mem* mem, cmd_value::Assign* cmd_val, args::_Attributes* attrs, bool print_flags, int builtin = _OTHER);
void _ExportReadonly(state::Mem* mem, runtime_asdl::AssignArg* pair, int flags);
class Export : public ::vm::_AssignBuiltin {
 public:
  Export(state::Mem* mem, ui::ErrorFormatter* errfmt);
  virtual int Run(cmd_value::Assign* cmd_val);

  ui::ErrorFormatter* errfmt;
  state::Mem* mem;
  
  static constexpr uint32_t field_mask() {
    return ::vm::_AssignBuiltin::field_mask()
         | maskbit(offsetof(Export, errfmt))
         | maskbit(offsetof(Export, mem));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(Export));
  }

  DISALLOW_COPY_AND_ASSIGN(Export)
};

value_asdl::value_t* _ReconcileTypes(value_asdl::value_t* rval, bool flag_a, bool flag_A, syntax_asdl::word_t* blame_word);
class Readonly : public ::vm::_AssignBuiltin {
 public:
  Readonly(state::Mem* mem, ui::ErrorFormatter* errfmt);
  virtual int Run(cmd_value::Assign* cmd_val);

  ui::ErrorFormatter* errfmt;
  state::Mem* mem;
  
  static constexpr uint32_t field_mask() {
    return ::vm::_AssignBuiltin::field_mask()
         | maskbit(offsetof(Readonly, errfmt))
         | maskbit(offsetof(Readonly, mem));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(Readonly));
  }

  DISALLOW_COPY_AND_ASSIGN(Readonly)
};

class NewVar : public ::vm::_AssignBuiltin {
 public:
  NewVar(state::Mem* mem, Dict<BigStr*, value::Proc*>* procs, optview::Exec* exec_opts, ui::ErrorFormatter* errfmt);
  int _PrintFuncs(List<BigStr*>* names);
  virtual int Run(cmd_value::Assign* cmd_val);

  ui::ErrorFormatter* errfmt;
  optview::Exec* exec_opts;
  state::Mem* mem;
  Dict<BigStr*, value::Proc*>* procs;
  
  static constexpr uint32_t field_mask() {
    return ::vm::_AssignBuiltin::field_mask()
         | maskbit(offsetof(NewVar, errfmt))
         | maskbit(offsetof(NewVar, exec_opts))
         | maskbit(offsetof(NewVar, mem))
         | maskbit(offsetof(NewVar, procs));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(NewVar));
  }

  DISALLOW_COPY_AND_ASSIGN(NewVar)
};

class Unset : public ::vm::_Builtin {
 public:
  Unset(state::Mem* mem, Dict<BigStr*, value::Proc*>* procs, sh_expr_eval::UnsafeArith* unsafe_arith, ui::ErrorFormatter* errfmt);
  bool _UnsetVar(BigStr* arg, syntax_asdl::loc_t* location, bool proc_fallback);
  virtual int Run(cmd_value::Argv* cmd_val);

  ui::ErrorFormatter* errfmt;
  state::Mem* mem;
  Dict<BigStr*, value::Proc*>* procs;
  sh_expr_eval::UnsafeArith* unsafe_arith;
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Builtin::field_mask()
         | maskbit(offsetof(Unset, errfmt))
         | maskbit(offsetof(Unset, mem))
         | maskbit(offsetof(Unset, procs))
         | maskbit(offsetof(Unset, unsafe_arith));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(Unset));
  }

  DISALLOW_COPY_AND_ASSIGN(Unset)
};

class Shift : public ::vm::_Builtin {
 public:
  Shift(state::Mem* mem);
  virtual int Run(cmd_value::Argv* cmd_val);

  state::Mem* mem;
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Builtin::field_mask()
         | maskbit(offsetof(Shift, mem));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(Shift));
  }

  DISALLOW_COPY_AND_ASSIGN(Shift)
};


}  // declare namespace assign_osh

namespace completion_ysh {  // declare

using syntax_asdl::loc;
class CompExport : public ::vm::_Builtin {
 public:
  CompExport(completion::RootCompleter* root_comp);
  virtual int Run(cmd_value::Argv* cmd_val);

  completion::RootCompleter* root_comp;
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Builtin::field_mask()
         | maskbit(offsetof(CompExport, root_comp));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(CompExport));
  }

  DISALLOW_COPY_AND_ASSIGN(CompExport)
};


}  // declare namespace completion_ysh

namespace dirs_osh {  // declare

using runtime_asdl::cmd_value;
class DirStack {
 public:
  DirStack();
  void Reset();
  void Replace(BigStr* d);
  void Push(BigStr* entry);
  BigStr* Pop();
  List<BigStr*>* Iter();
  List<BigStr*>* stack;

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassScanned(1, sizeof(DirStack));
  }

  DISALLOW_COPY_AND_ASSIGN(DirStack)
};

class ctx_CdBlock {
 public:
  ctx_CdBlock(dirs_osh::DirStack* dir_stack, BigStr* dest_dir, state::Mem* mem, ui::ErrorFormatter* errfmt, List<bool>* out_errs);
  ~ctx_CdBlock();
  dirs_osh::DirStack* dir_stack;
  state::Mem* mem;
  ui::ErrorFormatter* errfmt;
  List<bool>* out_errs;

  DISALLOW_COPY_AND_ASSIGN(ctx_CdBlock)
};

class Cd : public ::vm::_Builtin {
 public:
  Cd(state::Mem* mem, dirs_osh::DirStack* dir_stack, cmd_eval::CommandEvaluator* cmd_ev, ui::ErrorFormatter* errfmt);
  virtual int Run(cmd_value::Argv* cmd_val);

  cmd_eval::CommandEvaluator* cmd_ev;
  dirs_osh::DirStack* dir_stack;
  ui::ErrorFormatter* errfmt;
  state::Mem* mem;
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Builtin::field_mask()
         | maskbit(offsetof(Cd, cmd_ev))
         | maskbit(offsetof(Cd, dir_stack))
         | maskbit(offsetof(Cd, errfmt))
         | maskbit(offsetof(Cd, mem));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(Cd));
  }

  DISALLOW_COPY_AND_ASSIGN(Cd)
};

extern int WITH_LINE_NUMBERS;
extern int WITHOUT_LINE_NUMBERS;
extern int SINGLE_LINE;
void _PrintDirStack(dirs_osh::DirStack* dir_stack, int style, BigStr* home_dir);
class Pushd : public ::vm::_Builtin {
 public:
  Pushd(state::Mem* mem, dirs_osh::DirStack* dir_stack, ui::ErrorFormatter* errfmt);
  virtual int Run(cmd_value::Argv* cmd_val);

  dirs_osh::DirStack* dir_stack;
  ui::ErrorFormatter* errfmt;
  state::Mem* mem;
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Builtin::field_mask()
         | maskbit(offsetof(Pushd, dir_stack))
         | maskbit(offsetof(Pushd, errfmt))
         | maskbit(offsetof(Pushd, mem));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(Pushd));
  }

  DISALLOW_COPY_AND_ASSIGN(Pushd)
};

bool _PopDirStack(BigStr* label, state::Mem* mem, dirs_osh::DirStack* dir_stack, ui::ErrorFormatter* errfmt, List<bool>* out_errs);
class Popd : public ::vm::_Builtin {
 public:
  Popd(state::Mem* mem, dirs_osh::DirStack* dir_stack, ui::ErrorFormatter* errfmt);
  virtual int Run(cmd_value::Argv* cmd_val);

  dirs_osh::DirStack* dir_stack;
  ui::ErrorFormatter* errfmt;
  state::Mem* mem;
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Builtin::field_mask()
         | maskbit(offsetof(Popd, dir_stack))
         | maskbit(offsetof(Popd, errfmt))
         | maskbit(offsetof(Popd, mem));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(Popd));
  }

  DISALLOW_COPY_AND_ASSIGN(Popd)
};

class Dirs : public ::vm::_Builtin {
 public:
  Dirs(state::Mem* mem, dirs_osh::DirStack* dir_stack, ui::ErrorFormatter* errfmt);
  virtual int Run(cmd_value::Argv* cmd_val);

  dirs_osh::DirStack* dir_stack;
  ui::ErrorFormatter* errfmt;
  state::Mem* mem;
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Builtin::field_mask()
         | maskbit(offsetof(Dirs, dir_stack))
         | maskbit(offsetof(Dirs, errfmt))
         | maskbit(offsetof(Dirs, mem));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(Dirs));
  }

  DISALLOW_COPY_AND_ASSIGN(Dirs)
};

class Pwd : public ::vm::_Builtin {
 public:
  Pwd(state::Mem* mem, ui::ErrorFormatter* errfmt);
  virtual int Run(cmd_value::Argv* cmd_val);

  ui::ErrorFormatter* errfmt;
  state::Mem* mem;
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Builtin::field_mask()
         | maskbit(offsetof(Pwd, errfmt))
         | maskbit(offsetof(Pwd, mem));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(Pwd));
  }

  DISALLOW_COPY_AND_ASSIGN(Pwd)
};


}  // declare namespace dirs_osh

namespace error_ysh {  // declare

using runtime_asdl::cmd_value;
using syntax_asdl::loc;
class ctx_Try {
 public:
  ctx_Try(state::MutableOpts* mutable_opts);
  ~ctx_Try();
  state::MutableOpts* mutable_opts;

  DISALLOW_COPY_AND_ASSIGN(ctx_Try)
};

class Try : public ::vm::_Builtin {
 public:
  Try(state::MutableOpts* mutable_opts, state::Mem* mem, cmd_eval::CommandEvaluator* cmd_ev, vm::_Executor* shell_ex, ui::ErrorFormatter* errfmt);
  virtual int Run(cmd_value::Argv* cmd_val);

  cmd_eval::CommandEvaluator* cmd_ev;
  ui::ErrorFormatter* errfmt;
  state::Mem* mem;
  state::MutableOpts* mutable_opts;
  vm::_Executor* shell_ex;
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Builtin::field_mask()
         | maskbit(offsetof(Try, cmd_ev))
         | maskbit(offsetof(Try, errfmt))
         | maskbit(offsetof(Try, mem))
         | maskbit(offsetof(Try, mutable_opts))
         | maskbit(offsetof(Try, shell_ex));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(Try));
  }

  DISALLOW_COPY_AND_ASSIGN(Try)
};

class Failed : public ::vm::_Builtin {
 public:
  Failed(state::Mem* mem);
  virtual int Run(cmd_value::Argv* cmd_val);

  state::Mem* mem;
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Builtin::field_mask()
         | maskbit(offsetof(Failed, mem));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(Failed));
  }

  DISALLOW_COPY_AND_ASSIGN(Failed)
};

class Error : public ::vm::_Builtin {
 public:
  Error();
  virtual int Run(cmd_value::Argv* cmd_val);
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Builtin::field_mask();
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(Error));
  }

  DISALLOW_COPY_AND_ASSIGN(Error)
};

class BoolStatus : public ::vm::_Builtin {
 public:
  BoolStatus(vm::_Executor* shell_ex, ui::ErrorFormatter* errfmt);
  virtual int Run(cmd_value::Argv* cmd_val);

  ui::ErrorFormatter* errfmt;
  vm::_Executor* shell_ex;
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Builtin::field_mask()
         | maskbit(offsetof(BoolStatus, errfmt))
         | maskbit(offsetof(BoolStatus, shell_ex));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(BoolStatus));
  }

  DISALLOW_COPY_AND_ASSIGN(BoolStatus)
};


}  // declare namespace error_ysh

namespace func_eggex {  // declare

extern int G;
extern int S;
extern int E;
class _MatchCallable : public ::vm::_Callable {
 public:
  _MatchCallable(int to_return, expr_eval::ExprEvaluator* expr_ev);
  value_asdl::value_t* _ReturnValue(value_asdl::RegexMatch* match, int group_index, syntax_asdl::loc_t* blame_loc);
  value_asdl::value_t* _Call(value_asdl::RegexMatch* match, value_asdl::value_t* group_arg, syntax_asdl::loc_t* blame_loc);

  expr_eval::ExprEvaluator* expr_ev;
  int to_return;
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Callable::field_mask()
         | maskbit(offsetof(_MatchCallable, expr_ev));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(_MatchCallable));
  }

  DISALLOW_COPY_AND_ASSIGN(_MatchCallable)
};

int _GetGroupIndex(value_asdl::value_t* group, value_asdl::eggex_ops_t* ops, syntax_asdl::loc_t* blame_loc);
class MatchFunc : public ::func_eggex::_MatchCallable {
 public:
  MatchFunc(int to_return, expr_eval::ExprEvaluator* expr_ev, state::Mem* mem);
  value_asdl::value_t* Call(typed_args::Reader* rd);

  state::Mem* mem;
  
  static constexpr uint32_t field_mask() {
    return ::func_eggex::_MatchCallable::field_mask()
         | maskbit(offsetof(MatchFunc, mem));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(MatchFunc));
  }

  DISALLOW_COPY_AND_ASSIGN(MatchFunc)
};

class MatchMethod : public ::func_eggex::_MatchCallable {
 public:
  MatchMethod(int to_return, expr_eval::ExprEvaluator* expr_ev);
  value_asdl::value_t* Call(typed_args::Reader* rd);
  
  static constexpr uint32_t field_mask() {
    return ::func_eggex::_MatchCallable::field_mask();
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(MatchMethod));
  }

  DISALLOW_COPY_AND_ASSIGN(MatchMethod)
};


}  // declare namespace func_eggex

namespace func_hay {  // declare

using syntax_asdl::loc;
class ParseHay : public ::vm::_Callable {
 public:
  ParseHay(process::FdState* fd_state, parse_lib::ParseContext* parse_ctx, ui::ErrorFormatter* errfmt);
  value_asdl::value_t* _Call(BigStr* path);
  virtual value_asdl::value_t* Call(typed_args::Reader* rd);

  ui::ErrorFormatter* errfmt;
  process::FdState* fd_state;
  parse_lib::ParseContext* parse_ctx;
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Callable::field_mask()
         | maskbit(offsetof(ParseHay, errfmt))
         | maskbit(offsetof(ParseHay, fd_state))
         | maskbit(offsetof(ParseHay, parse_ctx));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(ParseHay));
  }

  DISALLOW_COPY_AND_ASSIGN(ParseHay)
};

class EvalHay : public ::vm::_Callable {
 public:
  EvalHay(hay_ysh::HayState* hay_state, state::MutableOpts* mutable_opts, state::Mem* mem, cmd_eval::CommandEvaluator* cmd_ev);
  Dict<BigStr*, value_asdl::value_t*>* _Call(syntax_asdl::command_t* cmd);
  virtual value_asdl::value_t* Call(typed_args::Reader* rd);

  cmd_eval::CommandEvaluator* cmd_ev;
  hay_ysh::HayState* hay_state;
  state::Mem* mem;
  state::MutableOpts* mutable_opts;
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Callable::field_mask()
         | maskbit(offsetof(EvalHay, cmd_ev))
         | maskbit(offsetof(EvalHay, hay_state))
         | maskbit(offsetof(EvalHay, mem))
         | maskbit(offsetof(EvalHay, mutable_opts));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(EvalHay));
  }

  DISALLOW_COPY_AND_ASSIGN(EvalHay)
};

class BlockAsStr : public ::vm::_Callable {
 public:
  BlockAsStr(alloc::Arena* arena);
  value_asdl::value_t* _Call(value_asdl::value_t* block);
  virtual value_asdl::value_t* Call(typed_args::Reader* rd);

  alloc::Arena* arena;
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Callable::field_mask()
         | maskbit(offsetof(BlockAsStr, arena));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(BlockAsStr));
  }

  DISALLOW_COPY_AND_ASSIGN(BlockAsStr)
};

class HayFunc : public ::vm::_Callable {
 public:
  HayFunc(hay_ysh::HayState* hay_state);
  Dict<BigStr*, value_asdl::value_t*>* _Call();
  virtual value_asdl::value_t* Call(typed_args::Reader* rd);

  hay_ysh::HayState* hay_state;
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Callable::field_mask()
         | maskbit(offsetof(HayFunc, hay_state));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(HayFunc));
  }

  DISALLOW_COPY_AND_ASSIGN(HayFunc)
};


}  // declare namespace func_hay

namespace func_misc {  // declare

using runtime_asdl::scope_e;
class Len : public ::vm::_Callable {
 public:
  Len();
  virtual value_asdl::value_t* Call(typed_args::Reader* rd);
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Callable::field_mask();
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(Len));
  }

  DISALLOW_COPY_AND_ASSIGN(Len)
};

class Type : public ::vm::_Callable {
 public:
  Type();
  virtual value_asdl::value_t* Call(typed_args::Reader* rd);
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Callable::field_mask();
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(Type));
  }

  DISALLOW_COPY_AND_ASSIGN(Type)
};

class Repeat : public ::vm::_Callable {
 public:
  Repeat();
  virtual value_asdl::value_t* Call(typed_args::Reader* rd);
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Callable::field_mask();
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(Repeat));
  }

  DISALLOW_COPY_AND_ASSIGN(Repeat)
};

class Join : public ::vm::_Callable {
 public:
  Join();
  virtual value_asdl::value_t* Call(typed_args::Reader* rd);
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Callable::field_mask();
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(Join));
  }

  DISALLOW_COPY_AND_ASSIGN(Join)
};

class Maybe : public ::vm::_Callable {
 public:
  Maybe();
  virtual value_asdl::value_t* Call(typed_args::Reader* rd);
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Callable::field_mask();
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(Maybe));
  }

  DISALLOW_COPY_AND_ASSIGN(Maybe)
};

class Bool : public ::vm::_Callable {
 public:
  Bool();
  virtual value_asdl::value_t* Call(typed_args::Reader* rd);
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Callable::field_mask();
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(Bool));
  }

  DISALLOW_COPY_AND_ASSIGN(Bool)
};

class Int : public ::vm::_Callable {
 public:
  Int();
  virtual value_asdl::value_t* Call(typed_args::Reader* rd);
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Callable::field_mask();
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(Int));
  }

  DISALLOW_COPY_AND_ASSIGN(Int)
};

class Float : public ::vm::_Callable {
 public:
  Float();
  virtual value_asdl::value_t* Call(typed_args::Reader* rd);
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Callable::field_mask();
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(Float));
  }

  DISALLOW_COPY_AND_ASSIGN(Float)
};

class Str_ : public ::vm::_Callable {
 public:
  Str_();
  virtual value_asdl::value_t* Call(typed_args::Reader* rd);
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Callable::field_mask();
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(Str_));
  }

  DISALLOW_COPY_AND_ASSIGN(Str_)
};

class List_ : public ::vm::_Callable {
 public:
  List_();
  virtual value_asdl::value_t* Call(typed_args::Reader* rd);
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Callable::field_mask();
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(List_));
  }

  DISALLOW_COPY_AND_ASSIGN(List_)
};

class Dict_ : public ::vm::_Callable {
 public:
  Dict_();
  virtual value_asdl::value_t* Call(typed_args::Reader* rd);
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Callable::field_mask();
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(Dict_));
  }

  DISALLOW_COPY_AND_ASSIGN(Dict_)
};

class Runes : public ::vm::_Callable {
 public:
  Runes();
  virtual value_asdl::value_t* Call(typed_args::Reader* rd);
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Callable::field_mask();
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(Runes));
  }

  DISALLOW_COPY_AND_ASSIGN(Runes)
};

class EncodeRunes : public ::vm::_Callable {
 public:
  EncodeRunes();
  virtual value_asdl::value_t* Call(typed_args::Reader* rd);
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Callable::field_mask();
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(EncodeRunes));
  }

  DISALLOW_COPY_AND_ASSIGN(EncodeRunes)
};

class Bytes : public ::vm::_Callable {
 public:
  Bytes();
  virtual value_asdl::value_t* Call(typed_args::Reader* rd);
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Callable::field_mask();
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(Bytes));
  }

  DISALLOW_COPY_AND_ASSIGN(Bytes)
};

class EncodeBytes : public ::vm::_Callable {
 public:
  EncodeBytes();
  virtual value_asdl::value_t* Call(typed_args::Reader* rd);
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Callable::field_mask();
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(EncodeBytes));
  }

  DISALLOW_COPY_AND_ASSIGN(EncodeBytes)
};

class Split : public ::vm::_Callable {
 public:
  Split(split::SplitContext* splitter);
  virtual value_asdl::value_t* Call(typed_args::Reader* rd);

  split::SplitContext* splitter;
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Callable::field_mask()
         | maskbit(offsetof(Split, splitter));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(Split));
  }

  DISALLOW_COPY_AND_ASSIGN(Split)
};

class Glob : public ::vm::_Callable {
 public:
  Glob(glob_::Globber* globber);
  virtual value_asdl::value_t* Call(typed_args::Reader* rd);

  glob_::Globber* globber;
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Callable::field_mask()
         | maskbit(offsetof(Glob, globber));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(Glob));
  }

  DISALLOW_COPY_AND_ASSIGN(Glob)
};

class Shvar_get : public ::vm::_Callable {
 public:
  Shvar_get(state::Mem* mem);
  virtual value_asdl::value_t* Call(typed_args::Reader* rd);

  state::Mem* mem;
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Callable::field_mask()
         | maskbit(offsetof(Shvar_get, mem));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(Shvar_get));
  }

  DISALLOW_COPY_AND_ASSIGN(Shvar_get)
};

class GetVar : public ::vm::_Callable {
 public:
  GetVar(state::Mem* mem);
  virtual value_asdl::value_t* Call(typed_args::Reader* rd);

  state::Mem* mem;
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Callable::field_mask()
         | maskbit(offsetof(GetVar, mem));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(GetVar));
  }

  DISALLOW_COPY_AND_ASSIGN(GetVar)
};

class Assert : public ::vm::_Callable {
 public:
  Assert();
  virtual value_asdl::value_t* Call(typed_args::Reader* rd);
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Callable::field_mask();
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(Assert));
  }

  DISALLOW_COPY_AND_ASSIGN(Assert)
};

class EvalExpr : public ::vm::_Callable {
 public:
  EvalExpr(expr_eval::ExprEvaluator* expr_ev);
  virtual value_asdl::value_t* Call(typed_args::Reader* rd);

  expr_eval::ExprEvaluator* expr_ev;
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Callable::field_mask()
         | maskbit(offsetof(EvalExpr, expr_ev));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(EvalExpr));
  }

  DISALLOW_COPY_AND_ASSIGN(EvalExpr)
};

class ToJson8 : public ::vm::_Callable {
 public:
  ToJson8(bool is_j8);
  virtual value_asdl::value_t* Call(typed_args::Reader* rd);

  bool is_j8;
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Callable::field_mask();
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(ToJson8));
  }

  DISALLOW_COPY_AND_ASSIGN(ToJson8)
};

class FromJson8 : public ::vm::_Callable {
 public:
  FromJson8(bool is_j8);
  virtual value_asdl::value_t* Call(typed_args::Reader* rd);

  bool is_j8;
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Callable::field_mask();
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(FromJson8));
  }

  DISALLOW_COPY_AND_ASSIGN(FromJson8)
};

class BashArrayToSparse : public ::vm::_Callable {
 public:
  BashArrayToSparse();
  virtual value_asdl::value_t* Call(typed_args::Reader* rd);
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Callable::field_mask();
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(BashArrayToSparse));
  }

  DISALLOW_COPY_AND_ASSIGN(BashArrayToSparse)
};

class DictToSparse : public ::vm::_Callable {
 public:
  DictToSparse();
  virtual value_asdl::value_t* Call(typed_args::Reader* rd);
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Callable::field_mask();
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(DictToSparse));
  }

  DISALLOW_COPY_AND_ASSIGN(DictToSparse)
};

class SparseOp : public ::vm::_Callable {
 public:
  SparseOp();
  virtual value_asdl::value_t* Call(typed_args::Reader* rd);
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Callable::field_mask();
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(SparseOp));
  }

  DISALLOW_COPY_AND_ASSIGN(SparseOp)
};


}  // declare namespace func_misc

namespace hay_ysh {  // declare

using runtime_asdl::scope_e;
using syntax_asdl::loc;
extern BigStr* _HAY_ACTION_ERROR;
class ctx_HayNode {
 public:
  ctx_HayNode(hay_ysh::HayState* hay_state, BigStr* hay_name);
  ~ctx_HayNode();
  hay_ysh::HayState* hay_state;

  DISALLOW_COPY_AND_ASSIGN(ctx_HayNode)
};

class ctx_HayEval {
 public:
  ctx_HayEval(hay_ysh::HayState* hay_state, state::MutableOpts* mutable_opts, state::Mem* mem);
  ~ctx_HayEval();
  hay_ysh::HayState* hay_state;
  state::MutableOpts* mutable_opts;
  state::Mem* mem;

  DISALLOW_COPY_AND_ASSIGN(ctx_HayEval)
};

class HayState {
 public:
  HayState();
  Dict<BigStr*, value_asdl::value_t*>* _MakeOutputNode();
  void PushEval();
  void PopEval();
  void AppendResult(Dict<BigStr*, value_asdl::value_t*>* d);
  Dict<BigStr*, value_asdl::value_t*>* Result();
  Dict<BigStr*, value_asdl::value_t*>* HayRegister();
  bool Resolve(BigStr* first_word);
  void DefinePath(List<BigStr*>* path);
  void Reset();
  void Push(BigStr* hay_name);
  void Pop();
  runtime_asdl::HayNode* root_defs;
  runtime_asdl::HayNode* cur_defs;
  List<runtime_asdl::HayNode*>* def_stack;
  List<Dict<BigStr*, value_asdl::value_t*>*>* result_stack;
  Dict<BigStr*, value_asdl::value_t*>* output;

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassScanned(5, sizeof(HayState));
  }

  DISALLOW_COPY_AND_ASSIGN(HayState)
};

class Hay : public ::vm::_Builtin {
 public:
  Hay(hay_ysh::HayState* hay_state, state::MutableOpts* mutable_opts, state::Mem* mem, cmd_eval::CommandEvaluator* cmd_ev);
  virtual int Run(cmd_value::Argv* cmd_val);

  cmd_eval::CommandEvaluator* cmd_ev;
  hay_ysh::HayState* hay_state;
  state::Mem* mem;
  state::MutableOpts* mutable_opts;
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Builtin::field_mask()
         | maskbit(offsetof(Hay, cmd_ev))
         | maskbit(offsetof(Hay, hay_state))
         | maskbit(offsetof(Hay, mem))
         | maskbit(offsetof(Hay, mutable_opts));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(Hay));
  }

  DISALLOW_COPY_AND_ASSIGN(Hay)
};

class HayNode_ : public ::vm::_Builtin {
 public:
  HayNode_(hay_ysh::HayState* hay_state, state::Mem* mem, cmd_eval::CommandEvaluator* cmd_ev);
  virtual int Run(cmd_value::Argv* cmd_val);

  alloc::Arena* arena;
  cmd_eval::CommandEvaluator* cmd_ev;
  hay_ysh::HayState* hay_state;
  state::Mem* mem;
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Builtin::field_mask()
         | maskbit(offsetof(HayNode_, arena))
         | maskbit(offsetof(HayNode_, cmd_ev))
         | maskbit(offsetof(HayNode_, hay_state))
         | maskbit(offsetof(HayNode_, mem));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(HayNode_));
  }

  DISALLOW_COPY_AND_ASSIGN(HayNode_)
};


}  // declare namespace hay_ysh

namespace io_osh {  // declare

using id_kind_asdl::Id;
class Echo : public ::vm::_Builtin {
 public:
  Echo(optview::Exec* exec_opts);
  arg_types::echo* _SimpleFlag();
  virtual int Run(cmd_value::Argv* cmd_val);

  optview::Exec* exec_opts;
  mylib::Writer* f;
  arg_types::echo* simple_flag;
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Builtin::field_mask()
         | maskbit(offsetof(Echo, exec_opts))
         | maskbit(offsetof(Echo, f))
         | maskbit(offsetof(Echo, simple_flag));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(Echo));
  }

  DISALLOW_COPY_AND_ASSIGN(Echo)
};

class MapFile : public ::vm::_Builtin {
 public:
  MapFile(state::Mem* mem, ui::ErrorFormatter* errfmt, cmd_eval::CommandEvaluator* cmd_ev);
  virtual int Run(cmd_value::Argv* cmd_val);

  cmd_eval::CommandEvaluator* cmd_ev;
  ui::ErrorFormatter* errfmt;
  state::Mem* mem;
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Builtin::field_mask()
         | maskbit(offsetof(MapFile, cmd_ev))
         | maskbit(offsetof(MapFile, errfmt))
         | maskbit(offsetof(MapFile, mem));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(MapFile));
  }

  DISALLOW_COPY_AND_ASSIGN(MapFile)
};

class Cat : public ::vm::_Builtin {
 public:
  Cat();
  virtual int Run(cmd_value::Argv* cmd_val);
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Builtin::field_mask();
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(Cat));
  }

  DISALLOW_COPY_AND_ASSIGN(Cat)
};


}  // declare namespace io_osh

namespace io_ysh {  // declare

using runtime_asdl::cmd_value;
using syntax_asdl::loc;
class _Builtin : public ::vm::_Builtin {
 public:
  _Builtin(state::Mem* mem, ui::ErrorFormatter* errfmt);

  ui::ErrorFormatter* errfmt;
  state::Mem* mem;
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Builtin::field_mask()
         | maskbit(offsetof(_Builtin, errfmt))
         | maskbit(offsetof(_Builtin, mem));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(_Builtin));
  }

  DISALLOW_COPY_AND_ASSIGN(_Builtin)
};

class Pp : public ::io_ysh::_Builtin {
 public:
  Pp(state::Mem* mem, ui::ErrorFormatter* errfmt, Dict<BigStr*, value::Proc*>* procs, alloc::Arena* arena);
  int Run(cmd_value::Argv* cmd_val);

  alloc::Arena* arena;
  Dict<BigStr*, value::Proc*>* procs;
  mylib::Writer* stdout_;
  
  static constexpr uint32_t field_mask() {
    return ::io_ysh::_Builtin::field_mask()
         | maskbit(offsetof(Pp, arena))
         | maskbit(offsetof(Pp, procs))
         | maskbit(offsetof(Pp, stdout_));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(Pp));
  }

  DISALLOW_COPY_AND_ASSIGN(Pp)
};

class Write : public ::io_ysh::_Builtin {
 public:
  Write(state::Mem* mem, ui::ErrorFormatter* errfmt);
  int Run(cmd_value::Argv* cmd_val);

  mylib::Writer* stdout_;
  
  static constexpr uint32_t field_mask() {
    return ::io_ysh::_Builtin::field_mask()
         | maskbit(offsetof(Write, stdout_));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(Write));
  }

  DISALLOW_COPY_AND_ASSIGN(Write)
};

class Fopen : public ::vm::_Builtin {
 public:
  Fopen(state::Mem* mem, cmd_eval::CommandEvaluator* cmd_ev);
  virtual int Run(cmd_value::Argv* cmd_val);

  cmd_eval::CommandEvaluator* cmd_ev;
  state::Mem* mem;
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Builtin::field_mask()
         | maskbit(offsetof(Fopen, cmd_ev))
         | maskbit(offsetof(Fopen, mem));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(Fopen));
  }

  DISALLOW_COPY_AND_ASSIGN(Fopen)
};


}  // declare namespace io_ysh

namespace json_ysh {  // declare

using runtime_asdl::cmd_value;
using syntax_asdl::loc;
extern BigStr* _JSON_ACTION_ERROR;
class Json : public ::vm::_Builtin {
 public:
  Json(state::Mem* mem, ui::ErrorFormatter* errfmt, bool is_j8);
  virtual int Run(cmd_value::Argv* cmd_val);

  ui::ErrorFormatter* errfmt;
  bool is_j8;
  state::Mem* mem;
  BigStr* name;
  mylib::Writer* stdout_;
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Builtin::field_mask()
         | maskbit(offsetof(Json, errfmt))
         | maskbit(offsetof(Json, mem))
         | maskbit(offsetof(Json, name))
         | maskbit(offsetof(Json, stdout_));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(Json));
  }

  DISALLOW_COPY_AND_ASSIGN(Json)
};


}  // declare namespace json_ysh

namespace meta_osh {  // declare

using runtime_asdl::cmd_value;
using syntax_asdl::loc;
class Eval : public ::vm::_Builtin {
 public:
  Eval(parse_lib::ParseContext* parse_ctx, optview::Exec* exec_opts, cmd_eval::CommandEvaluator* cmd_ev, dev::Tracer* tracer, ui::ErrorFormatter* errfmt);
  virtual int Run(cmd_value::Argv* cmd_val);

  alloc::Arena* arena;
  cmd_eval::CommandEvaluator* cmd_ev;
  ui::ErrorFormatter* errfmt;
  optview::Exec* exec_opts;
  parse_lib::ParseContext* parse_ctx;
  dev::Tracer* tracer;
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Builtin::field_mask()
         | maskbit(offsetof(Eval, arena))
         | maskbit(offsetof(Eval, cmd_ev))
         | maskbit(offsetof(Eval, errfmt))
         | maskbit(offsetof(Eval, exec_opts))
         | maskbit(offsetof(Eval, parse_ctx))
         | maskbit(offsetof(Eval, tracer));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(Eval));
  }

  DISALLOW_COPY_AND_ASSIGN(Eval)
};

class Source : public ::vm::_Builtin {
 public:
  Source(parse_lib::ParseContext* parse_ctx, state::SearchPath* search_path, cmd_eval::CommandEvaluator* cmd_ev, process::FdState* fd_state, dev::Tracer* tracer, ui::ErrorFormatter* errfmt, pyutil::_ResourceLoader* loader);
  virtual int Run(cmd_value::Argv* cmd_val);
  int _Exec(cmd_value::Argv* cmd_val, args::Reader* arg_r, BigStr* path, cmd_parse::CommandParser* c_parser);

  alloc::Arena* arena;
  cmd_eval::CommandEvaluator* cmd_ev;
  ui::ErrorFormatter* errfmt;
  process::FdState* fd_state;
  pyutil::_ResourceLoader* loader;
  state::Mem* mem;
  parse_lib::ParseContext* parse_ctx;
  state::SearchPath* search_path;
  dev::Tracer* tracer;
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Builtin::field_mask()
         | maskbit(offsetof(Source, arena))
         | maskbit(offsetof(Source, cmd_ev))
         | maskbit(offsetof(Source, errfmt))
         | maskbit(offsetof(Source, fd_state))
         | maskbit(offsetof(Source, loader))
         | maskbit(offsetof(Source, mem))
         | maskbit(offsetof(Source, parse_ctx))
         | maskbit(offsetof(Source, search_path))
         | maskbit(offsetof(Source, tracer));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(Source));
  }

  DISALLOW_COPY_AND_ASSIGN(Source)
};

void _PrintFreeForm(Tuple3<BigStr*, BigStr*, BigStr*>* row);
void _PrintEntry(arg_types::type* arg, Tuple3<BigStr*, BigStr*, BigStr*>* row);
class Command : public ::vm::_Builtin {
 public:
  Command(vm::_Executor* shell_ex, Dict<BigStr*, value::Proc*>* funcs, Dict<BigStr*, BigStr*>* aliases, state::SearchPath* search_path);
  virtual int Run(cmd_value::Argv* cmd_val);

  Dict<BigStr*, BigStr*>* aliases;
  Dict<BigStr*, value::Proc*>* funcs;
  state::SearchPath* search_path;
  vm::_Executor* shell_ex;
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Builtin::field_mask()
         | maskbit(offsetof(Command, aliases))
         | maskbit(offsetof(Command, funcs))
         | maskbit(offsetof(Command, search_path))
         | maskbit(offsetof(Command, shell_ex));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(Command));
  }

  DISALLOW_COPY_AND_ASSIGN(Command)
};

cmd_value::Argv* _ShiftArgv(cmd_value::Argv* cmd_val);
class Builtin : public ::vm::_Builtin {
 public:
  Builtin(vm::_Executor* shell_ex, ui::ErrorFormatter* errfmt);
  virtual int Run(cmd_value::Argv* cmd_val);

  ui::ErrorFormatter* errfmt;
  vm::_Executor* shell_ex;
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Builtin::field_mask()
         | maskbit(offsetof(Builtin, errfmt))
         | maskbit(offsetof(Builtin, shell_ex));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(Builtin));
  }

  DISALLOW_COPY_AND_ASSIGN(Builtin)
};

class RunProc : public ::vm::_Builtin {
 public:
  RunProc(vm::_Executor* shell_ex, Dict<BigStr*, value::Proc*>* procs, ui::ErrorFormatter* errfmt);
  virtual int Run(cmd_value::Argv* cmd_val);

  ui::ErrorFormatter* errfmt;
  Dict<BigStr*, value::Proc*>* procs;
  vm::_Executor* shell_ex;
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Builtin::field_mask()
         | maskbit(offsetof(RunProc, errfmt))
         | maskbit(offsetof(RunProc, procs))
         | maskbit(offsetof(RunProc, shell_ex));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(RunProc));
  }

  DISALLOW_COPY_AND_ASSIGN(RunProc)
};

List<Tuple3<BigStr*, BigStr*, BigStr*>*>* _ResolveName(BigStr* name, Dict<BigStr*, value::Proc*>* funcs, Dict<BigStr*, BigStr*>* aliases, state::SearchPath* search_path, bool do_all);
class Type : public ::vm::_Builtin {
 public:
  Type(Dict<BigStr*, value::Proc*>* funcs, Dict<BigStr*, BigStr*>* aliases, state::SearchPath* search_path, ui::ErrorFormatter* errfmt);
  virtual int Run(cmd_value::Argv* cmd_val);

  Dict<BigStr*, BigStr*>* aliases;
  ui::ErrorFormatter* errfmt;
  Dict<BigStr*, value::Proc*>* funcs;
  state::SearchPath* search_path;
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Builtin::field_mask()
         | maskbit(offsetof(Type, aliases))
         | maskbit(offsetof(Type, errfmt))
         | maskbit(offsetof(Type, funcs))
         | maskbit(offsetof(Type, search_path));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(Type));
  }

  DISALLOW_COPY_AND_ASSIGN(Type)
};


}  // declare namespace meta_osh

namespace method_dict {  // declare

class Keys : public ::vm::_Callable {
 public:
  Keys();
  virtual value_asdl::value_t* Call(typed_args::Reader* rd);
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Callable::field_mask();
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(Keys));
  }

  DISALLOW_COPY_AND_ASSIGN(Keys)
};

class Values : public ::vm::_Callable {
 public:
  Values();
  virtual value_asdl::value_t* Call(typed_args::Reader* rd);
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Callable::field_mask();
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(Values));
  }

  DISALLOW_COPY_AND_ASSIGN(Values)
};


}  // declare namespace method_dict

namespace method_io {  // declare

class Eval : public ::vm::_Callable {
 public:
  Eval();
  virtual value_asdl::value_t* Call(typed_args::Reader* rd);
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Callable::field_mask();
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(Eval));
  }

  DISALLOW_COPY_AND_ASSIGN(Eval)
};

class CaptureStdout : public ::vm::_Callable {
 public:
  CaptureStdout();
  virtual value_asdl::value_t* Call(typed_args::Reader* rd);
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Callable::field_mask();
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(CaptureStdout));
  }

  DISALLOW_COPY_AND_ASSIGN(CaptureStdout)
};

class PromptVal : public ::vm::_Callable {
 public:
  PromptVal();
  virtual value_asdl::value_t* Call(typed_args::Reader* rd);
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Callable::field_mask();
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(PromptVal));
  }

  DISALLOW_COPY_AND_ASSIGN(PromptVal)
};

class Time : public ::vm::_Callable {
 public:
  Time();
  virtual value_asdl::value_t* Call(typed_args::Reader* rd);
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Callable::field_mask();
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(Time));
  }

  DISALLOW_COPY_AND_ASSIGN(Time)
};

class Strftime : public ::vm::_Callable {
 public:
  Strftime();
  virtual value_asdl::value_t* Call(typed_args::Reader* rd);
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Callable::field_mask();
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(Strftime));
  }

  DISALLOW_COPY_AND_ASSIGN(Strftime)
};


}  // declare namespace method_io

namespace method_list {  // declare

class Append : public ::vm::_Callable {
 public:
  Append();
  virtual value_asdl::value_t* Call(typed_args::Reader* rd);
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Callable::field_mask();
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(Append));
  }

  DISALLOW_COPY_AND_ASSIGN(Append)
};

class Extend : public ::vm::_Callable {
 public:
  Extend();
  virtual value_asdl::value_t* Call(typed_args::Reader* rd);
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Callable::field_mask();
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(Extend));
  }

  DISALLOW_COPY_AND_ASSIGN(Extend)
};

class Pop : public ::vm::_Callable {
 public:
  Pop();
  virtual value_asdl::value_t* Call(typed_args::Reader* rd);
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Callable::field_mask();
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(Pop));
  }

  DISALLOW_COPY_AND_ASSIGN(Pop)
};

class Reverse : public ::vm::_Callable {
 public:
  Reverse();
  virtual value_asdl::value_t* Call(typed_args::Reader* rd);
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Callable::field_mask();
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(Reverse));
  }

  DISALLOW_COPY_AND_ASSIGN(Reverse)
};

class IndexOf : public ::vm::_Callable {
 public:
  IndexOf();
  virtual value_asdl::value_t* Call(typed_args::Reader* rd);
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Callable::field_mask();
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(IndexOf));
  }

  DISALLOW_COPY_AND_ASSIGN(IndexOf)
};


}  // declare namespace method_list

namespace method_other {  // declare

class SetValue : public ::vm::_Callable {
 public:
  SetValue(state::Mem* mem);
  virtual value_asdl::value_t* Call(typed_args::Reader* rd);

  state::Mem* mem;
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Callable::field_mask()
         | maskbit(offsetof(SetValue, mem));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(SetValue));
  }

  DISALLOW_COPY_AND_ASSIGN(SetValue)
};


}  // declare namespace method_other

namespace method_str {  // declare

using syntax_asdl::loc;
using runtime_asdl::scope_e;
Tuple3<bool, int, int> _StrMatchStart(BigStr* s, BigStr* p);
Tuple3<bool, int, int> _StrMatchEnd(BigStr* s, BigStr* p);
Tuple3<bool, int, int> _EggexMatchCommon(BigStr* s, value::Eggex* p, BigStr* ere, int empty_p);
Tuple3<bool, int, int> _EggexMatchStart(BigStr* s, value::Eggex* p);
Tuple3<bool, int, int> _EggexMatchEnd(BigStr* s, value::Eggex* p);
extern int START;
extern int END;
class HasAffix : public ::vm::_Callable {
 public:
  HasAffix(int anchor);
  virtual value_asdl::value_t* Call(typed_args::Reader* rd);

  int anchor;
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Callable::field_mask();
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(HasAffix));
  }

  DISALLOW_COPY_AND_ASSIGN(HasAffix)
};

class Trim : public ::vm::_Callable {
 public:
  Trim(int anchor);
  virtual value_asdl::value_t* Call(typed_args::Reader* rd);

  int anchor;
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Callable::field_mask();
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(Trim));
  }

  DISALLOW_COPY_AND_ASSIGN(Trim)
};

class Upper : public ::vm::_Callable {
 public:
  Upper();
  virtual value_asdl::value_t* Call(typed_args::Reader* rd);
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Callable::field_mask();
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(Upper));
  }

  DISALLOW_COPY_AND_ASSIGN(Upper)
};

class Lower : public ::vm::_Callable {
 public:
  Lower();
  virtual value_asdl::value_t* Call(typed_args::Reader* rd);
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Callable::field_mask();
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(Lower));
  }

  DISALLOW_COPY_AND_ASSIGN(Lower)
};

extern int SEARCH;
extern int LEFT_MATCH;
class SearchMatch : public ::vm::_Callable {
 public:
  SearchMatch(int which_method);
  virtual value_asdl::value_t* Call(typed_args::Reader* rd);

  int which_method;
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Callable::field_mask();
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(SearchMatch));
  }

  DISALLOW_COPY_AND_ASSIGN(SearchMatch)
};

class ctx_EvalReplace {
 public:
  ctx_EvalReplace(state::Mem* mem, BigStr* arg0, List<BigStr*>* argv);
  ~ctx_EvalReplace();
  value_asdl::LeftName* lval;
  state::Mem* mem;
  bool pushed_argv;

  DISALLOW_COPY_AND_ASSIGN(ctx_EvalReplace)
};

class Replace : public ::vm::_Callable {
 public:
  Replace(state::Mem* mem, expr_eval::ExprEvaluator* expr_ev);
  BigStr* EvalSubstExpr(value::Expr* expr, syntax_asdl::loc_t* blame_loc);
  virtual value_asdl::value_t* Call(typed_args::Reader* rd);

  expr_eval::ExprEvaluator* expr_ev;
  state::Mem* mem;
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Callable::field_mask()
         | maskbit(offsetof(Replace, expr_ev))
         | maskbit(offsetof(Replace, mem));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(Replace));
  }

  DISALLOW_COPY_AND_ASSIGN(Replace)
};


}  // declare namespace method_str

namespace misc_osh {  // declare

using runtime_asdl::cmd_value;
class Times : public ::vm::_Builtin {
 public:
  Times();
  virtual int Run(cmd_value::Argv* cmd_val);
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Builtin::field_mask();
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(Times));
  }

  DISALLOW_COPY_AND_ASSIGN(Times)
};

class Help : public ::vm::_Builtin {
 public:
  Help(BigStr* lang, pyutil::_ResourceLoader* loader, Dict<BigStr*, BigStr*>* help_data, ui::ErrorFormatter* errfmt);
  int _ShowTopic(BigStr* topic_id, syntax_asdl::loc_t* blame_loc);
  virtual int Run(cmd_value::Argv* cmd_val);

  ui::ErrorFormatter* errfmt;
  mylib::Writer* f;
  Dict<BigStr*, BigStr*>* help_data;
  BigStr* lang;
  pyutil::_ResourceLoader* loader;
  BigStr* version_str;
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Builtin::field_mask()
         | maskbit(offsetof(Help, errfmt))
         | maskbit(offsetof(Help, f))
         | maskbit(offsetof(Help, help_data))
         | maskbit(offsetof(Help, lang))
         | maskbit(offsetof(Help, loader))
         | maskbit(offsetof(Help, version_str));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(Help));
  }

  DISALLOW_COPY_AND_ASSIGN(Help)
};


}  // declare namespace misc_osh

namespace module_ysh {  // declare

using runtime_asdl::scope_e;
using syntax_asdl::loc;
class IsMain : public ::vm::_Builtin {
 public:
  IsMain(state::Mem* mem);
  virtual int Run(cmd_value::Argv* cmd_val);

  state::Mem* mem;
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Builtin::field_mask()
         | maskbit(offsetof(IsMain, mem));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(IsMain));
  }

  DISALLOW_COPY_AND_ASSIGN(IsMain)
};

class SourceGuard : public ::vm::_Builtin {
 public:
  SourceGuard(Dict<BigStr*, bool>* guards, optview::Exec* exec_opts, ui::ErrorFormatter* errfmt);
  virtual int Run(cmd_value::Argv* cmd_val);

  ui::ErrorFormatter* errfmt;
  optview::Exec* exec_opts;
  Dict<BigStr*, bool>* guards;
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Builtin::field_mask()
         | maskbit(offsetof(SourceGuard, errfmt))
         | maskbit(offsetof(SourceGuard, exec_opts))
         | maskbit(offsetof(SourceGuard, guards));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(SourceGuard));
  }

  DISALLOW_COPY_AND_ASSIGN(SourceGuard)
};

class Use : public ::vm::_Builtin {
 public:
  Use(state::Mem* mem, ui::ErrorFormatter* errfmt);
  virtual int Run(cmd_value::Argv* cmd_val);

  ui::ErrorFormatter* errfmt;
  state::Mem* mem;
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Builtin::field_mask()
         | maskbit(offsetof(Use, errfmt))
         | maskbit(offsetof(Use, mem));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(Use));
  }

  DISALLOW_COPY_AND_ASSIGN(Use)
};


}  // declare namespace module_ysh

namespace printf_osh {  // declare

using id_kind_asdl::Id;
using runtime_asdl::cmd_value;
using syntax_asdl::loc;
using types_asdl::lex_mode_e;
class _FormatStringParser {
 public:
  _FormatStringParser(lexer::Lexer* lexer);
  void _Next(types_asdl::lex_mode_t lex_mode);
  syntax_asdl::printf_part_t* _ParseFormatStr();
  List<syntax_asdl::printf_part_t*>* Parse();
  lexer::Lexer* lexer;
  syntax_asdl::Token* cur_token;
  int token_type;
  id_kind_asdl::Kind_t token_kind;

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassScanned(2, sizeof(_FormatStringParser));
  }

  DISALLOW_COPY_AND_ASSIGN(_FormatStringParser)
};

class _PrintfState {
 public:
  _PrintfState();
  int arg_index;
  bool backslash_c;
  int status;

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassScanned(0, sizeof(_PrintfState));
  }

  DISALLOW_COPY_AND_ASSIGN(_PrintfState)
};

class Printf : public ::vm::_Builtin {
 public:
  Printf(state::Mem* mem, parse_lib::ParseContext* parse_ctx, sh_expr_eval::UnsafeArith* unsafe_arith, ui::ErrorFormatter* errfmt);
  BigStr* _Percent(printf_osh::_PrintfState* pr, printf_part::Percent* part, List<BigStr*>* varargs, List<syntax_asdl::CompoundWord*>* locs);
  int _Format(List<syntax_asdl::printf_part_t*>* parts, List<BigStr*>* varargs, List<syntax_asdl::CompoundWord*>* locs, List<BigStr*>* out);
  virtual int Run(cmd_value::Argv* cmd_val);

  ui::ErrorFormatter* errfmt;
  state::Mem* mem;
  Dict<BigStr*, List<syntax_asdl::printf_part_t*>*>* parse_cache;
  parse_lib::ParseContext* parse_ctx;
  double shell_start_time;
  sh_expr_eval::UnsafeArith* unsafe_arith;
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Builtin::field_mask()
         | maskbit(offsetof(Printf, errfmt))
         | maskbit(offsetof(Printf, mem))
         | maskbit(offsetof(Printf, parse_cache))
         | maskbit(offsetof(Printf, parse_ctx))
         | maskbit(offsetof(Printf, unsafe_arith));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(Printf));
  }

  DISALLOW_COPY_AND_ASSIGN(Printf)
};


}  // declare namespace printf_osh

namespace process_osh {  // declare

using syntax_asdl::loc;
using runtime_asdl::cmd_value;
class Jobs : public ::vm::_Builtin {
 public:
  Jobs(process::JobList* job_list);
  virtual int Run(cmd_value::Argv* cmd_val);

  process::JobList* job_list;
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Builtin::field_mask()
         | maskbit(offsetof(Jobs, job_list));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(Jobs));
  }

  DISALLOW_COPY_AND_ASSIGN(Jobs)
};

class Fg : public ::vm::_Builtin {
 public:
  Fg(process::JobControl* job_control, process::JobList* job_list, process::Waiter* waiter);
  virtual int Run(cmd_value::Argv* cmd_val);

  process::JobControl* job_control;
  process::JobList* job_list;
  process::Waiter* waiter;
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Builtin::field_mask()
         | maskbit(offsetof(Fg, job_control))
         | maskbit(offsetof(Fg, job_list))
         | maskbit(offsetof(Fg, waiter));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(Fg));
  }

  DISALLOW_COPY_AND_ASSIGN(Fg)
};

class Bg : public ::vm::_Builtin {
 public:
  Bg(process::JobList* job_list);
  virtual int Run(cmd_value::Argv* cmd_val);

  process::JobList* job_list;
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Builtin::field_mask()
         | maskbit(offsetof(Bg, job_list));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(Bg));
  }

  DISALLOW_COPY_AND_ASSIGN(Bg)
};

class Fork : public ::vm::_Builtin {
 public:
  Fork(vm::_Executor* shell_ex);
  virtual int Run(cmd_value::Argv* cmd_val);

  vm::_Executor* shell_ex;
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Builtin::field_mask()
         | maskbit(offsetof(Fork, shell_ex));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(Fork));
  }

  DISALLOW_COPY_AND_ASSIGN(Fork)
};

class ForkWait : public ::vm::_Builtin {
 public:
  ForkWait(vm::_Executor* shell_ex);
  virtual int Run(cmd_value::Argv* cmd_val);

  vm::_Executor* shell_ex;
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Builtin::field_mask()
         | maskbit(offsetof(ForkWait, shell_ex));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(ForkWait));
  }

  DISALLOW_COPY_AND_ASSIGN(ForkWait)
};

class Exec : public ::vm::_Builtin {
 public:
  Exec(state::Mem* mem, process::ExternalProgram* ext_prog, process::FdState* fd_state, state::SearchPath* search_path, ui::ErrorFormatter* errfmt);
  virtual int Run(cmd_value::Argv* cmd_val);

  ui::ErrorFormatter* errfmt;
  process::ExternalProgram* ext_prog;
  process::FdState* fd_state;
  state::Mem* mem;
  state::SearchPath* search_path;
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Builtin::field_mask()
         | maskbit(offsetof(Exec, errfmt))
         | maskbit(offsetof(Exec, ext_prog))
         | maskbit(offsetof(Exec, fd_state))
         | maskbit(offsetof(Exec, mem))
         | maskbit(offsetof(Exec, search_path));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(Exec));
  }

  DISALLOW_COPY_AND_ASSIGN(Exec)
};

class Wait : public ::vm::_Builtin {
 public:
  Wait(process::Waiter* waiter, process::JobList* job_list, state::Mem* mem, dev::Tracer* tracer, ui::ErrorFormatter* errfmt);
  virtual int Run(cmd_value::Argv* cmd_val);
  int _Run(cmd_value::Argv* cmd_val);

  ui::ErrorFormatter* errfmt;
  process::JobList* job_list;
  state::Mem* mem;
  dev::Tracer* tracer;
  process::Waiter* waiter;
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Builtin::field_mask()
         | maskbit(offsetof(Wait, errfmt))
         | maskbit(offsetof(Wait, job_list))
         | maskbit(offsetof(Wait, mem))
         | maskbit(offsetof(Wait, tracer))
         | maskbit(offsetof(Wait, waiter));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(Wait));
  }

  DISALLOW_COPY_AND_ASSIGN(Wait)
};

class Umask : public ::vm::_Builtin {
 public:
  Umask();
  virtual int Run(cmd_value::Argv* cmd_val);
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Builtin::field_mask();
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(Umask));
  }

  DISALLOW_COPY_AND_ASSIGN(Umask)
};

BigStr* _LimitString(mops::BigInt lim, int factor);
class Ulimit : public ::vm::_Builtin {
 public:
  Ulimit();
  List<Tuple4<BigStr*, int, int, BigStr*>*>* _Table();
  int _FindFactor(int what);
  virtual int Run(cmd_value::Argv* cmd_val);

  List<Tuple4<BigStr*, int, int, BigStr*>*>* _table;
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Builtin::field_mask()
         | maskbit(offsetof(Ulimit, _table));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(Ulimit));
  }

  DISALLOW_COPY_AND_ASSIGN(Ulimit)
};


}  // declare namespace process_osh

namespace pure_osh {  // declare

using syntax_asdl::loc;
class Boolean : public ::vm::_Builtin {
 public:
  Boolean(int status);
  virtual int Run(cmd_value::Argv* cmd_val);

  int status;
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Builtin::field_mask();
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(Boolean));
  }

  DISALLOW_COPY_AND_ASSIGN(Boolean)
};

class Alias : public ::vm::_Builtin {
 public:
  Alias(Dict<BigStr*, BigStr*>* aliases, ui::ErrorFormatter* errfmt);
  virtual int Run(cmd_value::Argv* cmd_val);

  Dict<BigStr*, BigStr*>* aliases;
  ui::ErrorFormatter* errfmt;
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Builtin::field_mask()
         | maskbit(offsetof(Alias, aliases))
         | maskbit(offsetof(Alias, errfmt));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(Alias));
  }

  DISALLOW_COPY_AND_ASSIGN(Alias)
};

class UnAlias : public ::vm::_Builtin {
 public:
  UnAlias(Dict<BigStr*, BigStr*>* aliases, ui::ErrorFormatter* errfmt);
  virtual int Run(cmd_value::Argv* cmd_val);

  Dict<BigStr*, BigStr*>* aliases;
  ui::ErrorFormatter* errfmt;
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Builtin::field_mask()
         | maskbit(offsetof(UnAlias, aliases))
         | maskbit(offsetof(UnAlias, errfmt));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(UnAlias));
  }

  DISALLOW_COPY_AND_ASSIGN(UnAlias)
};

void SetOptionsFromFlags(state::MutableOpts* exec_opts, List<Tuple2<BigStr*, bool>*>* opt_changes, List<Tuple2<BigStr*, bool>*>* shopt_changes);
class Set : public ::vm::_Builtin {
 public:
  Set(state::MutableOpts* exec_opts, state::Mem* mem);
  virtual int Run(cmd_value::Argv* cmd_val);

  state::MutableOpts* exec_opts;
  state::Mem* mem;
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Builtin::field_mask()
         | maskbit(offsetof(Set, exec_opts))
         | maskbit(offsetof(Set, mem));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(Set));
  }

  DISALLOW_COPY_AND_ASSIGN(Set)
};

class Shopt : public ::vm::_Builtin {
 public:
  Shopt(state::MutableOpts* mutable_opts, cmd_eval::CommandEvaluator* cmd_ev);
  void _PrintOptions(bool use_set_opts, List<BigStr*>* opt_names);
  virtual int Run(cmd_value::Argv* cmd_val);

  cmd_eval::CommandEvaluator* cmd_ev;
  state::MutableOpts* mutable_opts;
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Builtin::field_mask()
         | maskbit(offsetof(Shopt, cmd_ev))
         | maskbit(offsetof(Shopt, mutable_opts));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(Shopt));
  }

  DISALLOW_COPY_AND_ASSIGN(Shopt)
};

class Hash : public ::vm::_Builtin {
 public:
  Hash(state::SearchPath* search_path);
  virtual int Run(cmd_value::Argv* cmd_val);

  state::SearchPath* search_path;
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Builtin::field_mask()
         | maskbit(offsetof(Hash, search_path));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(Hash));
  }

  DISALLOW_COPY_AND_ASSIGN(Hash)
};

Dict<BigStr*, bool>* _ParseOptSpec(BigStr* spec_str);
class GetOptsState {
 public:
  GetOptsState(state::Mem* mem, ui::ErrorFormatter* errfmt);
  int _OptInd();
  BigStr* GetArg(List<BigStr*>* argv);
  void IncIndex();
  void SetArg(BigStr* optarg);
  void Fail();
  state::Mem* mem;
  ui::ErrorFormatter* errfmt;
  int _optind;
  int flag_pos;

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassScanned(2, sizeof(GetOptsState));
  }

  DISALLOW_COPY_AND_ASSIGN(GetOptsState)
};

Tuple2<int, BigStr*> _GetOpts(Dict<BigStr*, bool>* spec, List<BigStr*>* argv, pure_osh::GetOptsState* my_state, ui::ErrorFormatter* errfmt);
class GetOpts : public ::vm::_Builtin {
 public:
  GetOpts(state::Mem* mem, ui::ErrorFormatter* errfmt);
  virtual int Run(cmd_value::Argv* cmd_val);

  ui::ErrorFormatter* errfmt;
  state::Mem* mem;
  pure_osh::GetOptsState* my_state;
  Dict<BigStr*, Dict<BigStr*, bool>*>* spec_cache;
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Builtin::field_mask()
         | maskbit(offsetof(GetOpts, errfmt))
         | maskbit(offsetof(GetOpts, mem))
         | maskbit(offsetof(GetOpts, my_state))
         | maskbit(offsetof(GetOpts, spec_cache));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(GetOpts));
  }

  DISALLOW_COPY_AND_ASSIGN(GetOpts)
};


}  // declare namespace pure_osh

namespace pure_ysh {  // declare

using runtime_asdl::cmd_value;
using runtime_asdl::scope_e;
using syntax_asdl::loc;
class ctx_Shvar {
 public:
  ctx_Shvar(state::Mem* mem, List<Tuple2<BigStr*, value_asdl::value_t*>*>* pairs);
  ~ctx_Shvar();
  void _Push(List<Tuple2<BigStr*, value_asdl::value_t*>*>* pairs);
  void _Pop();
  state::Mem* mem;
  List<Tuple2<value_asdl::LeftName*, value_asdl::value_t*>*>* restore;

  DISALLOW_COPY_AND_ASSIGN(ctx_Shvar)
};

class Shvar : public ::vm::_Builtin {
 public:
  Shvar(state::Mem* mem, state::SearchPath* search_path, cmd_eval::CommandEvaluator* cmd_ev);
  virtual int Run(cmd_value::Argv* cmd_val);

  cmd_eval::CommandEvaluator* cmd_ev;
  state::Mem* mem;
  state::SearchPath* search_path;
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Builtin::field_mask()
         | maskbit(offsetof(Shvar, cmd_ev))
         | maskbit(offsetof(Shvar, mem))
         | maskbit(offsetof(Shvar, search_path));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(Shvar));
  }

  DISALLOW_COPY_AND_ASSIGN(Shvar)
};

class ctx_Context {
 public:
  ctx_Context(state::Mem* mem, Dict<BigStr*, value_asdl::value_t*>* context);
  ~ctx_Context();
  state::Mem* mem;

  DISALLOW_COPY_AND_ASSIGN(ctx_Context)
};

class Ctx : public ::vm::_Builtin {
 public:
  Ctx(state::Mem* mem, cmd_eval::CommandEvaluator* cmd_ev);
  Dict<BigStr*, value_asdl::value_t*>* _GetContext();
  int _Push(Dict<BigStr*, value_asdl::value_t*>* context, syntax_asdl::command_t* block);
  int _Set(Dict<BigStr*, value_asdl::value_t*>* updates);
  int _Emit(BigStr* field, value_asdl::value_t* item, syntax_asdl::loc_t* blame);
  virtual int Run(cmd_value::Argv* cmd_val);

  cmd_eval::CommandEvaluator* cmd_ev;
  state::Mem* mem;
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Builtin::field_mask()
         | maskbit(offsetof(Ctx, cmd_ev))
         | maskbit(offsetof(Ctx, mem));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(Ctx));
  }

  DISALLOW_COPY_AND_ASSIGN(Ctx)
};

class PushRegisters : public ::vm::_Builtin {
 public:
  PushRegisters(state::Mem* mem, cmd_eval::CommandEvaluator* cmd_ev);
  virtual int Run(cmd_value::Argv* cmd_val);

  cmd_eval::CommandEvaluator* cmd_ev;
  state::Mem* mem;
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Builtin::field_mask()
         | maskbit(offsetof(PushRegisters, cmd_ev))
         | maskbit(offsetof(PushRegisters, mem));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(PushRegisters));
  }

  DISALLOW_COPY_AND_ASSIGN(PushRegisters)
};

class Append : public ::vm::_Builtin {
 public:
  Append(state::Mem* mem, ui::ErrorFormatter* errfmt);
  virtual int Run(cmd_value::Argv* cmd_val);

  ui::ErrorFormatter* errfmt;
  state::Mem* mem;
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Builtin::field_mask()
         | maskbit(offsetof(Append, errfmt))
         | maskbit(offsetof(Append, mem));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(Append));
  }

  DISALLOW_COPY_AND_ASSIGN(Append)
};


}  // declare namespace pure_ysh

namespace read_osh {  // declare

using runtime_asdl::cmd_value;
Tuple2<bool, bool> _AppendParts(BigStr* s, List<Tuple2<runtime_asdl::span_t, int>*>* spans, int max_results, bool join_next, List<mylib::BufWriter*>* parts);
BigStr* _ReadN(int num_bytes, cmd_eval::CommandEvaluator* cmd_ev);
Tuple2<BigStr*, bool> _ReadPortion(int delim_byte, int max_chars, cmd_eval::CommandEvaluator* cmd_ev);
Tuple2<BigStr*, bool> ReadLineSlowly(cmd_eval::CommandEvaluator* cmd_ev, bool with_eol = true);
BigStr* ReadAll();
class ctx_TermAttrs {
 public:
  ctx_TermAttrs(int fd, int local_modes);
  ~ctx_TermAttrs();
  void* term_attrs;
  int fd;
  int orig_local_modes;

  DISALLOW_COPY_AND_ASSIGN(ctx_TermAttrs)
};

class Read : public ::vm::_Builtin {
 public:
  Read(split::SplitContext* splitter, state::Mem* mem, parse_lib::ParseContext* parse_ctx, cmd_eval::CommandEvaluator* cmd_ev, ui::ErrorFormatter* errfmt);
  virtual int Run(cmd_value::Argv* cmd_val);
  int _ReadYsh(arg_types::read* arg, args::Reader* arg_r, cmd_value::Argv* cmd_val);
  int _Run(cmd_value::Argv* cmd_val);
  int _Read(arg_types::read* arg, List<BigStr*>* names);

  cmd_eval::CommandEvaluator* cmd_ev;
  ui::ErrorFormatter* errfmt;
  state::Mem* mem;
  parse_lib::ParseContext* parse_ctx;
  split::SplitContext* splitter;
  mylib::LineReader* stdin_;
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Builtin::field_mask()
         | maskbit(offsetof(Read, cmd_ev))
         | maskbit(offsetof(Read, errfmt))
         | maskbit(offsetof(Read, mem))
         | maskbit(offsetof(Read, parse_ctx))
         | maskbit(offsetof(Read, splitter))
         | maskbit(offsetof(Read, stdin_));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(Read));
  }

  DISALLOW_COPY_AND_ASSIGN(Read)
};


}  // declare namespace read_osh

namespace readline_osh {  // declare

using syntax_asdl::loc;
class Bind : public ::vm::_Builtin {
 public:
  Bind(py_readline::Readline* readline, ui::ErrorFormatter* errfmt);
  virtual int Run(cmd_value::Argv* cmd_val);

  ui::ErrorFormatter* errfmt;
  py_readline::Readline* readline;
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Builtin::field_mask()
         | maskbit(offsetof(Bind, errfmt))
         | maskbit(offsetof(Bind, readline));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(Bind));
  }

  DISALLOW_COPY_AND_ASSIGN(Bind)
};

class History : public ::vm::_Builtin {
 public:
  History(py_readline::Readline* readline, shell::ShellFiles* sh_files, ui::ErrorFormatter* errfmt, mylib::Writer* f);
  virtual int Run(cmd_value::Argv* cmd_val);

  ui::ErrorFormatter* errfmt;
  mylib::Writer* f;
  py_readline::Readline* readline;
  shell::ShellFiles* sh_files;
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Builtin::field_mask()
         | maskbit(offsetof(History, errfmt))
         | maskbit(offsetof(History, f))
         | maskbit(offsetof(History, readline))
         | maskbit(offsetof(History, sh_files));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(History));
  }

  DISALLOW_COPY_AND_ASSIGN(History)
};


}  // declare namespace readline_osh

namespace trap_osh {  // declare

using runtime_asdl::cmd_value;
using syntax_asdl::loc;
class TrapState {
 public:
  TrapState(pyos::SignalSafe* signal_safe);
  void ClearForSubProgram();
  syntax_asdl::command_t* GetHook(BigStr* hook_name);
  void AddUserHook(BigStr* hook_name, syntax_asdl::command_t* handler);
  void RemoveUserHook(BigStr* hook_name);
  void AddUserTrap(int sig_num, syntax_asdl::command_t* handler);
  void RemoveUserTrap(int sig_num);
  List<syntax_asdl::command_t*>* GetPendingTraps();
  pyos::SignalSafe* signal_safe;
  Dict<BigStr*, syntax_asdl::command_t*>* hooks;
  Dict<int, syntax_asdl::command_t*>* traps;

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassScanned(3, sizeof(TrapState));
  }

  DISALLOW_COPY_AND_ASSIGN(TrapState)
};

int _GetSignalNumber(BigStr* sig_spec);
extern List<BigStr*>* _HOOK_NAMES;
class Trap : public ::vm::_Builtin {
 public:
  Trap(trap_osh::TrapState* trap_state, parse_lib::ParseContext* parse_ctx, dev::Tracer* tracer, ui::ErrorFormatter* errfmt);
  syntax_asdl::command_t* _ParseTrapCode(BigStr* code_str);
  virtual int Run(cmd_value::Argv* cmd_val);

  alloc::Arena* arena;
  ui::ErrorFormatter* errfmt;
  parse_lib::ParseContext* parse_ctx;
  dev::Tracer* tracer;
  trap_osh::TrapState* trap_state;
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Builtin::field_mask()
         | maskbit(offsetof(Trap, arena))
         | maskbit(offsetof(Trap, errfmt))
         | maskbit(offsetof(Trap, parse_ctx))
         | maskbit(offsetof(Trap, tracer))
         | maskbit(offsetof(Trap, trap_state));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(Trap));
  }

  DISALLOW_COPY_AND_ASSIGN(Trap)
};


}  // declare namespace trap_osh

namespace alloc {  // declare

using syntax_asdl::loc;
BigStr* SnipCodeBlock(syntax_asdl::Token* left, syntax_asdl::Token* right, List<syntax_asdl::SourceLine*>* lines);
class ctx_SourceCode {
 public:
  ctx_SourceCode(alloc::Arena* arena, syntax_asdl::source_t* src);
  ~ctx_SourceCode();
  alloc::Arena* arena;

  DISALLOW_COPY_AND_ASSIGN(ctx_SourceCode)
};

class Arena {
 public:
  Arena(bool save_tokens = false);
  void SaveTokens();
  void PushSource(syntax_asdl::source_t* src);
  void PopSource();
  syntax_asdl::SourceLine* AddLine(BigStr* line, int line_num);
  void DiscardLines();
  List<syntax_asdl::SourceLine*>* SaveLinesAndDiscard(syntax_asdl::Token* left, syntax_asdl::Token* right);
  BigStr* SnipCodeString(syntax_asdl::Token* left, syntax_asdl::Token* right);
  syntax_asdl::Token* NewToken(int id_, int col, int length, syntax_asdl::SourceLine* src_line);
  void UnreadOne();
  syntax_asdl::Token* GetToken(int span_id);
  int GetSpanId(syntax_asdl::Token* tok);
  int LastSpanId();
  List<syntax_asdl::SourceLine*>* lines_list;
  int num_tokens;
  bool save_tokens;
  List<syntax_asdl::source_t*>* source_instances;
  Dict<syntax_asdl::Token*, int>* span_id_lookup;
  List<syntax_asdl::Token*>* tokens;
  
  static constexpr uint32_t field_mask() {
    return maskbit(offsetof(Arena, lines_list))
         | maskbit(offsetof(Arena, source_instances))
         | maskbit(offsetof(Arena, span_id_lookup))
         | maskbit(offsetof(Arena, tokens));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(Arena));
  }

  DISALLOW_COPY_AND_ASSIGN(Arena)
};

class LosslessArena : public ::alloc::Arena {
 public:
  
  static constexpr uint32_t field_mask() {
    return ::alloc::Arena::field_mask();
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(LosslessArena));
  }

  DISALLOW_COPY_AND_ASSIGN(LosslessArena)
};

class DynamicArena : public ::alloc::Arena {
 public:
  
  static constexpr uint32_t field_mask() {
    return ::alloc::Arena::field_mask();
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(DynamicArena));
  }

  DISALLOW_COPY_AND_ASSIGN(DynamicArena)
};


}  // declare namespace alloc

namespace ansi {  // declare

extern BigStr* RESET;
extern BigStr* BOLD;
extern BigStr* UNDERLINE;
extern BigStr* REVERSE;
extern BigStr* RED;
extern BigStr* GREEN;
extern BigStr* YELLOW;
extern BigStr* BLUE;
extern BigStr* MAGENTA;
extern BigStr* CYAN;

}  // declare namespace ansi

namespace comp_ui {  // declare

int _PromptLen(BigStr* prompt_str);
class PromptState {
 public:
  PromptState();
  void SetLastPrompt(BigStr* prompt_str);
  BigStr* last_prompt_str;
  int last_prompt_len;

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassScanned(1, sizeof(PromptState));
  }

  DISALLOW_COPY_AND_ASSIGN(PromptState)
};

class State {
 public:
  State();
  BigStr* line_until_tab;
  Dict<BigStr*, BigStr*>* descriptions;
  int display_pos;

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassScanned(2, sizeof(State));
  }

  DISALLOW_COPY_AND_ASSIGN(State)
};

class _IDisplay {
 public:
  _IDisplay(comp_ui::State* comp_state, comp_ui::PromptState* prompt_state, int num_lines_cap, mylib::Writer* f, util::_DebugFile* debug_f);
  void PrintCandidates(BigStr* unused_subst, List<BigStr*>* matches, int unused_match_len);
  virtual void _PrintCandidates(BigStr* unused_subst, List<BigStr*>* matches, int unused_match_len);
  virtual void Reset();
  virtual void ShowPromptOnRight(BigStr* rendered);
  virtual void EraseLines();
  comp_ui::State* comp_state;
  util::_DebugFile* debug_f;
  mylib::Writer* f;
  int num_lines_cap;
  comp_ui::PromptState* prompt_state;
  
  static constexpr uint32_t field_mask() {
    return maskbit(offsetof(_IDisplay, comp_state))
         | maskbit(offsetof(_IDisplay, debug_f))
         | maskbit(offsetof(_IDisplay, f))
         | maskbit(offsetof(_IDisplay, prompt_state));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(_IDisplay));
  }

  DISALLOW_COPY_AND_ASSIGN(_IDisplay)
};

class MinimalDisplay : public ::comp_ui::_IDisplay {
 public:
  MinimalDisplay(comp_ui::State* comp_state, comp_ui::PromptState* prompt_state, util::_DebugFile* debug_f);
  void _RedrawPrompt();
  virtual void _PrintCandidates(BigStr* unused_subst, List<BigStr*>* matches, int unused_match_len);

  void* reader;
  
  static constexpr uint32_t field_mask() {
    return ::comp_ui::_IDisplay::field_mask()
         | maskbit(offsetof(MinimalDisplay, reader));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(MinimalDisplay));
  }

  DISALLOW_COPY_AND_ASSIGN(MinimalDisplay)
};

int _PrintPacked(List<BigStr*>* matches, int max_match_len, int term_width, int max_lines, mylib::Writer* f);
int _PrintLong(List<BigStr*>* matches, int max_match_len, int term_width, int max_lines, Dict<BigStr*, BigStr*>* descriptions, mylib::Writer* f);
class NiceDisplay : public ::comp_ui::_IDisplay {
 public:
  NiceDisplay(int term_width, comp_ui::State* comp_state, comp_ui::PromptState* prompt_state, util::_DebugFile* debug_f, py_readline::Readline* readline, pyos::SignalSafe* signal_safe);
  virtual void Reset();
  void _ReturnToPrompt(int num_lines);
  virtual void _PrintCandidates(BigStr* unused_subst, List<BigStr*>* matches, int unused_max_match_len);
  virtual void ShowPromptOnRight(BigStr* rendered);
  virtual void EraseLines();
  int _GetTerminalWidth();

  bool bold_line;
  int c_count;
  Dict<int, int>* dupes;
  int m_count;
  int num_lines_last_displayed;
  py_readline::Readline* readline;
  pyos::SignalSafe* signal_safe;
  int term_width;
  
  static constexpr uint32_t field_mask() {
    return ::comp_ui::_IDisplay::field_mask()
         | maskbit(offsetof(NiceDisplay, dupes))
         | maskbit(offsetof(NiceDisplay, readline))
         | maskbit(offsetof(NiceDisplay, signal_safe));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(NiceDisplay));
  }

  DISALLOW_COPY_AND_ASSIGN(NiceDisplay)
};

void ExecutePrintCandidates(comp_ui::_IDisplay* display, BigStr* sub, List<BigStr*>* matches, int max_len);
void InitReadline(py_readline::Readline* readline, BigStr* hist_file, completion::RootCompleter* root_comp, comp_ui::_IDisplay* display, util::_DebugFile* debug_f);

}  // declare namespace comp_ui

namespace completion {  // declare

using id_kind_asdl::Id;
using runtime_asdl::scope_e;
class _RetryCompletion {
 public:
  _RetryCompletion();

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassScanned(0, sizeof(_RetryCompletion));
  }

  DISALLOW_COPY_AND_ASSIGN(_RetryCompletion)
};

extern int CH_Break;
extern int CH_Other;
extern int ST_Begin;
extern int ST_Break;
extern int ST_Other;
Tuple2<int, bool> _TRANSITIONS(int state, int ch);
void AdjustArg(BigStr* arg, List<BigStr*>* break_chars, List<BigStr*>* argv_out);
extern Dict<BigStr*, bool>* _DEFAULT_OPTS;
class OptionState {
 public:
  OptionState();
  Dict<BigStr*, bool>* dynamic_opts;
  bool currently_completing;

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassScanned(1, sizeof(OptionState));
  }

  DISALLOW_COPY_AND_ASSIGN(OptionState)
};

class ctx_Completing {
 public:
  ctx_Completing(completion::OptionState* compopt_state);
  ~ctx_Completing();
  completion::OptionState* compopt_state;

  DISALLOW_COPY_AND_ASSIGN(ctx_Completing)
};

void _PrintOpts(Dict<BigStr*, bool>* opts, mylib::BufWriter* f);
class Lookup {
 public:
  Lookup();
  BigStr* __str__();
  void PrintSpecs();
  void ClearCommandsChanged();
  List<BigStr*>* GetCommandsChanged();
  void RegisterName(BigStr* name, Dict<BigStr*, bool>* base_opts, completion::UserSpec* user_spec);
  void RegisterGlob(BigStr* glob_pat, Dict<BigStr*, bool>* base_opts, completion::UserSpec* user_spec);
  Tuple2<Dict<BigStr*, bool>*, completion::UserSpec*> GetSpecForName(BigStr* argv0);
  Tuple2<Dict<BigStr*, bool>*, completion::UserSpec*> GetFirstSpec();
  Tuple2<Dict<BigStr*, bool>*, completion::UserSpec*> GetFallback();
  Dict<BigStr*, Tuple2<Dict<BigStr*, bool>*, completion::UserSpec*>*>* lookup;
  List<BigStr*>* commands_with_spec_changes;
  List<Tuple3<BigStr*, Dict<BigStr*, bool>*, completion::UserSpec*>*>* patterns;

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassScanned(3, sizeof(Lookup));
  }

  DISALLOW_COPY_AND_ASSIGN(Lookup)
};

class Api {
 public:
  Api(BigStr* line, int begin, int end);
  void Update(BigStr* first, BigStr* to_complete, BigStr* prev, int index, List<BigStr*>* partial_argv);
  BigStr* line;
  BigStr* first;
  BigStr* to_complete;
  BigStr* prev;
  List<BigStr*>* partial_argv;
  int begin;
  int end;
  int index;

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassScanned(5, sizeof(Api));
  }

  DISALLOW_COPY_AND_ASSIGN(Api)
};

class CompletionAction {
 public:
  CompletionAction();
  virtual void Matches(completion::Api* comp, List<BigStr*>* _out_yield_acc);
  virtual runtime_asdl::comp_action_t ActionKind();
  virtual void Print(mylib::BufWriter* f);
  
  static constexpr uint32_t field_mask() {
    return kZeroMask;
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(CompletionAction));
  }

  DISALLOW_COPY_AND_ASSIGN(CompletionAction)
};

class UsersAction : public ::completion::CompletionAction {
 public:
  UsersAction();
  virtual void Matches(completion::Api* comp, List<BigStr*>* _out_yield_acc);
  virtual void Print(mylib::BufWriter* f);
  
  static constexpr uint32_t field_mask() {
    return ::completion::CompletionAction::field_mask();
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(UsersAction));
  }

  DISALLOW_COPY_AND_ASSIGN(UsersAction)
};

class TestAction : public ::completion::CompletionAction {
 public:
  TestAction(List<BigStr*>* words, double delay = 0.0);
  virtual void Matches(completion::Api* comp, List<BigStr*>* _out_yield_acc);
  virtual void Print(mylib::BufWriter* f);

  double delay;
  List<BigStr*>* words;
  
  static constexpr uint32_t field_mask() {
    return ::completion::CompletionAction::field_mask()
         | maskbit(offsetof(TestAction, words));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(TestAction));
  }

  DISALLOW_COPY_AND_ASSIGN(TestAction)
};

class DynamicWordsAction : public ::completion::CompletionAction {
 public:
  DynamicWordsAction(word_eval::AbstractWordEvaluator* word_ev, split::SplitContext* splitter, syntax_asdl::CompoundWord* arg_word, ui::ErrorFormatter* errfmt);
  virtual void Matches(completion::Api* comp, List<BigStr*>* _out_yield_acc);
  virtual void Print(mylib::BufWriter* f);

  syntax_asdl::CompoundWord* arg_word;
  ui::ErrorFormatter* errfmt;
  split::SplitContext* splitter;
  word_eval::AbstractWordEvaluator* word_ev;
  
  static constexpr uint32_t field_mask() {
    return ::completion::CompletionAction::field_mask()
         | maskbit(offsetof(DynamicWordsAction, arg_word))
         | maskbit(offsetof(DynamicWordsAction, errfmt))
         | maskbit(offsetof(DynamicWordsAction, splitter))
         | maskbit(offsetof(DynamicWordsAction, word_ev));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(DynamicWordsAction));
  }

  DISALLOW_COPY_AND_ASSIGN(DynamicWordsAction)
};

class FileSystemAction : public ::completion::CompletionAction {
 public:
  FileSystemAction(bool dirs_only, bool exec_only, bool add_slash);
  virtual runtime_asdl::comp_action_t ActionKind();
  virtual void Print(mylib::BufWriter* f);
  virtual void Matches(completion::Api* comp, List<BigStr*>* _out_yield_acc);

  bool add_slash;
  bool dirs_only;
  bool exec_only;
  
  static constexpr uint32_t field_mask() {
    return ::completion::CompletionAction::field_mask();
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(FileSystemAction));
  }

  DISALLOW_COPY_AND_ASSIGN(FileSystemAction)
};

class CommandAction : public ::completion::CompletionAction {
 public:
  CommandAction(cmd_eval::CommandEvaluator* cmd_ev, BigStr* command_name);
  virtual void Matches(completion::Api* comp, List<BigStr*>* _out_yield_acc);

  cmd_eval::CommandEvaluator* cmd_ev;
  BigStr* command_name;
  
  static constexpr uint32_t field_mask() {
    return ::completion::CompletionAction::field_mask()
         | maskbit(offsetof(CommandAction, cmd_ev))
         | maskbit(offsetof(CommandAction, command_name));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(CommandAction));
  }

  DISALLOW_COPY_AND_ASSIGN(CommandAction)
};

class ShellFuncAction : public ::completion::CompletionAction {
 public:
  ShellFuncAction(cmd_eval::CommandEvaluator* cmd_ev, value::Proc* func, completion::Lookup* comp_lookup);
  virtual void Print(mylib::BufWriter* f);
  virtual runtime_asdl::comp_action_t ActionKind();
  void debug(BigStr* msg);
  virtual void Matches(completion::Api* comp, List<BigStr*>* _out_yield_acc);

  cmd_eval::CommandEvaluator* cmd_ev;
  completion::Lookup* comp_lookup;
  value::Proc* func;
  
  static constexpr uint32_t field_mask() {
    return ::completion::CompletionAction::field_mask()
         | maskbit(offsetof(ShellFuncAction, cmd_ev))
         | maskbit(offsetof(ShellFuncAction, comp_lookup))
         | maskbit(offsetof(ShellFuncAction, func));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(ShellFuncAction));
  }

  DISALLOW_COPY_AND_ASSIGN(ShellFuncAction)
};

class VariablesAction : public ::completion::CompletionAction {
 public:
  VariablesAction(state::Mem* mem);
  virtual void Matches(completion::Api* comp, List<BigStr*>* _out_yield_acc);
  virtual void Print(mylib::BufWriter* f);

  state::Mem* mem;
  
  static constexpr uint32_t field_mask() {
    return ::completion::CompletionAction::field_mask()
         | maskbit(offsetof(VariablesAction, mem));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(VariablesAction));
  }

  DISALLOW_COPY_AND_ASSIGN(VariablesAction)
};

class ExportedVarsAction : public ::completion::CompletionAction {
 public:
  ExportedVarsAction(state::Mem* mem);
  virtual void Matches(completion::Api* comp, List<BigStr*>* _out_yield_acc);

  state::Mem* mem;
  
  static constexpr uint32_t field_mask() {
    return ::completion::CompletionAction::field_mask()
         | maskbit(offsetof(ExportedVarsAction, mem));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(ExportedVarsAction));
  }

  DISALLOW_COPY_AND_ASSIGN(ExportedVarsAction)
};

class ExternalCommandAction : public ::completion::CompletionAction {
 public:
  ExternalCommandAction(state::Mem* mem);
  virtual void Print(mylib::BufWriter* f);
  virtual void Matches(completion::Api* comp, List<BigStr*>* _out_yield_acc);

  Dict<Tuple2<BigStr*, int>*, List<BigStr*>*>* cache;
  state::Mem* mem;
  
  static constexpr uint32_t field_mask() {
    return ::completion::CompletionAction::field_mask()
         | maskbit(offsetof(ExternalCommandAction, cache))
         | maskbit(offsetof(ExternalCommandAction, mem));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(ExternalCommandAction));
  }

  DISALLOW_COPY_AND_ASSIGN(ExternalCommandAction)
};

class _Predicate {
 public:
  _Predicate();
  virtual bool Evaluate(BigStr* candidate);
  virtual void Print(mylib::BufWriter* f);
  
  static constexpr uint32_t field_mask() {
    return kZeroMask;
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(_Predicate));
  }

  DISALLOW_COPY_AND_ASSIGN(_Predicate)
};

class DefaultPredicate : public ::completion::_Predicate {
 public:
  DefaultPredicate();
  virtual bool Evaluate(BigStr* candidate);
  virtual void Print(mylib::BufWriter* f);
  
  static constexpr uint32_t field_mask() {
    return ::completion::_Predicate::field_mask();
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(DefaultPredicate));
  }

  DISALLOW_COPY_AND_ASSIGN(DefaultPredicate)
};

class GlobPredicate : public ::completion::_Predicate {
 public:
  GlobPredicate(bool include, BigStr* glob_pat);
  virtual bool Evaluate(BigStr* candidate);
  virtual void Print(mylib::BufWriter* f);

  BigStr* glob_pat;
  bool include;
  
  static constexpr uint32_t field_mask() {
    return ::completion::_Predicate::field_mask()
         | maskbit(offsetof(GlobPredicate, glob_pat));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(GlobPredicate));
  }

  DISALLOW_COPY_AND_ASSIGN(GlobPredicate)
};

class UserSpec {
 public:
  UserSpec(List<completion::CompletionAction*>* actions, List<completion::CompletionAction*>* extra_actions, List<completion::CompletionAction*>* else_actions, completion::_Predicate* predicate, BigStr* prefix, BigStr* suffix);
  void PrintSpec(mylib::BufWriter* f);
  void AllMatches(completion::Api* comp, List<Tuple2<BigStr*, runtime_asdl::comp_action_t>*>* _out_yield_acc);
  List<completion::CompletionAction*>* actions;
  List<completion::CompletionAction*>* extra_actions;
  List<completion::CompletionAction*>* else_actions;
  completion::_Predicate* predicate;
  BigStr* prefix;
  BigStr* suffix;

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassScanned(6, sizeof(UserSpec));
  }

  DISALLOW_COPY_AND_ASSIGN(UserSpec)
};

bool IsDollar(syntax_asdl::Token* t);
bool IsDummy(syntax_asdl::Token* t);
bool WordEndsWithCompDummy(syntax_asdl::CompoundWord* w);
class RootCompleter {
 public:
  RootCompleter(word_eval::AbstractWordEvaluator* word_ev, state::Mem* mem, completion::Lookup* comp_lookup, completion::OptionState* compopt_state, comp_ui::State* comp_ui_state, parse_lib::ParseContext* parse_ctx, util::_DebugFile* debug_f);
  void Matches(completion::Api* comp, List<BigStr*>* _out_yield_acc);
  void _PostProcess(Dict<BigStr*, bool>* base_opts, Dict<BigStr*, bool>* dynamic_opts, completion::UserSpec* user_spec, completion::Api* comp, List<BigStr*>* _out_yield_acc);
  word_eval::AbstractWordEvaluator* word_ev;
  state::Mem* mem;
  completion::Lookup* comp_lookup;
  completion::OptionState* compopt_state;
  comp_ui::State* comp_ui_state;
  parse_lib::ParseContext* parse_ctx;
  util::_DebugFile* debug_f;

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassScanned(7, sizeof(RootCompleter));
  }

  DISALLOW_COPY_AND_ASSIGN(RootCompleter)
};

class ReadlineCallback {
 public:
  ReadlineCallback(py_readline::Readline* readline, completion::RootCompleter* root_comp, util::_DebugFile* debug_f);
  BigStr* _GetNextCompletion(int state);
  BigStr* __call__(BigStr* unused_word, int state);
  py_readline::Readline* readline;
  completion::RootCompleter* root_comp;
  util::_DebugFile* debug_f;
  List<BigStr*>* comp_matches;

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassScanned(4, sizeof(ReadlineCallback));
  }

  DISALLOW_COPY_AND_ASSIGN(ReadlineCallback)
};

BigStr* ExecuteReadlineCallback(completion::ReadlineCallback* cb, BigStr* word, int state);

}  // declare namespace completion

namespace dev {  // declare

using runtime_asdl::cmd_value;
using runtime_asdl::scope_e;
using value_asdl::sh_lvalue;
class CrashDumper {
 public:
  CrashDumper(BigStr* crash_dump_dir, process::FdState* fd_state);
  void MaybeRecord(cmd_eval::CommandEvaluator* cmd_ev, error::_ErrorWithLocation* err);
  void MaybeDump(int status);
  BigStr* crash_dump_dir;
  process::FdState* fd_state;
  List<value_asdl::value_t*>* var_stack;
  List<value_asdl::value_t*>* argv_stack;
  List<value_asdl::value_t*>* debug_stack;
  Dict<BigStr*, value_asdl::value_t*>* error;
  bool do_collect;
  bool collected;

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassScanned(6, sizeof(CrashDumper));
  }

  DISALLOW_COPY_AND_ASSIGN(CrashDumper)
};

class ctx_Tracer {
 public:
  ctx_Tracer(dev::Tracer* tracer, BigStr* label, List<BigStr*>* argv);
  ~ctx_Tracer();
  BigStr* arg;
  BigStr* label;
  dev::Tracer* tracer;

  DISALLOW_COPY_AND_ASSIGN(ctx_Tracer)
};

void _PrintShValue(value_asdl::value_t* val, mylib::BufWriter* buf);
void PrintShellArgv(List<BigStr*>* argv, mylib::BufWriter* buf);
void _PrintYshArgv(List<BigStr*>* argv, mylib::BufWriter* buf);
class MultiTracer {
 public:
  MultiTracer(int shell_pid, BigStr* out_dir, BigStr* dumps, BigStr* streams, process::FdState* fd_state);
  void OnNewProcess(int child_pid);
  void EmitArgv0(BigStr* argv0);
  void WriteDumps();
  BigStr* out_dir;
  BigStr* dumps;
  BigStr* streams;
  process::FdState* fd_state;
  Dict<BigStr*, int>* hist_argv0;
  int this_pid;

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassScanned(5, sizeof(MultiTracer));
  }

  DISALLOW_COPY_AND_ASSIGN(MultiTracer)
};

class Tracer {
 public:
  Tracer(parse_lib::ParseContext* parse_ctx, optview::Exec* exec_opts, state::MutableOpts* mutable_opts, state::Mem* mem, util::_DebugFile* f, dev::MultiTracer* multi_trace);
  void CheckCircularDeps();
  BigStr* _EvalPS4(BigStr* punct);
  void _Inc();
  void _Dec();
  mylib::BufWriter* _ShTraceBegin();
  mylib::BufWriter* _RichTraceBegin(BigStr* punct);
  void OnProcessStart(int pid, runtime_asdl::trace_t* why);
  void OnProcessEnd(int pid, int status);
  void OnNewProcess(int child_pid);
  void PushMessage(BigStr* label, List<BigStr*>* argv);
  void PopMessage(BigStr* label, BigStr* arg);
  void OtherMessage(BigStr* message);
  void OnExec(List<BigStr*>* argv);
  void OnBuiltin(int builtin_id, List<BigStr*>* argv);
  void OnSimpleCommand(List<BigStr*>* argv);
  void OnAssignBuiltin(cmd_value::Assign* cmd_val);
  void OnShAssignment(value_asdl::sh_lvalue_t* lval, syntax_asdl::assign_op_t op, value_asdl::value_t* val, int flags, runtime_asdl::scope_t which_scopes);
  void OnControlFlow(BigStr* keyword, int arg);
  void PrintSourceCode(syntax_asdl::Token* left_tok, syntax_asdl::Token* right_tok, alloc::Arena* arena);
  parse_lib::ParseContext* parse_ctx;
  optview::Exec* exec_opts;
  state::MutableOpts* mutable_opts;
  state::Mem* mem;
  util::_DebugFile* f;
  dev::MultiTracer* multi_trace;
  word_eval::NormalWordEvaluator* word_ev;
  List<BigStr*>* indents;
  Dict<BigStr*, syntax_asdl::CompoundWord*>* parse_cache;
  value::Str* val_indent;
  value::Str* val_punct;
  value::Str* val_pid_str;
  value_asdl::LeftName* lval_indent;
  value_asdl::LeftName* lval_punct;
  value_asdl::LeftName* lval_pid_str;
  int ind;

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassScanned(15, sizeof(Tracer));
  }

  DISALLOW_COPY_AND_ASSIGN(Tracer)
};


}  // declare namespace dev

namespace error {  // declare

using syntax_asdl::loc;
BigStr* _ValType(value_asdl::value_t* val);
class _ErrorWithLocation {
 public:
  _ErrorWithLocation(BigStr* msg, syntax_asdl::loc_t* location);
  bool HasLocation();
  BigStr* UserErrorString();
  syntax_asdl::loc_t* location;
  BigStr* msg;
  
  static constexpr uint32_t field_mask() {
    return maskbit(offsetof(_ErrorWithLocation, location))
         | maskbit(offsetof(_ErrorWithLocation, msg));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(_ErrorWithLocation));
  }

  DISALLOW_COPY_AND_ASSIGN(_ErrorWithLocation)
};

class Usage : public ::error::_ErrorWithLocation {
 public:
  Usage(BigStr* msg, syntax_asdl::loc_t* location);
  
  static constexpr uint32_t field_mask() {
    return ::error::_ErrorWithLocation::field_mask();
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(Usage));
  }

  DISALLOW_COPY_AND_ASSIGN(Usage)
};

class Parse : public ::error::_ErrorWithLocation {
 public:
  Parse(BigStr* msg, syntax_asdl::loc_t* location);
  
  static constexpr uint32_t field_mask() {
    return ::error::_ErrorWithLocation::field_mask();
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(Parse));
  }

  DISALLOW_COPY_AND_ASSIGN(Parse)
};

class FailGlob : public ::error::_ErrorWithLocation {
 public:
  FailGlob(BigStr* msg, syntax_asdl::loc_t* location);
  
  static constexpr uint32_t field_mask() {
    return ::error::_ErrorWithLocation::field_mask();
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(FailGlob));
  }

  DISALLOW_COPY_AND_ASSIGN(FailGlob)
};

class RedirectEval : public ::error::_ErrorWithLocation {
 public:
  RedirectEval(BigStr* msg, syntax_asdl::loc_t* location);
  
  static constexpr uint32_t field_mask() {
    return ::error::_ErrorWithLocation::field_mask();
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(RedirectEval));
  }

  DISALLOW_COPY_AND_ASSIGN(RedirectEval)
};

class FatalRuntime : public ::error::_ErrorWithLocation {
 public:
  FatalRuntime(int exit_status, BigStr* msg, syntax_asdl::loc_t* location);
  int ExitStatus();

  int exit_status;
  
  static constexpr uint32_t field_mask() {
    return ::error::_ErrorWithLocation::field_mask();
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(FatalRuntime));
  }

  DISALLOW_COPY_AND_ASSIGN(FatalRuntime)
};

class Strict : public ::error::FatalRuntime {
 public:
  Strict(BigStr* msg, syntax_asdl::loc_t* location);
  
  static constexpr uint32_t field_mask() {
    return ::error::FatalRuntime::field_mask();
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(Strict));
  }

  DISALLOW_COPY_AND_ASSIGN(Strict)
};

class ErrExit : public ::error::FatalRuntime {
 public:
  ErrExit(int exit_status, BigStr* msg, syntax_asdl::loc_t* location, bool show_code = false);

  bool show_code;
  
  static constexpr uint32_t field_mask() {
    return ::error::FatalRuntime::field_mask();
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(ErrExit));
  }

  DISALLOW_COPY_AND_ASSIGN(ErrExit)
};

class Expr : public ::error::FatalRuntime {
 public:
  Expr(BigStr* msg, syntax_asdl::loc_t* location);
  
  static constexpr uint32_t field_mask() {
    return ::error::FatalRuntime::field_mask();
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(Expr));
  }

  DISALLOW_COPY_AND_ASSIGN(Expr)
};

class Structured : public ::error::FatalRuntime {
 public:
  Structured(int status, BigStr* msg, syntax_asdl::loc_t* location, Dict<BigStr*, value_asdl::value_t*>* properties = nullptr);
  value::Dict* ToDict();

  Dict<BigStr*, value_asdl::value_t*>* properties;
  
  static constexpr uint32_t field_mask() {
    return ::error::FatalRuntime::field_mask()
         | maskbit(offsetof(Structured, properties));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(Structured));
  }

  DISALLOW_COPY_AND_ASSIGN(Structured)
};

class AssertionErr : public ::error::Expr {
 public:
  AssertionErr(BigStr* msg, syntax_asdl::loc_t* location);
  
  static constexpr uint32_t field_mask() {
    return ::error::Expr::field_mask();
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(AssertionErr));
  }

  DISALLOW_COPY_AND_ASSIGN(AssertionErr)
};

class TypeErrVerbose : public ::error::Expr {
 public:
  TypeErrVerbose(BigStr* msg, syntax_asdl::loc_t* location);
  
  static constexpr uint32_t field_mask() {
    return ::error::Expr::field_mask();
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(TypeErrVerbose));
  }

  DISALLOW_COPY_AND_ASSIGN(TypeErrVerbose)
};

class TypeErr : public ::error::TypeErrVerbose {
 public:
  TypeErr(value_asdl::value_t* actual_val, BigStr* msg, syntax_asdl::loc_t* location);
  
  static constexpr uint32_t field_mask() {
    return ::error::TypeErrVerbose::field_mask();
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(TypeErr));
  }

  DISALLOW_COPY_AND_ASSIGN(TypeErr)
};

class Runtime {
 public:
  Runtime(BigStr* msg);
  BigStr* UserErrorString();
  BigStr* msg;

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassScanned(1, sizeof(Runtime));
  }

  DISALLOW_COPY_AND_ASSIGN(Runtime)
};

class Decode {
 public:
  Decode(BigStr* msg, BigStr* s, int start_pos, int end_pos, int line_num);
  BigStr* Message();
  BigStr* __str__();
  BigStr* msg;
  BigStr* s;
  int start_pos;
  int end_pos;
  int line_num;

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassScanned(2, sizeof(Decode));
  }

  DISALLOW_COPY_AND_ASSIGN(Decode)
};

class Encode {
 public:
  Encode(BigStr* msg);
  BigStr* Message();
  BigStr* msg;

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassScanned(1, sizeof(Encode));
  }

  DISALLOW_COPY_AND_ASSIGN(Encode)
};

[[noreturn]] void e_usage(BigStr* msg, syntax_asdl::loc_t* location);
[[noreturn]] void e_strict(BigStr* msg, syntax_asdl::loc_t* location);
[[noreturn]] void p_die(BigStr* msg, syntax_asdl::loc_t* location);
[[noreturn]] void e_die(BigStr* msg, syntax_asdl::loc_t* location = nullptr);
[[noreturn]] void e_die_status(int status, BigStr* msg, syntax_asdl::loc_t* location = nullptr);

}  // declare namespace error

namespace executor {  // declare

using id_kind_asdl::Id;
using syntax_asdl::loc;
class _ProcessSubFrame {
 public:
  _ProcessSubFrame();
  bool WasModified();
  void Append(process::Process* p, int fd, syntax_asdl::loc_t* status_loc);
  void MaybeWaitOnProcessSubs(process::Waiter* waiter, runtime_asdl::StatusArray* status_array);
  List<process::Process*>* _to_wait;
  List<int>* _to_close;
  List<syntax_asdl::loc_t*>* _locs;
  bool _modified;

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassScanned(3, sizeof(_ProcessSubFrame));
  }

  DISALLOW_COPY_AND_ASSIGN(_ProcessSubFrame)
};

extern int DO_FORK;
extern int NO_CALL_PROCS;
extern int USE_DEFAULT_PATH;
extern List<BigStr*>* DEFAULT_PATH;
class ShellExecutor : public ::vm::_Executor {
 public:
  ShellExecutor(state::Mem* mem, optview::Exec* exec_opts, state::MutableOpts* mutable_opts, Dict<BigStr*, value::Proc*>* procs, hay_ysh::HayState* hay_state, Dict<int, vm::_Builtin*>* builtins, state::SearchPath* search_path, process::ExternalProgram* ext_prog, process::Waiter* waiter, dev::Tracer* tracer, process::JobControl* job_control, process::JobList* job_list, process::FdState* fd_state, trap_osh::TrapState* trap_state, ui::ErrorFormatter* errfmt);
  virtual void CheckCircularDeps();
  process::Process* _MakeProcess(syntax_asdl::command_t* node, bool inherit_errexit = true);
  virtual int RunBuiltin(int builtin_id, cmd_value::Argv* cmd_val);
  virtual int RunSimpleCommand(cmd_value::Argv* cmd_val, runtime_asdl::CommandStatus* cmd_st, int run_flags);
  virtual int RunBackgroundJob(syntax_asdl::command_t* node);
  virtual void RunPipeline(command::Pipeline* node, runtime_asdl::CommandStatus* status_out);
  virtual int RunSubshell(syntax_asdl::command_t* node);
  virtual BigStr* RunCommandSub(syntax_asdl::CommandSub* cs_part);
  virtual BigStr* RunProcessSub(syntax_asdl::CommandSub* cs_part);
  virtual void PushRedirects(List<runtime_asdl::RedirValue*>* redirects, List<IOError_OSError*>* err_out);
  virtual void PopRedirects(int num_redirects, List<IOError_OSError*>* err_out);
  virtual void PushProcessSub();
  virtual void PopProcessSub(runtime_asdl::StatusArray* compound_st);

  Dict<int, vm::_Builtin*>* builtins;
  List<executor::_ProcessSubFrame*>* clean_frame_pool;
  ui::ErrorFormatter* errfmt;
  optview::Exec* exec_opts;
  process::ExternalProgram* ext_prog;
  process::FdState* fd_state;
  process::Pipeline* fg_pipeline;
  hay_ysh::HayState* hay_state;
  process::JobControl* job_control;
  process::JobList* job_list;
  state::Mem* mem;
  dev::MultiTracer* multi_trace;
  state::MutableOpts* mutable_opts;
  List<executor::_ProcessSubFrame*>* process_sub_stack;
  Dict<BigStr*, value::Proc*>* procs;
  state::SearchPath* search_path;
  dev::Tracer* tracer;
  trap_osh::TrapState* trap_state;
  process::Waiter* waiter;
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Executor::field_mask()
         | maskbit(offsetof(ShellExecutor, builtins))
         | maskbit(offsetof(ShellExecutor, clean_frame_pool))
         | maskbit(offsetof(ShellExecutor, errfmt))
         | maskbit(offsetof(ShellExecutor, exec_opts))
         | maskbit(offsetof(ShellExecutor, ext_prog))
         | maskbit(offsetof(ShellExecutor, fd_state))
         | maskbit(offsetof(ShellExecutor, fg_pipeline))
         | maskbit(offsetof(ShellExecutor, hay_state))
         | maskbit(offsetof(ShellExecutor, job_control))
         | maskbit(offsetof(ShellExecutor, job_list))
         | maskbit(offsetof(ShellExecutor, mem))
         | maskbit(offsetof(ShellExecutor, multi_trace))
         | maskbit(offsetof(ShellExecutor, mutable_opts))
         | maskbit(offsetof(ShellExecutor, process_sub_stack))
         | maskbit(offsetof(ShellExecutor, procs))
         | maskbit(offsetof(ShellExecutor, search_path))
         | maskbit(offsetof(ShellExecutor, tracer))
         | maskbit(offsetof(ShellExecutor, trap_state))
         | maskbit(offsetof(ShellExecutor, waiter));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(ShellExecutor));
  }

  DISALLOW_COPY_AND_ASSIGN(ShellExecutor)
};


}  // declare namespace executor

namespace main_loop {  // declare

class ctx_Descriptors {
 public:
  ctx_Descriptors(List<int>* fds);
  ~ctx_Descriptors();
  List<int>* fds;
  int saved0;
  int saved1;
  int saved2;

  DISALLOW_COPY_AND_ASSIGN(ctx_Descriptors)
};

void fanos_log(BigStr* msg);
void ShowDescriptorState(BigStr* label);
class Headless {
 public:
  Headless(cmd_eval::CommandEvaluator* cmd_ev, parse_lib::ParseContext* parse_ctx, ui::ErrorFormatter* errfmt);
  int Loop();
  BigStr* EVAL(BigStr* arg);
  int _Loop();
  cmd_eval::CommandEvaluator* cmd_ev;
  parse_lib::ParseContext* parse_ctx;
  ui::ErrorFormatter* errfmt;

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassScanned(3, sizeof(Headless));
  }

  DISALLOW_COPY_AND_ASSIGN(Headless)
};

int Interactive(arg_types::main* flag, cmd_eval::CommandEvaluator* cmd_ev, cmd_parse::CommandParser* c_parser, comp_ui::_IDisplay* display, prompt::UserPlugin* prompt_plugin, process::Waiter* waiter, ui::ErrorFormatter* errfmt);
int Batch(cmd_eval::CommandEvaluator* cmd_ev, cmd_parse::CommandParser* c_parser, ui::ErrorFormatter* errfmt, int cmd_flags = 0);
syntax_asdl::command_t* ParseWholeFile(cmd_parse::CommandParser* c_parser);

}  // declare namespace main_loop

namespace num {  // declare

value::Int* ToBig(int i);
mops::BigInt Exponent(mops::BigInt x, mops::BigInt y);
int Exponent2(int x, int y);
mops::BigInt IntDivide(mops::BigInt x, mops::BigInt y);
int IntDivide2(int x, int y);
mops::BigInt IntRemainder(mops::BigInt x, mops::BigInt y);
int IntRemainder2(int x, int y);

}  // declare namespace num

namespace process {  // declare

using id_kind_asdl::Id;
extern int NO_FD;
extern int _SHELL_MIN_FD;
extern int STYLE_DEFAULT;
extern int STYLE_LONG;
extern int STYLE_PID_ONLY;
extern List<BigStr*>* CURRENT_JOB_SPECS;
class ctx_FileCloser {
 public:
  ctx_FileCloser(mylib::LineReader* f);
  ~ctx_FileCloser();
  mylib::LineReader* f;

  DISALLOW_COPY_AND_ASSIGN(ctx_FileCloser)
};

void InitInteractiveShell();
int SaveFd(int fd);
class _RedirFrame {
 public:
  _RedirFrame(int saved_fd, int orig_fd, bool forget);
  int saved_fd;
  int orig_fd;
  bool forget;

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassScanned(0, sizeof(_RedirFrame));
  }

  DISALLOW_COPY_AND_ASSIGN(_RedirFrame)
};

class _FdFrame {
 public:
  _FdFrame();
  void Forget();
  List<process::_RedirFrame*>* saved;
  List<process::Process*>* need_wait;

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassScanned(2, sizeof(_FdFrame));
  }

  DISALLOW_COPY_AND_ASSIGN(_FdFrame)
};

class FdState {
 public:
  FdState(ui::ErrorFormatter* errfmt, process::JobControl* job_control, process::JobList* job_list, state::Mem* mem, dev::Tracer* tracer, process::Waiter* waiter);
  mylib::LineReader* Open(BigStr* path);
  mylib::Writer* OpenForWrite(BigStr* path);
  mylib::File* _Open(BigStr* path, BigStr* c_mode, int fd_mode);
  void _WriteFdToMem(BigStr* fd_name, int fd);
  int _ReadFdFromMem(BigStr* fd_name);
  bool _PushSave(int fd);
  int _PushDup(int fd1, syntax_asdl::redir_loc_t* blame_loc);
  bool _PushCloseFd(syntax_asdl::redir_loc_t* blame_loc);
  void _PushClose(int fd);
  void _PushWait(process::Process* proc);
  void _ApplyRedirect(runtime_asdl::RedirValue* r);
  void Push(List<runtime_asdl::RedirValue*>* redirects, List<IOError_OSError*>* err_out);
  bool PushStdinFromPipe(int r);
  void Pop(List<IOError_OSError*>* err_out);
  void MakePermanent();
  ui::ErrorFormatter* errfmt;
  process::JobControl* job_control;
  process::JobList* job_list;
  process::_FdFrame* cur_frame;
  List<process::_FdFrame*>* stack;
  state::Mem* mem;
  dev::Tracer* tracer;
  process::Waiter* waiter;

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassScanned(8, sizeof(FdState));
  }

  DISALLOW_COPY_AND_ASSIGN(FdState)
};

class ChildStateChange {
 public:
  ChildStateChange();
  virtual void Apply();
  virtual void ApplyFromParent(process::Process* proc);
  
  static constexpr uint32_t field_mask() {
    return kZeroMask;
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(ChildStateChange));
  }

  DISALLOW_COPY_AND_ASSIGN(ChildStateChange)
};

class StdinFromPipe : public ::process::ChildStateChange {
 public:
  StdinFromPipe(int pipe_read_fd, int w);
  virtual void Apply();

  int r;
  int w;
  
  static constexpr uint32_t field_mask() {
    return ::process::ChildStateChange::field_mask();
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(StdinFromPipe));
  }

  DISALLOW_COPY_AND_ASSIGN(StdinFromPipe)
};

class StdoutToPipe : public ::process::ChildStateChange {
 public:
  StdoutToPipe(int r, int pipe_write_fd);
  virtual void Apply();

  int r;
  int w;
  
  static constexpr uint32_t field_mask() {
    return ::process::ChildStateChange::field_mask();
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(StdoutToPipe));
  }

  DISALLOW_COPY_AND_ASSIGN(StdoutToPipe)
};

extern int INVALID_PGID;
extern int OWN_LEADER;
class SetPgid : public ::process::ChildStateChange {
 public:
  SetPgid(int pgid, dev::Tracer* tracer);
  virtual void Apply();
  virtual void ApplyFromParent(process::Process* proc);

  int pgid;
  dev::Tracer* tracer;
  
  static constexpr uint32_t field_mask() {
    return ::process::ChildStateChange::field_mask()
         | maskbit(offsetof(SetPgid, tracer));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(SetPgid));
  }

  DISALLOW_COPY_AND_ASSIGN(SetPgid)
};

class ExternalProgram {
 public:
  ExternalProgram(BigStr* hijack_shebang, process::FdState* fd_state, ui::ErrorFormatter* errfmt, util::_DebugFile* debug_f);
  void Exec(BigStr* argv0_path, cmd_value::Argv* cmd_val, Dict<BigStr*, BigStr*>* environ);
  void _Exec(BigStr* argv0_path, List<BigStr*>* argv, syntax_asdl::loc_t* argv0_loc, Dict<BigStr*, BigStr*>* environ, bool should_retry);
  BigStr* hijack_shebang;
  process::FdState* fd_state;
  ui::ErrorFormatter* errfmt;
  util::_DebugFile* debug_f;

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassScanned(4, sizeof(ExternalProgram));
  }

  DISALLOW_COPY_AND_ASSIGN(ExternalProgram)
};

class Thunk {
 public:
  Thunk();
  virtual void Run();
  virtual BigStr* UserString();
  
  static constexpr uint32_t field_mask() {
    return kZeroMask;
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(Thunk));
  }

  DISALLOW_COPY_AND_ASSIGN(Thunk)
};

class ExternalThunk : public ::process::Thunk {
 public:
  ExternalThunk(process::ExternalProgram* ext_prog, BigStr* argv0_path, cmd_value::Argv* cmd_val, Dict<BigStr*, BigStr*>* environ);
  virtual BigStr* UserString();
  virtual void Run();

  BigStr* argv0_path;
  cmd_value::Argv* cmd_val;
  Dict<BigStr*, BigStr*>* environ;
  process::ExternalProgram* ext_prog;
  
  static constexpr uint32_t field_mask() {
    return ::process::Thunk::field_mask()
         | maskbit(offsetof(ExternalThunk, argv0_path))
         | maskbit(offsetof(ExternalThunk, cmd_val))
         | maskbit(offsetof(ExternalThunk, environ))
         | maskbit(offsetof(ExternalThunk, ext_prog));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(ExternalThunk));
  }

  DISALLOW_COPY_AND_ASSIGN(ExternalThunk)
};

class SubProgramThunk : public ::process::Thunk {
 public:
  SubProgramThunk(cmd_eval::CommandEvaluator* cmd_ev, syntax_asdl::command_t* node, trap_osh::TrapState* trap_state, dev::MultiTracer* multi_trace, bool inherit_errexit = true);
  virtual BigStr* UserString();
  virtual void Run();

  cmd_eval::CommandEvaluator* cmd_ev;
  bool inherit_errexit;
  dev::MultiTracer* multi_trace;
  syntax_asdl::command_t* node;
  trap_osh::TrapState* trap_state;
  
  static constexpr uint32_t field_mask() {
    return ::process::Thunk::field_mask()
         | maskbit(offsetof(SubProgramThunk, cmd_ev))
         | maskbit(offsetof(SubProgramThunk, multi_trace))
         | maskbit(offsetof(SubProgramThunk, node))
         | maskbit(offsetof(SubProgramThunk, trap_state));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(SubProgramThunk));
  }

  DISALLOW_COPY_AND_ASSIGN(SubProgramThunk)
};

class _HereDocWriterThunk : public ::process::Thunk {
 public:
  _HereDocWriterThunk(int w, BigStr* body_str);
  virtual BigStr* UserString();
  virtual void Run();

  BigStr* body_str;
  int w;
  
  static constexpr uint32_t field_mask() {
    return ::process::Thunk::field_mask()
         | maskbit(offsetof(_HereDocWriterThunk, body_str));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(_HereDocWriterThunk));
  }

  DISALLOW_COPY_AND_ASSIGN(_HereDocWriterThunk)
};

class Job {
 public:
  Job();
  virtual void DisplayJob(int job_id, mylib::Writer* f, int style);
  runtime_asdl::job_state_t State();
  virtual int ProcessGroupId();
  virtual runtime_asdl::wait_status_t* JobWait(process::Waiter* waiter);
  void SetBackground();
  void SetForeground();
  bool in_background;
  int job_id;
  runtime_asdl::job_state_t state;
  
  static constexpr uint32_t field_mask() {
    return kZeroMask;
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(Job));
  }

  DISALLOW_COPY_AND_ASSIGN(Job)
};

class Process : public ::process::Job {
 public:
  Process(process::Thunk* thunk, process::JobControl* job_control, process::JobList* job_list, dev::Tracer* tracer);
  void Init_ParentPipeline(process::Pipeline* pi);
  virtual int ProcessGroupId();
  virtual void DisplayJob(int job_id, mylib::Writer* f, int style);
  void AddStateChange(process::ChildStateChange* s);
  void AddPipeToClose(int r, int w);
  void MaybeClosePipe();
  int StartProcess(runtime_asdl::trace_t* why);
  int Wait(process::Waiter* waiter);
  virtual runtime_asdl::wait_status_t* JobWait(process::Waiter* waiter);
  void WhenStopped(int stop_sig);
  void WhenDone(int pid, int status);
  int RunProcess(process::Waiter* waiter, runtime_asdl::trace_t* why);

  int close_r;
  int close_w;
  process::JobControl* job_control;
  process::JobList* job_list;
  process::Pipeline* parent_pipeline;
  int pid;
  List<process::ChildStateChange*>* state_changes;
  int status;
  process::Thunk* thunk;
  dev::Tracer* tracer;
  
  static constexpr uint32_t field_mask() {
    return ::process::Job::field_mask()
         | maskbit(offsetof(Process, job_control))
         | maskbit(offsetof(Process, job_list))
         | maskbit(offsetof(Process, parent_pipeline))
         | maskbit(offsetof(Process, state_changes))
         | maskbit(offsetof(Process, thunk))
         | maskbit(offsetof(Process, tracer));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(Process));
  }

  DISALLOW_COPY_AND_ASSIGN(Process)
};

class ctx_Pipe {
 public:
  ctx_Pipe(process::FdState* fd_state, int fd, List<IOError_OSError*>* err_out);
  ~ctx_Pipe();
  process::FdState* fd_state;
  List<IOError_OSError*>* err_out;

  DISALLOW_COPY_AND_ASSIGN(ctx_Pipe)
};

class Pipeline : public ::process::Job {
 public:
  Pipeline(bool sigpipe_status_ok, process::JobControl* job_control, process::JobList* job_list, dev::Tracer* tracer);
  virtual int ProcessGroupId();
  virtual void DisplayJob(int job_id, mylib::Writer* f, int style);
  void DebugPrint();
  void Add(process::Process* p);
  void AddLast(Tuple2<cmd_eval::CommandEvaluator*, syntax_asdl::command_t*>* thunk);
  void StartPipeline(process::Waiter* waiter);
  int LastPid();
  List<int>* Wait(process::Waiter* waiter);
  virtual runtime_asdl::wait_status_t* JobWait(process::Waiter* waiter);
  List<int>* RunLastPart(process::Waiter* waiter, process::FdState* fd_state);
  bool AllDone();
  void WhenDone(int pid, int status);

  process::JobControl* job_control;
  process::JobList* job_list;
  Tuple2<int, int>* last_pipe;
  Tuple2<cmd_eval::CommandEvaluator*, syntax_asdl::command_t*>* last_thunk;
  int pgid;
  List<int>* pids;
  List<int>* pipe_status;
  List<process::Process*>* procs;
  bool sigpipe_status_ok;
  int status;
  dev::Tracer* tracer;
  
  static constexpr uint32_t field_mask() {
    return ::process::Job::field_mask()
         | maskbit(offsetof(Pipeline, job_control))
         | maskbit(offsetof(Pipeline, job_list))
         | maskbit(offsetof(Pipeline, last_pipe))
         | maskbit(offsetof(Pipeline, last_thunk))
         | maskbit(offsetof(Pipeline, pids))
         | maskbit(offsetof(Pipeline, pipe_status))
         | maskbit(offsetof(Pipeline, procs))
         | maskbit(offsetof(Pipeline, tracer));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(Pipeline));
  }

  DISALLOW_COPY_AND_ASSIGN(Pipeline)
};

BigStr* _JobStateStr(runtime_asdl::job_state_t i);
int _GetTtyFd();
class ctx_TerminalControl {
 public:
  ctx_TerminalControl(process::JobControl* job_control, ui::ErrorFormatter* errfmt);
  ~ctx_TerminalControl();
  process::JobControl* job_control;
  ui::ErrorFormatter* errfmt;

  DISALLOW_COPY_AND_ASSIGN(ctx_TerminalControl)
};

class JobControl {
 public:
  JobControl();
  void InitJobControl();
  bool Enabled();
  void MaybeGiveTerminal(int pgid);
  void MaybeTakeTerminal();
  void MaybeReturnTerminal();
  int shell_pid;
  int shell_pgid;
  int shell_tty_fd;
  int original_tty_pgid;

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassScanned(0, sizeof(JobControl));
  }

  DISALLOW_COPY_AND_ASSIGN(JobControl)
};

class JobList {
 public:
  JobList();
  int AddJob(process::Job* job);
  void RemoveJob(int job_id);
  void AddChildProcess(int pid, process::Process* proc);
  void RemoveChildProcess(int pid);
  process::Process* ProcessFromPid(int pid);
  Tuple2<process::Job*, process::Job*> GetCurrentAndPreviousJobs();
  process::Job* GetJobWithSpec(BigStr* job_spec);
  void DisplayJobs(int style);
  void DebugPrint();
  void ListRecent();
  int NumRunning();
  Dict<int, process::Job*>* jobs;
  Dict<int, process::Process*>* child_procs;
  List<process::Pipeline*>* debug_pipelines;
  int job_id;

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassScanned(3, sizeof(JobList));
  }

  DISALLOW_COPY_AND_ASSIGN(JobList)
};

extern int W1_OK;
extern int W1_ECHILD;
extern int W1_AGAIN;
class Waiter {
 public:
  Waiter(process::JobList* job_list, optview::Exec* exec_opts, pyos::SignalSafe* signal_safe, dev::Tracer* tracer);
  int WaitForOne(int waitpid_options = 0);
  void PollNotifications();
  process::JobList* job_list;
  optview::Exec* exec_opts;
  pyos::SignalSafe* signal_safe;
  dev::Tracer* tracer;
  int last_status;

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassScanned(4, sizeof(Waiter));
  }

  DISALLOW_COPY_AND_ASSIGN(Waiter)
};


}  // declare namespace process

namespace state {  // declare

using id_kind_asdl::Id;
using runtime_asdl::scope_e;
using syntax_asdl::loc;
using value_asdl::sh_lvalue;
extern BigStr* _READLINE_DELIMS;
extern int SetReadOnly;
extern int ClearReadOnly;
extern int SetExport;
extern int ClearExport;
extern int SetNameref;
extern int ClearNameref;
BigStr* LookupExecutable(BigStr* name, List<BigStr*>* path_dirs, bool exec_required = true);
class SearchPath {
 public:
  SearchPath(state::Mem* mem);
  List<BigStr*>* _GetPath();
  BigStr* LookupOne(BigStr* name, bool exec_required = true);
  List<BigStr*>* LookupReflect(BigStr* name, bool do_all);
  BigStr* CachedLookup(BigStr* name);
  void MaybeRemoveEntry(BigStr* name);
  void ClearCache();
  List<BigStr*>* CachedCommands();
  state::Mem* mem;
  Dict<BigStr*, BigStr*>* cache;

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassScanned(2, sizeof(SearchPath));
  }

  DISALLOW_COPY_AND_ASSIGN(SearchPath)
};

class ctx_Source {
 public:
  ctx_Source(state::Mem* mem, BigStr* source_name, List<BigStr*>* argv);
  ~ctx_Source();
  state::Mem* mem;
  List<BigStr*>* argv;
  bool to_restore;

  DISALLOW_COPY_AND_ASSIGN(ctx_Source)
};

class ctx_DebugTrap {
 public:
  ctx_DebugTrap(state::Mem* mem);
  ~ctx_DebugTrap();
  state::Mem* mem;

  DISALLOW_COPY_AND_ASSIGN(ctx_DebugTrap)
};

class ctx_ErrTrap {
 public:
  ctx_ErrTrap(state::Mem* mem);
  ~ctx_ErrTrap();
  state::Mem* mem;

  DISALLOW_COPY_AND_ASSIGN(ctx_ErrTrap)
};

class ctx_Option {
 public:
  ctx_Option(state::MutableOpts* mutable_opts, List<int>* opt_nums, bool b);
  ~ctx_Option();
  state::MutableOpts* mutable_opts;
  List<int>* opt_nums;

  DISALLOW_COPY_AND_ASSIGN(ctx_Option)
};

class ctx_AssignBuiltin {
 public:
  ctx_AssignBuiltin(state::MutableOpts* mutable_opts);
  ~ctx_AssignBuiltin();
  state::MutableOpts* mutable_opts;
  bool strict;

  DISALLOW_COPY_AND_ASSIGN(ctx_AssignBuiltin)
};

class ctx_YshExpr {
 public:
  ctx_YshExpr(state::MutableOpts* mutable_opts);
  ~ctx_YshExpr();
  state::MutableOpts* mutable_opts;

  DISALLOW_COPY_AND_ASSIGN(ctx_YshExpr)
};

class ctx_ErrExit {
 public:
  ctx_ErrExit(state::MutableOpts* mutable_opts, bool b, syntax_asdl::Token* disabled_tok);
  ~ctx_ErrExit();
  state::MutableOpts* mutable_opts;
  bool strict;

  DISALLOW_COPY_AND_ASSIGN(ctx_ErrExit)
};

class OptHook {
 public:
  OptHook();
  virtual bool OnChange(List<bool>* opt0_array, BigStr* opt_name, bool b);
  
  static constexpr uint32_t field_mask() {
    return kZeroMask;
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(OptHook));
  }

  DISALLOW_COPY_AND_ASSIGN(OptHook)
};

List<bool>* InitOpts();
Tuple3<optview::Parse*, optview::Exec*, state::MutableOpts*> MakeOpts(state::Mem* mem, state::OptHook* opt_hook);
void _SetGroup(List<bool>* opt0_array, List<int>* opt_nums, bool b);
optview::Parse* MakeOilOpts();
int _AnyOptionNum(BigStr* opt_name);
int _SetOptionNum(BigStr* opt_name);
class MutableOpts {
 public:
  MutableOpts(state::Mem* mem, List<bool>* opt0_array, List<List<bool>*>* opt_stacks, state::OptHook* opt_hook);
  void Init();
  void _InitOptionsFromEnv(BigStr* shellopts);
  void Push(int opt_num, bool b);
  bool Pop(int opt_num);
  void PushDynamicScope(bool b);
  void PopDynamicScope();
  bool Get(int opt_num);
  void _Set(int opt_num, bool b);
  void set_interactive();
  void set_redefine_proc_func();
  void set_redefine_module();
  void set_emacs();
  void set_xtrace(bool b);
  void _SetArrayByNum(int opt_num, bool b);
  void SetDeferredErrExit(bool b);
  void DisableErrExit();
  syntax_asdl::Token* ErrExitDisabledToken();
  bool ErrExitIsDisabled();
  void _SetOldOption(BigStr* opt_name, bool b);
  void SetOldOption(BigStr* opt_name, bool b);
  void SetAnyOption(BigStr* opt_name, bool b);
  void ShowOptions(List<BigStr*>* opt_names);
  void ShowShoptOptions(List<BigStr*>* opt_names);
  state::Mem* mem;
  List<bool>* opt0_array;
  List<List<bool>*>* opt_stacks;
  List<syntax_asdl::Token*>* errexit_disabled_tok;
  state::OptHook* opt_hook;

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassScanned(5, sizeof(MutableOpts));
  }

  DISALLOW_COPY_AND_ASSIGN(MutableOpts)
};

class _ArgFrame {
 public:
  _ArgFrame(List<BigStr*>* argv);
  Dict<BigStr*, value_asdl::value_t*>* Dump();
  value_asdl::value_t* GetArgNum(int arg_num);
  List<BigStr*>* GetArgv();
  int GetNumArgs();
  void SetArgv(List<BigStr*>* argv);
  List<BigStr*>* argv;
  int num_shifted;

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassScanned(1, sizeof(_ArgFrame));
  }

  DISALLOW_COPY_AND_ASSIGN(_ArgFrame)
};

Dict<BigStr*, value_asdl::value_t*>* _DumpVarFrame(Dict<BigStr*, runtime_asdl::Cell*>* frame);
BigStr* _GetWorkingDir();
BigStr* _LineNumber(syntax_asdl::Token* tok);
void _AddCallToken(Dict<BigStr*, value_asdl::value_t*>* d, syntax_asdl::Token* token);
void _InitDefaults(state::Mem* mem);
void _InitVarsFromEnv(state::Mem* mem, Dict<BigStr*, BigStr*>* environ);
void InitMem(state::Mem* mem, Dict<BigStr*, BigStr*>* environ, BigStr* version_str);
void InitInteractive(state::Mem* mem);
class ctx_FuncCall {
 public:
  ctx_FuncCall(state::Mem* mem, value::Func* func);
  ~ctx_FuncCall();
  state::Mem* mem;

  DISALLOW_COPY_AND_ASSIGN(ctx_FuncCall)
};

class ctx_ProcCall {
 public:
  ctx_ProcCall(state::Mem* mem, state::MutableOpts* mutable_opts, value::Proc* proc, List<BigStr*>* argv);
  ~ctx_ProcCall();
  state::Mem* mem;
  state::MutableOpts* mutable_opts;
  bool sh_compat;

  DISALLOW_COPY_AND_ASSIGN(ctx_ProcCall)
};

class ctx_Temp {
 public:
  ctx_Temp(state::Mem* mem);
  ~ctx_Temp();
  state::Mem* mem;

  DISALLOW_COPY_AND_ASSIGN(ctx_Temp)
};

class ctx_Registers {
 public:
  ctx_Registers(state::Mem* mem);
  ~ctx_Registers();
  state::Mem* mem;

  DISALLOW_COPY_AND_ASSIGN(ctx_Registers)
};

class ctx_ThisDir {
 public:
  ctx_ThisDir(state::Mem* mem, BigStr* filename);
  ~ctx_ThisDir();
  state::Mem* mem;
  bool do_pop;

  DISALLOW_COPY_AND_ASSIGN(ctx_ThisDir)
};

runtime_asdl::Cell* _MakeArgvCell(List<BigStr*>* argv);
class Mem {
 public:
  Mem(BigStr* dollar0, List<BigStr*>* argv, alloc::Arena* arena, List<syntax_asdl::debug_frame_t*>* debug_stack);
  void SetPwd(BigStr* pwd);
  bool ParsingChangesAllowed();
  Tuple3<List<value_asdl::value_t*>*, List<value_asdl::value_t*>*, List<value_asdl::value_t*>*> Dump();
  void SetLastArgument(BigStr* s);
  void SetTokenForLine(syntax_asdl::Token* tok);
  void SetLocationForExpr(syntax_asdl::loc_t* blame_loc);
  syntax_asdl::loc_t* GetFallbackLocation();
  int LastStatus();
  int TryStatus();
  value::Dict* TryError();
  List<int>* PipeStatus();
  void SetLastStatus(int x);
  void SetTryStatus(int x);
  void SetTryError(value::Dict* x);
  void SetPipeStatus(List<int>* x);
  void SetSimplePipeStatus(int status);
  void SetProcessSubStatus(List<int>* x);
  void PushCall(BigStr* func_name, syntax_asdl::Token* def_tok);
  void PopCall();
  bool ShouldRunDebugTrap();
  bool InsideFunction();
  void PushSource(BigStr* source_name, List<BigStr*>* argv);
  void PopSource(List<BigStr*>* argv);
  void PushTemp();
  void PopTemp();
  Dict<BigStr*, runtime_asdl::Cell*>* TopNamespace();
  int Shift(int n);
  value::Str* GetArg0();
  value_asdl::value_t* GetArgNum(int arg_num);
  List<BigStr*>* GetArgv();
  void SetArgv(List<BigStr*>* argv);
  value_asdl::value_t* GetSpecialVar(int op_id);
  Tuple2<runtime_asdl::Cell*, Dict<BigStr*, runtime_asdl::Cell*>*> _ResolveNameOnly(BigStr* name, runtime_asdl::scope_t which_scopes);
  Tuple3<runtime_asdl::Cell*, Dict<BigStr*, runtime_asdl::Cell*>*, BigStr*> _ResolveNameOrRef(BigStr* name, runtime_asdl::scope_t which_scopes, List<BigStr*>* ref_trail = nullptr);
  bool IsBashAssoc(BigStr* name);
  void SetPlace(value::Place* place, value_asdl::value_t* val, syntax_asdl::loc_t* blame_loc);
  void SetLocalName(value_asdl::LeftName* lval, value_asdl::value_t* val);
  void SetNamed(value_asdl::LeftName* lval, value_asdl::value_t* val, runtime_asdl::scope_t which_scopes, int flags = 0);
  void SetValue(value_asdl::sh_lvalue_t* lval, value_asdl::value_t* val, runtime_asdl::scope_t which_scopes, int flags = 0);
  void _BindNewArrayWithEntry(Dict<BigStr*, runtime_asdl::Cell*>* name_map, sh_lvalue::Indexed* lval, value::Str* val, int flags);
  void InternalSetGlobal(BigStr* name, value_asdl::value_t* new_val);
  value_asdl::value_t* GetValue(BigStr* name, runtime_asdl::scope_t which_scopes = scope_e::Shopt);
  runtime_asdl::Cell* GetCell(BigStr* name, runtime_asdl::scope_t which_scopes = scope_e::Shopt);
  bool Unset(value_asdl::sh_lvalue_t* lval, runtime_asdl::scope_t which_scopes);
  runtime_asdl::scope_t ScopesForReading();
  runtime_asdl::scope_t ScopesForWriting();
  bool ClearFlag(BigStr* name, int flag);
  Dict<BigStr*, BigStr*>* GetExported();
  List<BigStr*>* VarNames();
  List<BigStr*>* VarNamesStartingWith(BigStr* prefix);
  Dict<BigStr*, BigStr*>* GetAllVars();
  Dict<BigStr*, runtime_asdl::Cell*>* GetAllCells(runtime_asdl::scope_t which_scopes);
  bool IsGlobalScope();
  void SetRegexMatch(value_asdl::regex_match_t* match);
  value_asdl::regex_match_t* GetRegexMatch();
  void PushContextStack(Dict<BigStr*, value_asdl::value_t*>* context);
  Dict<BigStr*, value_asdl::value_t*>* GetContext();
  Dict<BigStr*, value_asdl::value_t*>* PopContextStack();
  optview::Exec* exec_opts;
  sh_expr_eval::UnsafeArith* unsafe_arith;
  BigStr* dollar0;
  List<state::_ArgFrame*>* argv_stack;
  List<Dict<BigStr*, runtime_asdl::Cell*>*>* var_stack;
  List<syntax_asdl::debug_frame_t*>* debug_stack;
  BigStr* pwd;
  syntax_asdl::Token* token_for_line;
  syntax_asdl::loc_t* loc_for_expr;
  BigStr* last_arg;
  value::Str* line_num;
  List<int>* last_status;
  List<int>* try_status;
  List<value::Dict*>* try_error;
  List<List<int>*>* pipe_status;
  List<List<int>*>* process_sub_status;
  List<BigStr*>* this_dir;
  List<value_asdl::regex_match_t*>* regex_match;
  List<Dict<BigStr*, value_asdl::value_t*>*>* ctx_stack;
  double seconds_start;
  int root_pid;
  int last_bg_pid;
  bool running_debug_trap;
  bool running_err_trap;
  bool is_main;

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassScanned(19, sizeof(Mem));
  }

  DISALLOW_COPY_AND_ASSIGN(Mem)
};

void OshLanguageSetValue(state::Mem* mem, value_asdl::sh_lvalue_t* lval, value_asdl::value_t* val, int flags = 0);
void BuiltinSetValue(state::Mem* mem, value_asdl::sh_lvalue_t* lval, value_asdl::value_t* val);
void BuiltinSetString(state::Mem* mem, BigStr* name, BigStr* s);
void BuiltinSetArray(state::Mem* mem, BigStr* name, List<BigStr*>* a);
void SetGlobalString(state::Mem* mem, BigStr* name, BigStr* s);
void SetGlobalArray(state::Mem* mem, BigStr* name, List<BigStr*>* a);
void ExportGlobalString(state::Mem* mem, BigStr* name, BigStr* s);
value_asdl::value_t* DynamicGetVar(state::Mem* mem, BigStr* name, runtime_asdl::scope_t which_scopes);
BigStr* GetString(state::Mem* mem, BigStr* name);
BigStr* MaybeString(state::Mem* mem, BigStr* name);
int GetInteger(state::Mem* mem, BigStr* name);

}  // declare namespace state

namespace ui {  // declare

using id_kind_asdl::Id;
using syntax_asdl::loc;
BigStr* ValType(value_asdl::value_t* val);
BigStr* CommandType(syntax_asdl::command_t* cmd);
BigStr* PrettyId(int id_);
BigStr* PrettyToken(syntax_asdl::Token* tok);
BigStr* PrettyDir(BigStr* dir_name, BigStr* home_dir);
void _PrintCodeExcerpt(BigStr* line, int col, int length, mylib::Writer* f);
void _PrintTokenTooLong(loc::TokenTooLong* loc_tok, mylib::Writer* f);
BigStr* GetLineSourceString(syntax_asdl::SourceLine* line, bool quote_filename = false);
void _PrintWithLocation(BigStr* prefix, BigStr* msg, syntax_asdl::loc_t* blame_loc, bool show_code);
class ctx_Location {
 public:
  ctx_Location(ui::ErrorFormatter* errfmt, syntax_asdl::loc_t* location);
  ~ctx_Location();
  ui::ErrorFormatter* errfmt;

  DISALLOW_COPY_AND_ASSIGN(ctx_Location)
};

class ErrorFormatter {
 public:
  ErrorFormatter();
  void OneLineErrExit();
  syntax_asdl::loc_t* _FallbackLocation(syntax_asdl::loc_t* blame_loc);
  void PrefixPrint(BigStr* msg, BigStr* prefix, syntax_asdl::loc_t* blame_loc);
  void Print_(BigStr* msg, syntax_asdl::loc_t* blame_loc = nullptr);
  void PrintMessage(BigStr* msg, syntax_asdl::loc_t* blame_loc = nullptr);
  void StderrLine(BigStr* msg);
  void PrettyPrintError(error::_ErrorWithLocation* err, BigStr* prefix = str1109);
  void PrintErrExit(error::ErrExit* err, int pid);
  List<syntax_asdl::loc_t*>* loc_stack;
  bool one_line_errexit;

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassScanned(1, sizeof(ErrorFormatter));
  }

  DISALLOW_COPY_AND_ASSIGN(ErrorFormatter)
};

void PrintAst(syntax_asdl::command_t* node, arg_types::main* flag);
void PrettyPrintValue(value_asdl::value_t* val, mylib::Writer* f);

}  // declare namespace ui

namespace util {  // declare

List<BigStr*>* RegexGroupStrings(BigStr* s, List<int>* indices);
List<BigStr*>* RegexSearch(BigStr* pat, BigStr* s);
class UserExit {
 public:
  UserExit(int status);
  int status;

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassScanned(0, sizeof(UserExit));
  }

  DISALLOW_COPY_AND_ASSIGN(UserExit)
};

class HistoryError {
 public:
  HistoryError(BigStr* msg);
  BigStr* UserErrorString();
  BigStr* msg;

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassScanned(1, sizeof(HistoryError));
  }

  DISALLOW_COPY_AND_ASSIGN(HistoryError)
};

class _DebugFile {
 public:
  _DebugFile();
  virtual void write(BigStr* s);
  virtual void writeln(BigStr* s);
  virtual bool isatty();
  
  static constexpr uint32_t field_mask() {
    return kZeroMask;
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(_DebugFile));
  }

  DISALLOW_COPY_AND_ASSIGN(_DebugFile)
};

class NullDebugFile : public ::util::_DebugFile {
 public:
  NullDebugFile();
  
  static constexpr uint32_t field_mask() {
    return ::util::_DebugFile::field_mask();
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(NullDebugFile));
  }

  DISALLOW_COPY_AND_ASSIGN(NullDebugFile)
};

class DebugFile : public ::util::_DebugFile {
 public:
  DebugFile(mylib::Writer* f);
  virtual void write(BigStr* s);
  virtual void writeln(BigStr* s);
  virtual bool isatty();

  mylib::Writer* f;
  
  static constexpr uint32_t field_mask() {
    return ::util::_DebugFile::field_mask()
         | maskbit(offsetof(DebugFile, f));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(DebugFile));
  }

  DISALLOW_COPY_AND_ASSIGN(DebugFile)
};

void PrintTopicHeader(BigStr* topic_id, mylib::Writer* f);
bool PrintEmbeddedHelp(pyutil::_ResourceLoader* loader, BigStr* topic_id, mylib::Writer* f);
void _PrintVersionLine(pyutil::_ResourceLoader* loader, mylib::Writer* f);
void HelpFlag(pyutil::_ResourceLoader* loader, BigStr* topic_id, mylib::Writer* f);
void VersionFlag(pyutil::_ResourceLoader* loader, mylib::Writer* f);

}  // declare namespace util

namespace j8 {  // declare

using id_kind_asdl::Id;
BigStr* ValType(value_asdl::value_t* val);
int ValueId(value_asdl::value_t* val);
BigStr* ValueIdString(value_asdl::value_t* val);
BigStr* Utf8Encode(int code);
extern int SHOW_CYCLES;
extern int SHOW_NON_DATA;
extern int LOSSY_JSON;
void _Print(value_asdl::value_t* val, mylib::BufWriter* buf, int indent, int options = 0);
void PrintMessage(value_asdl::value_t* val, mylib::BufWriter* buf, int indent);
void PrintJsonMessage(value_asdl::value_t* val, mylib::BufWriter* buf, int indent);
void PrintLine(value_asdl::value_t* val, mylib::Writer* f);
void EncodeString(BigStr* s, mylib::BufWriter* buf, bool unquoted_ok = false);
BigStr* MaybeEncodeString(BigStr* s);
BigStr* MaybeEncodeJsonString(BigStr* s);
extern int UNSEEN;
extern int EXPLORING;
extern int FINISHED;
class InstancePrinter {
 public:
  InstancePrinter(mylib::BufWriter* buf, int indent, int options);
  void _ItemIndent(int level);
  void _BracketIndent(int level);
  void _MaybeNewline();
  void _MaybeSpace();
  void _PrintList(value::List* val, int level);
  void _PrintDict(value::Dict* val, int level);
  void Print(value_asdl::value_t* val, int level = 0);
  mylib::BufWriter* buf;
  Dict<int, int>* visited;
  int indent;
  int options;

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassScanned(2, sizeof(InstancePrinter));
  }

  DISALLOW_COPY_AND_ASSIGN(InstancePrinter)
};

class PrettyPrinter {
 public:
  PrettyPrinter(int max_col);
  void PrettyTree(value_asdl::value_t* val, format::ColorOutput* f);
  void Print(value_asdl::value_t* val, mylib::BufWriter* buf);
  Dict<int, int>* ref_count;
  int max_col;

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassScanned(1, sizeof(PrettyPrinter));
  }

  DISALLOW_COPY_AND_ASSIGN(PrettyPrinter)
};

class LexerDecoder {
 public:
  LexerDecoder(BigStr* s, bool is_j8, BigStr* lang_str);
  error::Decode* _Error(BigStr* msg, int end_pos);
  Tuple3<int, int, BigStr*> Next();
  Tuple3<int, int, BigStr*> NextForLines();
  Tuple3<int, int, BigStr*> _DecodeString(int left_id, int str_pos);
  BigStr* s;
  BigStr* lang_str;
  mylib::BufWriter* decoded;
  bool is_j8;
  int pos;
  int cur_line_num;

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassScanned(3, sizeof(LexerDecoder));
  }

  DISALLOW_COPY_AND_ASSIGN(LexerDecoder)
};

class _Parser {
 public:
  _Parser(BigStr* s, bool is_j8);
  void _Next();
  void _Eat(int tok_id);
  void _NextForLines();
  error::Decode* _ParseError(BigStr* msg);
  BigStr* decoded;
  int end_pos;
  bool is_j8;
  BigStr* lang_str;
  j8::LexerDecoder* lexer;
  BigStr* s;
  int start_pos;
  int tok_id;
  
  static constexpr uint32_t field_mask() {
    return maskbit(offsetof(_Parser, decoded))
         | maskbit(offsetof(_Parser, lang_str))
         | maskbit(offsetof(_Parser, lexer))
         | maskbit(offsetof(_Parser, s));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(_Parser));
  }

  DISALLOW_COPY_AND_ASSIGN(_Parser)
};

class Parser : public ::j8::_Parser {
 public:
  Parser(BigStr* s, bool is_j8);
  Tuple2<BigStr*, value_asdl::value_t*> _ParsePair();
  value_asdl::value_t* _ParseDict();
  value_asdl::value_t* _ParseList();
  value_asdl::value_t* _ParseValue();
  value_asdl::value_t* ParseValue();
  
  static constexpr uint32_t field_mask() {
    return ::j8::_Parser::field_mask();
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(Parser));
  }

  DISALLOW_COPY_AND_ASSIGN(Parser)
};

class Nil8Parser : public ::j8::_Parser {
 public:
  Nil8Parser(BigStr* s, bool is_j8);
  nil8_asdl::nvalue_t* _ParseRecord();
  nil8_asdl::nvalue_t* _ParseList8();
  nil8_asdl::nvalue_t* _ParseNil8();
  nil8_asdl::nvalue_t* ParseNil8();
  
  static constexpr uint32_t field_mask() {
    return ::j8::_Parser::field_mask();
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(Nil8Parser));
  }

  DISALLOW_COPY_AND_ASSIGN(Nil8Parser)
};

class J8LinesParser : public ::j8::_Parser {
 public:
  J8LinesParser(BigStr* s);
  void _Show(BigStr* s);
  void _ParseLine(List<BigStr*>* out);
  List<BigStr*>* Parse();
  
  static constexpr uint32_t field_mask() {
    return ::j8::_Parser::field_mask();
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(J8LinesParser));
  }

  DISALLOW_COPY_AND_ASSIGN(J8LinesParser)
};

List<BigStr*>* SplitJ8Lines(BigStr* s);

}  // declare namespace j8

namespace j8_lite {  // declare

BigStr* EncodeString(BigStr* s, bool unquoted_ok = false);
BigStr* MaybeShellEncode(BigStr* s);
BigStr* ShellEncode(BigStr* s);
BigStr* YshEncode(BigStr* s, bool unquoted_ok = false);

}  // declare namespace j8_lite

namespace pretty {  // declare

int TryUnicodeWidth(BigStr* s);
pretty_asdl::Measure* _EmptyMeasure();
pretty_asdl::Measure* _FlattenMeasure(pretty_asdl::Measure* measure);
pretty_asdl::Measure* _ConcatMeasure(pretty_asdl::Measure* m1, pretty_asdl::Measure* m2);
int _SuffixLen(pretty_asdl::Measure* measure);
pretty_asdl::MeasuredDoc* _Text(BigStr* string);
pretty_asdl::MeasuredDoc* _Break(BigStr* string);
pretty_asdl::MeasuredDoc* _Indent(int indent, pretty_asdl::MeasuredDoc* mdoc);
pretty_asdl::MeasuredDoc* _Concat(List<pretty_asdl::MeasuredDoc*>* mdocs);
pretty_asdl::MeasuredDoc* _Group(pretty_asdl::MeasuredDoc* mdoc);
pretty_asdl::MeasuredDoc* _IfFlat(pretty_asdl::MeasuredDoc* flat_mdoc, pretty_asdl::MeasuredDoc* nonflat_mdoc);
extern int _DEFAULT_MAX_WIDTH;
extern int _DEFAULT_INDENTATION;
extern bool _DEFAULT_USE_STYLES;
extern bool _DEFAULT_SHOW_TYPE_PREFIX;
extern int _DEFAULT_MAX_TABULAR_WIDTH;
class PrettyPrinter {
 public:
  PrettyPrinter();
  void SetMaxWidth(int max_width);
  void SetIndent(int indent);
  void SetUseStyles(bool use_styles);
  void SetShowTypePrefix(bool show_type_prefix);
  void SetMaxTabularWidth(int max_tabular_width);
  void PrintValue(value_asdl::value_t* val, mylib::BufWriter* buf);
  bool _Fits(int prefix_len, doc::Group* group, pretty_asdl::Measure* suffix_measure);
  void _PrintDoc(pretty_asdl::MeasuredDoc* document, mylib::BufWriter* buf);
  int max_width;
  int indent;
  bool use_styles;
  bool show_type_prefix;
  int max_tabular_width;

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassScanned(0, sizeof(PrettyPrinter));
  }

  DISALLOW_COPY_AND_ASSIGN(PrettyPrinter)
};

class _DocConstructor {
 public:
  _DocConstructor(int indent, bool use_styles, bool show_type_prefix, int max_tabular_width);
  pretty_asdl::MeasuredDoc* Value(value_asdl::value_t* val);
  pretty_asdl::MeasuredDoc* _Styled(BigStr* style, pretty_asdl::MeasuredDoc* mdoc);
  pretty_asdl::MeasuredDoc* _Surrounded(BigStr* open, pretty_asdl::MeasuredDoc* mdoc, BigStr* close);
  pretty_asdl::MeasuredDoc* _SurroundedAndPrefixed(BigStr* open, pretty_asdl::MeasuredDoc* prefix, BigStr* sep, pretty_asdl::MeasuredDoc* mdoc, BigStr* close);
  pretty_asdl::MeasuredDoc* _Join(List<pretty_asdl::MeasuredDoc*>* items, BigStr* sep, BigStr* space);
  pretty_asdl::MeasuredDoc* _Tabular(List<pretty_asdl::MeasuredDoc*>* items, BigStr* sep);
  pretty_asdl::MeasuredDoc* _DictKey(BigStr* s);
  pretty_asdl::MeasuredDoc* _StringLiteral(BigStr* s);
  pretty_asdl::MeasuredDoc* _BashStringLiteral(BigStr* s);
  pretty_asdl::MeasuredDoc* _YshList(value::List* vlist);
  pretty_asdl::MeasuredDoc* _YshDict(value::Dict* vdict);
  pretty_asdl::MeasuredDoc* _BashArray(value::BashArray* varray);
  pretty_asdl::MeasuredDoc* _BashAssoc(value::BashAssoc* vassoc);
  pretty_asdl::MeasuredDoc* _Value(value_asdl::value_t* val);
  Dict<int, bool>* visiting;
  BigStr* number_style;
  BigStr* null_style;
  BigStr* bool_style;
  BigStr* string_style;
  BigStr* cycle_style;
  BigStr* type_style;
  int indent;
  bool use_styles;
  bool show_type_prefix;
  int max_tabular_width;

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassScanned(7, sizeof(_DocConstructor));
  }

  DISALLOW_COPY_AND_ASSIGN(_DocConstructor)
};


}  // declare namespace pretty

namespace args {  // declare

using syntax_asdl::loc;
extern int String;
extern int Int;
extern int Float;
extern int Bool;
class _Attributes {
 public:
  _Attributes(Dict<BigStr*, value_asdl::value_t*>* defaults);
  void SetTrue(BigStr* name);
  void Set(BigStr* name, value_asdl::value_t* val);
  Dict<BigStr*, value_asdl::value_t*>* attrs;
  List<Tuple2<BigStr*, bool>*>* opt_changes;
  List<Tuple2<BigStr*, bool>*>* shopt_changes;
  List<BigStr*>* actions;
  bool show_options;
  bool saw_double_dash;

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassScanned(4, sizeof(_Attributes));
  }

  DISALLOW_COPY_AND_ASSIGN(_Attributes)
};

class Reader {
 public:
  Reader(List<BigStr*>* argv, List<syntax_asdl::CompoundWord*>* locs = nullptr);
  void Next();
  BigStr* Peek();
  Tuple2<BigStr*, syntax_asdl::loc_t*> Peek2();
  BigStr* ReadRequired(BigStr* error_msg);
  Tuple2<BigStr*, syntax_asdl::loc_t*> ReadRequired2(BigStr* error_msg);
  List<BigStr*>* Rest();
  Tuple2<List<BigStr*>*, List<syntax_asdl::CompoundWord*>*> Rest2();
  bool AtEnd();
  void Done();
  syntax_asdl::loc_t* _FirstLocation();
  syntax_asdl::loc_t* Location();
  List<BigStr*>* argv;
  List<syntax_asdl::CompoundWord*>* locs;
  int n;
  int i;

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassScanned(2, sizeof(Reader));
  }

  DISALLOW_COPY_AND_ASSIGN(Reader)
};

class _Action {
 public:
  _Action();
  virtual bool OnMatch(BigStr* attached_arg, args::Reader* arg_r, args::_Attributes* out);
  
  static constexpr uint32_t field_mask() {
    return kZeroMask;
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(_Action));
  }

  DISALLOW_COPY_AND_ASSIGN(_Action)
};

class _ArgAction : public ::args::_Action {
 public:
  _ArgAction(BigStr* name, bool quit_parsing_flags, List<BigStr*>* valid = nullptr);
  virtual value_asdl::value_t* _Value(BigStr* arg, syntax_asdl::loc_t* location);
  virtual bool OnMatch(BigStr* attached_arg, args::Reader* arg_r, args::_Attributes* out);

  BigStr* name;
  bool quit_parsing_flags;
  List<BigStr*>* valid;
  
  static constexpr uint32_t field_mask() {
    return ::args::_Action::field_mask()
         | maskbit(offsetof(_ArgAction, name))
         | maskbit(offsetof(_ArgAction, valid));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(_ArgAction));
  }

  DISALLOW_COPY_AND_ASSIGN(_ArgAction)
};

class SetToInt : public ::args::_ArgAction {
 public:
  SetToInt(BigStr* name);
  virtual value_asdl::value_t* _Value(BigStr* arg, syntax_asdl::loc_t* location);
  
  static constexpr uint32_t field_mask() {
    return ::args::_ArgAction::field_mask();
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(SetToInt));
  }

  DISALLOW_COPY_AND_ASSIGN(SetToInt)
};

class SetToFloat : public ::args::_ArgAction {
 public:
  SetToFloat(BigStr* name);
  virtual value_asdl::value_t* _Value(BigStr* arg, syntax_asdl::loc_t* location);
  
  static constexpr uint32_t field_mask() {
    return ::args::_ArgAction::field_mask();
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(SetToFloat));
  }

  DISALLOW_COPY_AND_ASSIGN(SetToFloat)
};

class SetToString : public ::args::_ArgAction {
 public:
  SetToString(BigStr* name, bool quit_parsing_flags, List<BigStr*>* valid = nullptr);
  virtual value_asdl::value_t* _Value(BigStr* arg, syntax_asdl::loc_t* location);
  
  static constexpr uint32_t field_mask() {
    return ::args::_ArgAction::field_mask();
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(SetToString));
  }

  DISALLOW_COPY_AND_ASSIGN(SetToString)
};

class SetAttachedBool : public ::args::_Action {
 public:
  SetAttachedBool(BigStr* name);
  virtual bool OnMatch(BigStr* attached_arg, args::Reader* arg_r, args::_Attributes* out);

  BigStr* name;
  
  static constexpr uint32_t field_mask() {
    return ::args::_Action::field_mask()
         | maskbit(offsetof(SetAttachedBool, name));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(SetAttachedBool));
  }

  DISALLOW_COPY_AND_ASSIGN(SetAttachedBool)
};

class SetToTrue : public ::args::_Action {
 public:
  SetToTrue(BigStr* name);
  virtual bool OnMatch(BigStr* attached_arg, args::Reader* arg_r, args::_Attributes* out);

  BigStr* name;
  
  static constexpr uint32_t field_mask() {
    return ::args::_Action::field_mask()
         | maskbit(offsetof(SetToTrue, name));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(SetToTrue));
  }

  DISALLOW_COPY_AND_ASSIGN(SetToTrue)
};

class SetOption : public ::args::_Action {
 public:
  SetOption(BigStr* name);
  virtual bool OnMatch(BigStr* attached_arg, args::Reader* arg_r, args::_Attributes* out);

  BigStr* name;
  
  static constexpr uint32_t field_mask() {
    return ::args::_Action::field_mask()
         | maskbit(offsetof(SetOption, name));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(SetOption));
  }

  DISALLOW_COPY_AND_ASSIGN(SetOption)
};

class SetNamedOption : public ::args::_Action {
 public:
  SetNamedOption(bool shopt = false);
  void ArgName(BigStr* name);
  virtual bool OnMatch(BigStr* attached_arg, args::Reader* arg_r, args::_Attributes* out);

  List<BigStr*>* names;
  bool shopt;
  
  static constexpr uint32_t field_mask() {
    return ::args::_Action::field_mask()
         | maskbit(offsetof(SetNamedOption, names));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(SetNamedOption));
  }

  DISALLOW_COPY_AND_ASSIGN(SetNamedOption)
};

class SetAction : public ::args::_Action {
 public:
  SetAction(BigStr* name);
  virtual bool OnMatch(BigStr* attached_arg, args::Reader* arg_r, args::_Attributes* out);

  BigStr* name;
  
  static constexpr uint32_t field_mask() {
    return ::args::_Action::field_mask()
         | maskbit(offsetof(SetAction, name));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(SetAction));
  }

  DISALLOW_COPY_AND_ASSIGN(SetAction)
};

class SetNamedAction : public ::args::_Action {
 public:
  SetNamedAction();
  void ArgName(BigStr* name);
  virtual bool OnMatch(BigStr* attached_arg, args::Reader* arg_r, args::_Attributes* out);

  List<BigStr*>* names;
  
  static constexpr uint32_t field_mask() {
    return ::args::_Action::field_mask()
         | maskbit(offsetof(SetNamedAction, names));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(SetNamedAction));
  }

  DISALLOW_COPY_AND_ASSIGN(SetNamedAction)
};

args::_Attributes* Parse(flag_spec::_FlagSpec* spec, args::Reader* arg_r);
args::_Attributes* ParseLikeEcho(flag_spec::_FlagSpec* spec, args::Reader* arg_r);
args::_Attributes* ParseMore(flag_spec::_FlagSpecAndMore* spec, args::Reader* arg_r);

}  // declare namespace args

namespace flag_util {  // declare

using runtime_asdl::cmd_value;
void _DoesNotAccept(syntax_asdl::ArgList* arg_list);
Tuple2<args::_Attributes*, args::Reader*> ParseCmdVal(BigStr* spec_name, cmd_value::Argv* cmd_val, bool accept_typed_args = false);
Tuple2<args::_Attributes*, args::Reader*> ParseLikeEcho(BigStr* spec_name, cmd_value::Argv* cmd_val);
args::_Attributes* Parse(BigStr* spec_name, args::Reader* arg_r);
args::_Attributes* ParseMore(BigStr* spec_name, args::Reader* arg_r);

}  // declare namespace flag_util

namespace lexer {  // declare

using types_asdl::lex_mode_e;
using id_kind_asdl::Id;
bool IsPlusEquals(syntax_asdl::Token* tok);
bool TokenContains(syntax_asdl::Token* tok, BigStr* substr);
bool TokenEquals(syntax_asdl::Token* tok, BigStr* s);
bool TokenStartsWith(syntax_asdl::Token* tok, BigStr* s);
bool TokenEndsWith(syntax_asdl::Token* tok, BigStr* s);
BigStr* TokenVal(syntax_asdl::Token* tok);
BigStr* TokenSliceLeft(syntax_asdl::Token* tok, int left_index);
BigStr* TokenSliceRight(syntax_asdl::Token* tok, int right_index);
BigStr* TokenSlice(syntax_asdl::Token* tok, int left, int right);
BigStr* LazyStr(syntax_asdl::Token* tok);
syntax_asdl::Token* DummyToken(int id_, BigStr* val);
class LineLexer {
 public:
  LineLexer(alloc::Arena* arena);
  void Reset(syntax_asdl::SourceLine* src_line, int line_pos);
  bool MaybeUnreadOne();
  syntax_asdl::Token* GetEofToken(int id_);
  int LookAheadOne(types_asdl::lex_mode_t lex_mode);
  void AssertAtEndOfLine();
  int LookPastSpace(types_asdl::lex_mode_t lex_mode);
  bool LookAheadFuncParens(int unread);
  BigStr* ByteLookAhead();
  int ByteLookBack();
  syntax_asdl::Token* Read(types_asdl::lex_mode_t lex_mode);
  alloc::Arena* arena;
  syntax_asdl::Token* eol_tok;
  syntax_asdl::SourceLine* src_line;
  bool replace_last_token;
  int line_pos;

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassScanned(3, sizeof(LineLexer));
  }

  DISALLOW_COPY_AND_ASSIGN(LineLexer)
};

class Lexer {
 public:
  Lexer(lexer::LineLexer* line_lexer, reader::_Reader* line_reader);
  void ResetInputObjects();
  bool MaybeUnreadOne();
  int LookAheadOne(types_asdl::lex_mode_t lex_mode);
  int LookPastSpace(types_asdl::lex_mode_t lex_mode);
  bool LookAheadFuncParens(int unread);
  BigStr* ByteLookAhead();
  int ByteLookBack();
  void EmitCompDummy();
  void PushHint(int old_id, int new_id);
  void MoveToNextLine();
  syntax_asdl::Token* _Read(types_asdl::lex_mode_t lex_mode);
  syntax_asdl::Token* Read(types_asdl::lex_mode_t lex_mode);
  lexer::LineLexer* line_lexer;
  reader::_Reader* line_reader;
  List<Tuple2<int, int>*>* translation_stack;
  int line_id;
  bool emit_comp_dummy;

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassScanned(3, sizeof(Lexer));
  }

  DISALLOW_COPY_AND_ASSIGN(Lexer)
};


}  // declare namespace lexer

namespace location {  // declare

using syntax_asdl::loc;
using syntax_asdl::word;
using syntax_asdl::word_part;
value_asdl::LeftName* LName(BigStr* name);
syntax_asdl::Token* TokenFor(syntax_asdl::loc_t* loc_);
syntax_asdl::Token* TokenForCommand(syntax_asdl::command_t* node);
syntax_asdl::Token* TokenForArith(syntax_asdl::arith_expr_t* node);
syntax_asdl::Token* LeftTokenForWordPart(syntax_asdl::word_part_t* part);
syntax_asdl::Token* _RightTokenForWordPart(syntax_asdl::word_part_t* part);
syntax_asdl::Token* LeftTokenForCompoundWord(syntax_asdl::CompoundWord* w);
syntax_asdl::Token* LeftTokenForWord(syntax_asdl::word_t* w);
syntax_asdl::Token* RightTokenForWord(syntax_asdl::word_t* w);
syntax_asdl::Token* TokenForLhsExpr(syntax_asdl::sh_lhs_t* node);
syntax_asdl::loc_t* TokenForExpr(syntax_asdl::expr_t* node);

}  // declare namespace location

namespace parse_lib {  // declare

using types_asdl::lex_mode_e;
class _BaseTrail {
 public:
  _BaseTrail();
  virtual void Clear();
  virtual void SetLatestWords(List<syntax_asdl::CompoundWord*>* words, List<syntax_asdl::Redir*>* redirects);
  virtual void AppendToken(syntax_asdl::Token* token);
  void BeginAliasExpansion();
  void EndAliasExpansion();
  bool _expanding_alias;
  List<syntax_asdl::CompoundWord*>* alias_words;
  List<syntax_asdl::Redir*>* redirects;
  List<syntax_asdl::Token*>* tokens;
  List<syntax_asdl::CompoundWord*>* words;
  
  static constexpr uint32_t field_mask() {
    return maskbit(offsetof(_BaseTrail, alias_words))
         | maskbit(offsetof(_BaseTrail, redirects))
         | maskbit(offsetof(_BaseTrail, tokens))
         | maskbit(offsetof(_BaseTrail, words));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(_BaseTrail));
  }

  DISALLOW_COPY_AND_ASSIGN(_BaseTrail)
};

class ctx_Alias {
 public:
  ctx_Alias(parse_lib::_BaseTrail* trail);
  ~ctx_Alias();
  parse_lib::_BaseTrail* trail;

  DISALLOW_COPY_AND_ASSIGN(ctx_Alias)
};

class Trail : public ::parse_lib::_BaseTrail {
 public:
  Trail();
  virtual void Clear();
  virtual void SetLatestWords(List<syntax_asdl::CompoundWord*>* words, List<syntax_asdl::Redir*>* redirects);
  virtual void AppendToken(syntax_asdl::Token* token);
  
  static constexpr uint32_t field_mask() {
    return ::parse_lib::_BaseTrail::field_mask();
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(Trail));
  }

  DISALLOW_COPY_AND_ASSIGN(Trail)
};

class ParseContext {
 public:
  ParseContext(alloc::Arena* arena, optview::Parse* parse_opts, Dict<BigStr*, BigStr*>* aliases, grammar::Grammar* ysh_grammar, bool do_lossless = false);
  void Init_Trail(parse_lib::_BaseTrail* trail);
  lexer::Lexer* MakeLexer(reader::_Reader* line_reader);
  cmd_parse::CommandParser* MakeOshParser(reader::_Reader* line_reader, bool emit_comp_dummy = false);
  cmd_parse::CommandParser* MakeConfigParser(reader::_Reader* line_reader);
  word_parse::WordParser* MakeWordParserForHereDoc(reader::_Reader* line_reader);
  word_parse::WordParser* MakeWordParser(lexer::Lexer* lx, reader::_Reader* line_reader);
  tdop::TdopParser* MakeArithParser(BigStr* code_str);
  cmd_parse::CommandParser* MakeParserForCommandSub(reader::_Reader* line_reader, lexer::Lexer* lexer, int eof_id);
  word_parse::WordParser* MakeWordParserForPlugin(BigStr* code_str);
  expr_parse::ExprParser* _YshParser();
  Tuple2<command::VarDecl*, syntax_asdl::Token*> ParseVarDecl(syntax_asdl::Token* kw_token, lexer::Lexer* lexer);
  Tuple2<command::Mutation*, syntax_asdl::Token*> ParseMutation(syntax_asdl::Token* kw_token, lexer::Lexer* lexer);
  void ParseProcCallArgs(lexer::Lexer* lx, syntax_asdl::ArgList* out, int start_symbol);
  Tuple2<syntax_asdl::expr_t*, syntax_asdl::Token*> ParseYshExpr(lexer::Lexer* lx, int start_symbol);
  Tuple3<syntax_asdl::pat_t*, syntax_asdl::Token*, syntax_asdl::Token*> ParseYshCasePattern(lexer::Lexer* lexer);
  syntax_asdl::Token* ParseProc(lexer::Lexer* lexer, syntax_asdl::Proc* out);
  syntax_asdl::Token* ParseFunc(lexer::Lexer* lexer, syntax_asdl::Func* out);
  alloc::Arena* arena;
  optview::Parse* parse_opts;
  Dict<BigStr*, BigStr*>* aliases;
  grammar::Grammar* ysh_grammar;
  expr_to_ast::Transformer* tr;
  parse_lib::_BaseTrail* trail;
  bool do_lossless;

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassScanned(6, sizeof(ParseContext));
  }

  DISALLOW_COPY_AND_ASSIGN(ParseContext)
};


}  // declare namespace parse_lib

namespace reader {  // declare

using id_kind_asdl::Id;
extern BigStr* _PS2;
class _Reader {
 public:
  _Reader(alloc::Arena* arena);
  void SetLineOffset(int n);
  virtual BigStr* _GetLine();
  virtual Tuple2<syntax_asdl::SourceLine*, int> GetLine();
  virtual void Reset();
  virtual bool LastLineHint();
  alloc::Arena* arena;
  int line_num;
  
  static constexpr uint32_t field_mask() {
    return maskbit(offsetof(_Reader, arena));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(_Reader));
  }

  DISALLOW_COPY_AND_ASSIGN(_Reader)
};

class DisallowedLineReader : public ::reader::_Reader {
 public:
  DisallowedLineReader(alloc::Arena* arena, syntax_asdl::Token* blame_token);
  virtual BigStr* _GetLine();

  syntax_asdl::Token* blame_token;
  
  static constexpr uint32_t field_mask() {
    return ::reader::_Reader::field_mask()
         | maskbit(offsetof(DisallowedLineReader, blame_token));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(DisallowedLineReader));
  }

  DISALLOW_COPY_AND_ASSIGN(DisallowedLineReader)
};

class FileLineReader : public ::reader::_Reader {
 public:
  FileLineReader(mylib::LineReader* f, alloc::Arena* arena);
  virtual BigStr* _GetLine();
  virtual bool LastLineHint();

  mylib::LineReader* f;
  bool last_line_hint;
  
  static constexpr uint32_t field_mask() {
    return ::reader::_Reader::field_mask()
         | maskbit(offsetof(FileLineReader, f));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(FileLineReader));
  }

  DISALLOW_COPY_AND_ASSIGN(FileLineReader)
};

reader::FileLineReader* StringLineReader(BigStr* s, alloc::Arena* arena);
class VirtualLineReader : public ::reader::_Reader {
 public:
  VirtualLineReader(alloc::Arena* arena, List<Tuple2<syntax_asdl::SourceLine*, int>*>* lines, bool do_lossless);
  virtual Tuple2<syntax_asdl::SourceLine*, int> GetLine();

  bool do_lossless;
  List<Tuple2<syntax_asdl::SourceLine*, int>*>* lines;
  int num_lines;
  int pos;
  
  static constexpr uint32_t field_mask() {
    return ::reader::_Reader::field_mask()
         | maskbit(offsetof(VirtualLineReader, lines));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(VirtualLineReader));
  }

  DISALLOW_COPY_AND_ASSIGN(VirtualLineReader)
};

BigStr* _PlainPromptInput(BigStr* prompt);
class InteractiveLineReader : public ::reader::_Reader {
 public:
  InteractiveLineReader(alloc::Arena* arena, prompt::Evaluator* prompt_ev, history::Evaluator* hist_ev, py_readline::Readline* line_input, comp_ui::PromptState* prompt_state);
  virtual void Reset();
  virtual BigStr* _GetLine();

  history::Evaluator* hist_ev;
  py_readline::Readline* line_input;
  BigStr* prev_line;
  prompt::Evaluator* prompt_ev;
  comp_ui::PromptState* prompt_state;
  BigStr* prompt_str;
  bool render_ps1;
  
  static constexpr uint32_t field_mask() {
    return ::reader::_Reader::field_mask()
         | maskbit(offsetof(InteractiveLineReader, hist_ev))
         | maskbit(offsetof(InteractiveLineReader, line_input))
         | maskbit(offsetof(InteractiveLineReader, prev_line))
         | maskbit(offsetof(InteractiveLineReader, prompt_ev))
         | maskbit(offsetof(InteractiveLineReader, prompt_state))
         | maskbit(offsetof(InteractiveLineReader, prompt_str));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(InteractiveLineReader));
  }

  DISALLOW_COPY_AND_ASSIGN(InteractiveLineReader)
};


}  // declare namespace reader

namespace typed_args {  // declare

using runtime_asdl::cmd_value;
using syntax_asdl::loc;
void DoesNotAccept(syntax_asdl::ArgList* arg_list);
syntax_asdl::command_t* OptionalBlock(cmd_value::Argv* cmd_val);
syntax_asdl::LiteralBlock* OptionalLiteralBlock(cmd_value::Argv* cmd_val);
typed_args::Reader* ReaderForProc(cmd_value::Argv* cmd_val);
class Reader {
 public:
  Reader(List<value_asdl::value_t*>* pos_args, Dict<BigStr*, value_asdl::value_t*>* named_args, value_asdl::value_t* block_arg, syntax_asdl::ArgList* arg_list, bool is_bound = false);
  void SetFallbackLocation(syntax_asdl::loc_t* blame_loc);
  syntax_asdl::loc_t* LeftParenToken();
  syntax_asdl::loc_t* LeastSpecificLocation();
  syntax_asdl::loc_t* BlamePos();
  value_asdl::value_t* PosValue();
  value_asdl::value_t* OptionalValue();
  BigStr* _ToStr(value_asdl::value_t* val);
  bool _ToBool(value_asdl::value_t* val);
  mops::BigInt _ToInt(value_asdl::value_t* val);
  double _ToFloat(value_asdl::value_t* val);
  List<BigStr*>* _ToBashArray(value_asdl::value_t* val);
  value::SparseArray* _ToSparseArray(value_asdl::value_t* val);
  List<value_asdl::value_t*>* _ToList(value_asdl::value_t* val);
  Dict<BigStr*, value_asdl::value_t*>* _ToDict(value_asdl::value_t* val);
  value::Place* _ToPlace(value_asdl::value_t* val);
  value_asdl::RegexMatch* _ToMatch(value_asdl::value_t* val);
  value::Eggex* _ToEggex(value_asdl::value_t* val);
  value::IO* _ToIO(value_asdl::value_t* val);
  syntax_asdl::expr_t* _ToExpr(value_asdl::value_t* val);
  syntax_asdl::command_t* _ToCommand(value_asdl::value_t* val);
  syntax_asdl::command_t* _ToBlock(value_asdl::value_t* val);
  syntax_asdl::LiteralBlock* _ToLiteralBlock(value_asdl::value_t* val);
  BigStr* PosStr();
  BigStr* OptionalStr(BigStr* default_ = nullptr);
  bool PosBool();
  mops::BigInt PosInt();
  mops::BigInt OptionalInt(int default_);
  double PosFloat();
  List<BigStr*>* PosBashArray();
  value::SparseArray* PosSparseArray();
  List<value_asdl::value_t*>* PosList();
  Dict<BigStr*, value_asdl::value_t*>* PosDict();
  value::Place* PosPlace();
  value::Eggex* PosEggex();
  value_asdl::RegexMatch* PosMatch();
  value::IO* PosIO();
  syntax_asdl::command_t* PosCommand();
  syntax_asdl::expr_t* PosExpr();
  syntax_asdl::command_t* RequiredBlock();
  syntax_asdl::command_t* OptionalBlock();
  syntax_asdl::LiteralBlock* OptionalLiteralBlock();
  List<value_asdl::value_t*>* RestPos();
  syntax_asdl::loc_t* _BlameNamed(BigStr* name);
  BigStr* NamedStr(BigStr* param_name, BigStr* default_);
  bool NamedBool(BigStr* param_name, bool default_);
  mops::BigInt NamedInt(BigStr* param_name, int default_);
  double NamedFloat(BigStr* param_name, double default_);
  List<value_asdl::value_t*>* NamedList(BigStr* param_name, List<value_asdl::value_t*>* default_);
  Dict<BigStr*, value_asdl::value_t*>* NamedDict(BigStr* param_name, Dict<BigStr*, value_asdl::value_t*>* default_);
  Dict<BigStr*, value_asdl::value_t*>* RestNamed();
  void Done();
  List<value_asdl::value_t*>* pos_args;
  Dict<BigStr*, value_asdl::value_t*>* named_args;
  value_asdl::value_t* block_arg;
  syntax_asdl::ArgList* arg_list;
  syntax_asdl::loc_t* fallback_loc;
  int pos_consumed;
  bool is_bound;

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassScanned(5, sizeof(Reader));
  }

  DISALLOW_COPY_AND_ASSIGN(Reader)
};


}  // declare namespace typed_args

namespace arith_parse {  // declare

using id_kind_asdl::Id;
using syntax_asdl::loc;
syntax_asdl::arith_expr_t* NullIncDec(tdop::TdopParser* p, syntax_asdl::word_t* w, int bp);
syntax_asdl::arith_expr_t* NullUnaryPlus(tdop::TdopParser* p, syntax_asdl::word_t* t, int bp);
syntax_asdl::arith_expr_t* NullUnaryMinus(tdop::TdopParser* p, syntax_asdl::word_t* t, int bp);
syntax_asdl::arith_expr_t* LeftIncDec(tdop::TdopParser* p, syntax_asdl::word_t* w, syntax_asdl::arith_expr_t* left, int rbp);
syntax_asdl::arith_expr_t* LeftIndex(tdop::TdopParser* p, syntax_asdl::word_t* w, syntax_asdl::arith_expr_t* left, int unused_bp);
syntax_asdl::arith_expr_t* LeftTernary(tdop::TdopParser* p, syntax_asdl::word_t* t, syntax_asdl::arith_expr_t* left, int bp);

}  // declare namespace arith_parse

namespace bool_parse {  // declare

using id_kind_asdl::Id;
using types_asdl::lex_mode_e;
using syntax_asdl::loc;
class BoolParser {
 public:
  BoolParser(word_parse::WordEmitter* w_parser);
  void _NextOne(types_asdl::lex_mode_t lex_mode = lex_mode_e::DBracket);
  void _Next(types_asdl::lex_mode_t lex_mode = lex_mode_e::DBracket);
  syntax_asdl::word_t* _LookAhead();
  Tuple2<syntax_asdl::bool_expr_t*, syntax_asdl::Token*> Parse();
  bool _TestAtEnd();
  syntax_asdl::bool_expr_t* ParseForBuiltin();
  syntax_asdl::bool_expr_t* ParseExpr();
  syntax_asdl::bool_expr_t* ParseTerm();
  syntax_asdl::bool_expr_t* ParseNegatedFactor();
  syntax_asdl::bool_expr_t* ParseFactor();
  word_parse::WordEmitter* w_parser;
  List<syntax_asdl::word_t*>* words;
  syntax_asdl::word_t* cur_word;
  int bool_id;
  id_kind_asdl::Kind_t bool_kind;

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassScanned(3, sizeof(BoolParser));
  }

  DISALLOW_COPY_AND_ASSIGN(BoolParser)
};


}  // declare namespace bool_parse

namespace braces {  // declare

using id_kind_asdl::Id;
using syntax_asdl::word;
using syntax_asdl::word_part;
extern int NO_STEP;
class _NotARange {
 public:
  _NotARange(BigStr* s);

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassScanned(0, sizeof(_NotARange));
  }

  DISALLOW_COPY_AND_ASSIGN(_NotARange)
};

class _RangeParser {
 public:
  _RangeParser(match::SimpleLexer* lexer, syntax_asdl::Token* blame_tok);
  void _Next();
  BigStr* _Eat(int token_type);
  int _ParseStep();
  word_part::BracedRange* _ParseRange(int range_kind);
  word_part::BracedRange* Parse();
  match::SimpleLexer* lexer;
  syntax_asdl::Token* blame_tok;
  BigStr* token_val;
  int token_type;

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassScanned(3, sizeof(_RangeParser));
  }

  DISALLOW_COPY_AND_ASSIGN(_RangeParser)
};

word_part::BracedRange* _RangePartDetect(syntax_asdl::Token* tok);
class _StackFrame {
 public:
  _StackFrame(List<syntax_asdl::word_part_t*>* cur_parts);
  List<syntax_asdl::word_part_t*>* cur_parts;
  word_part::BracedTuple* alt_part;
  bool saw_comma;

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassScanned(2, sizeof(_StackFrame));
  }

  DISALLOW_COPY_AND_ASSIGN(_StackFrame)
};

word::BracedTree* BraceDetect(syntax_asdl::CompoundWord* w);
List<syntax_asdl::word_t*>* BraceDetectAll(List<syntax_asdl::CompoundWord*>* words);
int _LeadingZeros(BigStr* s);
BigStr* _IntToString(int i, int width);
List<BigStr*>* _RangeStrings(word_part::BracedRange* part);
List<List<syntax_asdl::word_part_t*>*>* _ExpandPart(List<syntax_asdl::word_part_t*>* parts, int first_alt_index, List<List<syntax_asdl::word_part_t*>*>* suffixes);
List<List<syntax_asdl::word_part_t*>*>* _BraceExpand(List<syntax_asdl::word_part_t*>* parts);
List<syntax_asdl::CompoundWord*>* BraceExpandWords(List<syntax_asdl::word_t*>* words);

}  // declare namespace braces

namespace cmd_eval {  // declare

using id_kind_asdl::Id;
using syntax_asdl::loc;
using syntax_asdl::word;
using runtime_asdl::cmd_value;
using runtime_asdl::scope_e;
extern int IsMainProgram;
extern int RaiseControlFlow;
extern int Optimize;
extern int NoDebugTrap;
extern int NoErrTrap;
cmd_value::Argv* MakeBuiltinArgv(List<BigStr*>* argv1);
class Deps {
 public:
  Deps();
  state::MutableOpts* mutable_opts;
  dev::CrashDumper* dumper;
  util::_DebugFile* debug_f;

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassScanned(3, sizeof(Deps));
  }

  DISALLOW_COPY_AND_ASSIGN(Deps)
};

bool _HasManyStatuses(syntax_asdl::command_t* node);
value_asdl::value_t* PlusEquals(value_asdl::value_t* old_val, value_asdl::value_t* val);
class ctx_LoopLevel {
 public:
  ctx_LoopLevel(cmd_eval::CommandEvaluator* cmd_ev);
  ~ctx_LoopLevel();
  cmd_eval::CommandEvaluator* cmd_ev;

  DISALLOW_COPY_AND_ASSIGN(ctx_LoopLevel)
};

class CommandEvaluator {
 public:
  CommandEvaluator(state::Mem* mem, optview::Exec* exec_opts, ui::ErrorFormatter* errfmt, Dict<BigStr*, value::Proc*>* procs, Dict<int, vm::_AssignBuiltin*>* assign_builtins, alloc::Arena* arena, cmd_eval::Deps* cmd_deps, trap_osh::TrapState* trap_state, pyos::SignalSafe* signal_safe);
  void CheckCircularDeps();
  int _RunAssignBuiltin(cmd_value::Assign* cmd_val);
  void _CheckStatus(int status, runtime_asdl::CommandStatus* cmd_st, syntax_asdl::command_t* node, syntax_asdl::loc_t* default_loc);
  runtime_asdl::RedirValue* _EvalRedirect(syntax_asdl::Redir* r);
  int _RunSimpleCommand(runtime_asdl::cmd_value_t* cmd_val, runtime_asdl::CommandStatus* cmd_st, int run_flags);
  void _EvalTempEnv(List<syntax_asdl::EnvPair*>* more_env, int flags);
  void _StrictErrExit(syntax_asdl::command_t* node);
  void _StrictErrExitList(List<syntax_asdl::command_t*>* node_list);
  bool _EvalCondition(syntax_asdl::condition_t* cond, syntax_asdl::Token* blame_tok);
  value_asdl::value_t* _EvalCaseArg(syntax_asdl::case_arg_t* arg, syntax_asdl::loc_t* blame);
  int _DoVarDecl(command::VarDecl* node);
  void _DoMutation(command::Mutation* node);
  int _DoSimple(command::Simple* node, runtime_asdl::CommandStatus* cmd_st);
  int _DoExpandedAlias(command::ExpandedAlias* node);
  int _DoPipeline(command::Pipeline* node, runtime_asdl::CommandStatus* cmd_st);
  int _DoShAssignment(command::ShAssignment* node, runtime_asdl::CommandStatus* cmd_st);
  int _DoExpr(command::Expr* node);
  int _DoControlFlow(command::ControlFlow* node);
  int _DoAndOr(command::AndOr* node, runtime_asdl::CommandStatus* cmd_st);
  int _DoWhileUntil(command::WhileUntil* node);
  int _DoForEach(command::ForEach* node);
  int _DoForExpr(command::ForExpr* node);
  void _DoShFunction(command::ShFunction* node);
  void _DoProc(syntax_asdl::Proc* node);
  void _DoFunc(syntax_asdl::Func* node);
  int _DoIf(command::If* node);
  int _DoCase(command::Case* node);
  int _DoTimeBlock(command::TimeBlock* node);
  int _DoRedirect(command::Redirect* node, runtime_asdl::CommandStatus* cmd_st);
  int _Dispatch(syntax_asdl::command_t* node, runtime_asdl::CommandStatus* cmd_st);
  void RunPendingTraps();
  int _Execute(syntax_asdl::command_t* node);
  int _ExecuteList(List<syntax_asdl::command_t*>* children);
  int LastStatus();
  void _NoForkLast(syntax_asdl::command_t* node);
  syntax_asdl::command_t* _RemoveSubshells(syntax_asdl::command_t* node);
  Tuple2<bool, bool> ExecuteAndCatch(syntax_asdl::command_t* node, int cmd_flags = 0);
  int EvalCommand(syntax_asdl::command_t* block);
  void MaybeRunExitTrap(syntax_asdl::IntParamBox* mut_status);
  void _MaybeRunDebugTrap();
  void _MaybeRunErrTrap();
  int RunProc(value::Proc* proc, cmd_value::Argv* cmd_val);
  int RunFuncForCompletion(value::Proc* proc, List<BigStr*>* argv);
  vm::_Executor* shell_ex;
  sh_expr_eval::ArithEvaluator* arith_ev;
  sh_expr_eval::BoolEvaluator* bool_ev;
  expr_eval::ExprEvaluator* expr_ev;
  word_eval::AbstractWordEvaluator* word_ev;
  dev::Tracer* tracer;
  state::Mem* mem;
  optview::Exec* exec_opts;
  ui::ErrorFormatter* errfmt;
  Dict<BigStr*, value::Proc*>* procs;
  Dict<int, vm::_AssignBuiltin*>* assign_builtins;
  alloc::Arena* arena;
  state::MutableOpts* mutable_opts;
  dev::CrashDumper* dumper;
  util::_DebugFile* debug_f;
  trap_osh::TrapState* trap_state;
  pyos::SignalSafe* signal_safe;
  List<runtime_asdl::StatusArray*>* status_array_pool;
  int loop_level;
  bool check_command_sub_status;

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassScanned(18, sizeof(CommandEvaluator));
  }

  DISALLOW_COPY_AND_ASSIGN(CommandEvaluator)
};


}  // declare namespace cmd_eval

namespace cmd_parse {  // declare

using id_kind_asdl::Id;
using types_asdl::lex_mode_e;
using syntax_asdl::loc;
extern int TAB_CH;
extern int SPACE_CH;
Tuple2<List<Tuple2<syntax_asdl::SourceLine*, int>*>*, Tuple2<syntax_asdl::SourceLine*, int>*> _ReadHereLines(reader::_Reader* line_reader, syntax_asdl::Redir* h, BigStr* delimiter);
List<syntax_asdl::word_part_t*>* _MakeLiteralHereLines(List<Tuple2<syntax_asdl::SourceLine*, int>*>* here_lines, alloc::Arena* arena, bool do_lossless);
void _ParseHereDocBody(parse_lib::ParseContext* parse_ctx, syntax_asdl::Redir* r, reader::_Reader* line_reader, alloc::Arena* arena);
syntax_asdl::AssignPair* _MakeAssignPair(parse_lib::ParseContext* parse_ctx, syntax_asdl::ParsedAssignment* preparsed, alloc::Arena* arena);
void _AppendMoreEnv(List<syntax_asdl::ParsedAssignment*>* preparsed_list, List<syntax_asdl::EnvPair*>* more_env);
Tuple2<List<syntax_asdl::ParsedAssignment*>*, List<syntax_asdl::CompoundWord*>*> _SplitSimpleCommandPrefix(List<syntax_asdl::CompoundWord*>* words);
command::Simple* _MakeSimpleCommand(List<syntax_asdl::ParsedAssignment*>* preparsed_list, List<syntax_asdl::CompoundWord*>* suffix_words, syntax_asdl::ArgList* typed_args, syntax_asdl::LiteralBlock* block);
class VarChecker {
 public:
  VarChecker();
  void Push(syntax_asdl::Token* blame_tok);
  void Pop();
  void Check(int keyword_id, BigStr* var_name, syntax_asdl::Token* blame_tok);
  List<syntax_asdl::Token*>* tokens;
  List<Dict<BigStr*, int>*>* names;

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassScanned(2, sizeof(VarChecker));
  }

  DISALLOW_COPY_AND_ASSIGN(VarChecker)
};

class ctx_VarChecker {
 public:
  ctx_VarChecker(cmd_parse::VarChecker* var_checker, syntax_asdl::Token* blame_tok);
  ~ctx_VarChecker();
  cmd_parse::VarChecker* var_checker;

  DISALLOW_COPY_AND_ASSIGN(ctx_VarChecker)
};

class ctx_CmdMode {
 public:
  ctx_CmdMode(cmd_parse::CommandParser* cmd_parse, types_asdl::cmd_mode_t new_cmd_mode);
  ~ctx_CmdMode();
  cmd_parse::CommandParser* cmd_parse;
  types_asdl::cmd_mode_t prev_cmd_mode;

  DISALLOW_COPY_AND_ASSIGN(ctx_CmdMode)
};

extern List<int>* SECONDARY_KEYWORDS;
class CommandParser {
 public:
  CommandParser(parse_lib::ParseContext* parse_ctx, optview::Parse* parse_opts, word_parse::WordParser* w_parser, lexer::Lexer* lexer, reader::_Reader* line_reader, int eof_id = Id::Eof_Real);
  void Init_AliasesInFlight(List<Tuple2<BigStr*, int>*>* aliases_in_flight);
  void Reset();
  void ResetInputObjects();
  void _SetNext();
  void _SetNextBrack();
  void _GetWord();
  syntax_asdl::word_t* _Eat(int c_id, BigStr* msg = nullptr);
  void _NewlineOk();
  bool _AtSecondaryKeyword();
  syntax_asdl::Redir* ParseRedirect();
  List<syntax_asdl::Redir*>* _ParseRedirectList();
  syntax_asdl::command_t* _MaybeParseRedirectList(syntax_asdl::command_t* node);
  Tuple4<List<syntax_asdl::Redir*>*, List<syntax_asdl::CompoundWord*>*, syntax_asdl::ArgList*, syntax_asdl::LiteralBlock*> _ScanSimpleCommand();
  syntax_asdl::command_t* _MaybeExpandAliases(List<syntax_asdl::CompoundWord*>* words);
  syntax_asdl::command_t* ParseSimpleCommand();
  syntax_asdl::BraceGroup* ParseBraceGroup();
  command::DoGroup* ParseDoGroup();
  Tuple2<List<syntax_asdl::CompoundWord*>*, syntax_asdl::Token*> ParseForWords();
  command::ForExpr* _ParseForExprLoop(syntax_asdl::Token* for_kw);
  command::ForEach* _ParseForEachLoop(syntax_asdl::Token* for_kw);
  syntax_asdl::command_t* ParseFor();
  syntax_asdl::condition_t* _ParseConditionList();
  command::WhileUntil* ParseWhileUntil(syntax_asdl::Token* keyword);
  syntax_asdl::CaseArm* ParseCaseArm();
  syntax_asdl::CaseArm* ParseYshCaseArm(int discriminant);
  command::Case* ParseYshCase(syntax_asdl::Token* case_kw);
  command::Case* ParseOldCase(syntax_asdl::Token* case_kw);
  command::Case* ParseCase();
  void _ParseYshElifElse(command::If* if_node);
  command::If* _ParseYshIf(syntax_asdl::Token* if_kw, syntax_asdl::condition_t* cond);
  void _ParseElifElse(command::If* if_node);
  command::If* ParseIf();
  syntax_asdl::command_t* ParseTime();
  syntax_asdl::command_t* ParseCompoundCommand();
  command::ShFunction* ParseFunctionDef();
  command::ShFunction* ParseKshFunctionDef();
  syntax_asdl::Proc* ParseYshProc();
  syntax_asdl::Func* ParseYshFunc();
  syntax_asdl::command_t* ParseCoproc();
  command::Subshell* ParseSubshell();
  command::DBracket* ParseDBracket();
  command::DParen* ParseDParen();
  syntax_asdl::command_t* ParseCommand();
  syntax_asdl::command_t* ParsePipeline();
  syntax_asdl::command_t* ParseAndOr();
  syntax_asdl::command_t* _ParseAndOr();
  syntax_asdl::command_t* _ParseCommandLine();
  command::CommandList* _ParseCommandTerm();
  command::CommandList* _ParseCommandList();
  syntax_asdl::command_t* ParseLogicalLine();
  syntax_asdl::parse_result_t* ParseInteractiveLine();
  syntax_asdl::command_t* ParseCommandSub();
  void CheckForPendingHereDocs();
  parse_lib::ParseContext* parse_ctx;
  Dict<BigStr*, BigStr*>* aliases;
  optview::Parse* parse_opts;
  word_parse::WordParser* w_parser;
  lexer::Lexer* lexer;
  reader::_Reader* line_reader;
  alloc::Arena* arena;
  List<Tuple2<BigStr*, int>*>* aliases_in_flight;
  List<bool>* hay_attrs_stack;
  cmd_parse::VarChecker* var_checker;
  syntax_asdl::word_t* cur_word;
  List<syntax_asdl::Redir*>* pending_here_docs;
  int eof_id;
  bool allow_block;
  types_asdl::cmd_mode_t cmd_mode;
  types_asdl::lex_mode_t next_lex_mode;
  id_kind_asdl::Kind_t c_kind;
  int c_id;

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassScanned(12, sizeof(CommandParser));
  }

  DISALLOW_COPY_AND_ASSIGN(CommandParser)
};


}  // declare namespace cmd_parse

namespace glob_ {  // declare

using id_kind_asdl::Id;
bool LooksLikeGlob(BigStr* s);
bool LooksLikeStaticGlob(syntax_asdl::CompoundWord* w);
extern BigStr* GLOB_META_CHARS;
BigStr* GlobEscape(BigStr* s);
extern BigStr* ERE_META_CHARS;
BigStr* ExtendedRegexEscape(BigStr* s);
BigStr* GlobUnescape(BigStr* s);
class _GlobParser {
 public:
  _GlobParser(match::SimpleLexer* lexer);
  void _Next();
  List<syntax_asdl::glob_part_t*>* _ParseCharClass();
  Tuple2<List<syntax_asdl::glob_part_t*>*, List<BigStr*>*> Parse();
  match::SimpleLexer* lexer;
  BigStr* token_val;
  List<BigStr*>* warnings;
  int token_type;

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassScanned(3, sizeof(_GlobParser));
  }

  DISALLOW_COPY_AND_ASSIGN(_GlobParser)
};

extern BigStr* _REGEX_CHARS_TO_ESCAPE;
BigStr* _GenerateERE(List<syntax_asdl::glob_part_t*>* parts);
Tuple2<BigStr*, List<BigStr*>*> GlobToERE(BigStr* pat);
class Globber {
 public:
  Globber(optview::Exec* exec_opts);
  int _Glob(BigStr* arg, List<BigStr*>* out);
  int Expand(BigStr* arg, List<BigStr*>* out);
  int ExpandExtended(BigStr* glob_pat, BigStr* fnmatch_pat, List<BigStr*>* out);
  optview::Exec* exec_opts;

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassScanned(1, sizeof(Globber));
  }

  DISALLOW_COPY_AND_ASSIGN(Globber)
};


}  // declare namespace glob_

namespace history {  // declare

using id_kind_asdl::Id;
class Evaluator {
 public:
  Evaluator(py_readline::Readline* readline, parse_lib::ParseContext* parse_ctx, util::_DebugFile* debug_f);
  BigStr* Eval(BigStr* line);
  py_readline::Readline* readline;
  parse_lib::ParseContext* parse_ctx;
  util::_DebugFile* debug_f;

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassScanned(3, sizeof(Evaluator));
  }

  DISALLOW_COPY_AND_ASSIGN(Evaluator)
};


}  // declare namespace history

namespace prompt {  // declare

using id_kind_asdl::Id;
using syntax_asdl::loc;
extern BigStr* _ERROR_FMT;
extern BigStr* _UNBALANCED_ERROR;
class _PromptEvaluatorCache {
 public:
  _PromptEvaluatorCache();
  int _GetEuid();
  BigStr* Get(BigStr* name);
  Dict<BigStr*, BigStr*>* cache;
  int euid;

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassScanned(1, sizeof(_PromptEvaluatorCache));
  }

  DISALLOW_COPY_AND_ASSIGN(_PromptEvaluatorCache)
};

class Evaluator {
 public:
  Evaluator(BigStr* lang, BigStr* version_str, parse_lib::ParseContext* parse_ctx, state::Mem* mem);
  void CheckCircularDeps();
  BigStr* PromptVal(BigStr* what);
  BigStr* PromptSubst(BigStr* ch, BigStr* arg = nullptr);
  BigStr* _ReplaceBackslashCodes(List<Tuple2<int, BigStr*>*>* tokens);
  BigStr* EvalPrompt(value_asdl::value_t* UP_val);
  BigStr* EvalFirstPrompt();
  word_eval::AbstractWordEvaluator* word_ev;
  expr_eval::ExprEvaluator* expr_ev;
  value::IO* global_io;
  BigStr* lang;
  BigStr* version_str;
  parse_lib::ParseContext* parse_ctx;
  state::Mem* mem;
  prompt::_PromptEvaluatorCache* cache;
  Dict<BigStr*, List<Tuple2<int, BigStr*>*>*>* tokens_cache;
  Dict<BigStr*, syntax_asdl::CompoundWord*>* parse_cache;

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassScanned(10, sizeof(Evaluator));
  }

  DISALLOW_COPY_AND_ASSIGN(Evaluator)
};

extern BigStr* PROMPT_COMMAND;
class UserPlugin {
 public:
  UserPlugin(state::Mem* mem, parse_lib::ParseContext* parse_ctx, cmd_eval::CommandEvaluator* cmd_ev, ui::ErrorFormatter* errfmt);
  void Run();
  state::Mem* mem;
  parse_lib::ParseContext* parse_ctx;
  cmd_eval::CommandEvaluator* cmd_ev;
  ui::ErrorFormatter* errfmt;
  alloc::Arena* arena;
  Dict<BigStr*, syntax_asdl::command_t*>* parse_cache;

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassScanned(6, sizeof(UserPlugin));
  }

  DISALLOW_COPY_AND_ASSIGN(UserPlugin)
};


}  // declare namespace prompt

namespace sh_expr_eval {  // declare

using id_kind_asdl::Id;
using syntax_asdl::loc;
using value_asdl::sh_lvalue;
value_asdl::value_t* OldValue(value_asdl::sh_lvalue_t* lval, state::Mem* mem, optview::Exec* exec_opts);
class UnsafeArith {
 public:
  UnsafeArith(state::Mem* mem, optview::Exec* exec_opts, state::MutableOpts* mutable_opts, parse_lib::ParseContext* parse_ctx, sh_expr_eval::ArithEvaluator* arith_ev, ui::ErrorFormatter* errfmt);
  value_asdl::sh_lvalue_t* ParseLValue(BigStr* s, syntax_asdl::loc_t* location);
  syntax_asdl::BracedVarSub* ParseVarRef(BigStr* ref_str, syntax_asdl::Token* blame_tok);
  state::Mem* mem;
  optview::Exec* exec_opts;
  state::MutableOpts* mutable_opts;
  parse_lib::ParseContext* parse_ctx;
  sh_expr_eval::ArithEvaluator* arith_ev;
  ui::ErrorFormatter* errfmt;
  alloc::Arena* arena;

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassScanned(7, sizeof(UnsafeArith));
  }

  DISALLOW_COPY_AND_ASSIGN(UnsafeArith)
};

class ArithEvaluator {
 public:
  ArithEvaluator(state::Mem* mem, optview::Exec* exec_opts, state::MutableOpts* mutable_opts, parse_lib::ParseContext* parse_ctx, ui::ErrorFormatter* errfmt);
  void CheckCircularDeps();
  mops::BigInt _StringToBigInt(BigStr* s, syntax_asdl::loc_t* blame_loc);
  mops::BigInt _ValToIntOrError(value_asdl::value_t* val, syntax_asdl::arith_expr_t* blame);
  Tuple2<mops::BigInt, value_asdl::sh_lvalue_t*> _EvalLhsAndLookupArith(syntax_asdl::arith_expr_t* node);
  void _Store(value_asdl::sh_lvalue_t* lval, mops::BigInt new_int);
  mops::BigInt EvalToBigInt(syntax_asdl::arith_expr_t* node);
  int EvalToInt(syntax_asdl::arith_expr_t* node);
  value_asdl::value_t* Eval(syntax_asdl::arith_expr_t* node);
  BigStr* EvalWordToString(syntax_asdl::arith_expr_t* node, syntax_asdl::loc_t* blame_loc = loc::Missing);
  value_asdl::sh_lvalue_t* EvalShellLhs(syntax_asdl::sh_lhs_t* node, runtime_asdl::scope_t which_scopes);
  Tuple2<BigStr*, syntax_asdl::loc_t*> _VarNameOrWord(syntax_asdl::arith_expr_t* anode);
  value_asdl::sh_lvalue_t* EvalArithLhs(syntax_asdl::arith_expr_t* anode);
  ui::ErrorFormatter* errfmt;
  optview::Exec* exec_opts;
  state::Mem* mem;
  state::MutableOpts* mutable_opts;
  parse_lib::ParseContext* parse_ctx;
  word_eval::StringWordEvaluator* word_ev;
  
  static constexpr uint32_t field_mask() {
    return maskbit(offsetof(ArithEvaluator, errfmt))
         | maskbit(offsetof(ArithEvaluator, exec_opts))
         | maskbit(offsetof(ArithEvaluator, mem))
         | maskbit(offsetof(ArithEvaluator, mutable_opts))
         | maskbit(offsetof(ArithEvaluator, parse_ctx))
         | maskbit(offsetof(ArithEvaluator, word_ev));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(ArithEvaluator));
  }

  DISALLOW_COPY_AND_ASSIGN(ArithEvaluator)
};

class BoolEvaluator : public ::sh_expr_eval::ArithEvaluator {
 public:
  BoolEvaluator(state::Mem* mem, optview::Exec* exec_opts, state::MutableOpts* mutable_opts, parse_lib::ParseContext* parse_ctx, ui::ErrorFormatter* errfmt, bool always_strict = false);
  bool _IsDefined(BigStr* s, syntax_asdl::loc_t* blame_loc);
  mops::BigInt _StringToBigIntOrError(BigStr* s, syntax_asdl::word_t* blame_word = nullptr);
  BigStr* _EvalCompoundWord(syntax_asdl::word_t* word, int eval_flags = 0);
  bool EvalB(syntax_asdl::bool_expr_t* node);

  bool always_strict;
  
  static constexpr uint32_t field_mask() {
    return ::sh_expr_eval::ArithEvaluator::field_mask();
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(BoolEvaluator));
  }

  DISALLOW_COPY_AND_ASSIGN(BoolEvaluator)
};


}  // declare namespace sh_expr_eval

namespace split {  // declare

using runtime_asdl::scope_e;
extern BigStr* DEFAULT_IFS;
List<BigStr*>* _SpansToParts(BigStr* s, List<Tuple2<runtime_asdl::span_t, int>*>* spans);
class SplitContext {
 public:
  SplitContext(state::Mem* mem);
  split::IfsSplitter* _GetSplitter(BigStr* ifs = nullptr);
  BigStr* GetJoinChar();
  BigStr* Escape(BigStr* s);
  List<BigStr*>* SplitForWordEval(BigStr* s, BigStr* ifs = nullptr);
  List<Tuple2<runtime_asdl::span_t, int>*>* SplitForRead(BigStr* line, bool allow_escape, bool do_split);
  state::Mem* mem;
  Dict<BigStr*, split::IfsSplitter*>* splitters;

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassScanned(2, sizeof(SplitContext));
  }

  DISALLOW_COPY_AND_ASSIGN(SplitContext)
};

class _BaseSplitter {
 public:
  _BaseSplitter(BigStr* escape_chars);
  BigStr* Escape(BigStr* s);
  BigStr* escape_chars;
  
  static constexpr uint32_t field_mask() {
    return maskbit(offsetof(_BaseSplitter, escape_chars));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(_BaseSplitter));
  }

  DISALLOW_COPY_AND_ASSIGN(_BaseSplitter)
};

class IfsSplitter : public ::split::_BaseSplitter {
 public:
  IfsSplitter(BigStr* ifs_whitespace, BigStr* ifs_other);
  List<Tuple2<runtime_asdl::span_t, int>*>* Split(BigStr* s, bool allow_escape);

  BigStr* ifs_other;
  BigStr* ifs_whitespace;
  
  static constexpr uint32_t field_mask() {
    return ::split::_BaseSplitter::field_mask()
         | maskbit(offsetof(IfsSplitter, ifs_other))
         | maskbit(offsetof(IfsSplitter, ifs_whitespace));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(IfsSplitter));
  }

  DISALLOW_COPY_AND_ASSIGN(IfsSplitter)
};


}  // declare namespace split

namespace string_ops {  // declare

using id_kind_asdl::Id;
using syntax_asdl::loc;
using syntax_asdl::suffix_op;
extern int UTF8_ERR_OVERLONG;
extern int UTF8_ERR_SURROGATE;
extern int UTF8_ERR_TOO_LARGE;
extern int UTF8_ERR_BAD_ENCODING;
extern int UTF8_ERR_TRUNCATED_BYTES;
BigStr* Utf8Error_str(int error);
int DecodeUtf8Char(BigStr* s, int start);
int NextUtf8Char(BigStr* s, int i);
extern BigStr* _INVALID_START;
int _Utf8CharLen(int starting_byte);
int PreviousUtf8Char(BigStr* s, int i);
int CountUtf8Chars(BigStr* s);
int AdvanceUtf8Chars(BigStr* s, int num_chars, int byte_offset);
extern List<int>* SPACES;
bool _IsSpace(int codepoint);
Tuple2<int, int> StartsWithWhitespaceByteRange(BigStr* s);
Tuple2<int, int> EndsWithWhitespaceByteRange(BigStr* s);
BigStr* DoUnarySuffixOp(BigStr* s, syntax_asdl::Token* op_tok, BigStr* arg, bool is_extglob);
List<Tuple2<int, int>*>* _AllMatchPositions(BigStr* s, BigStr* regex);
BigStr* _PatSubAll(BigStr* s, BigStr* regex, BigStr* replace_str);
class GlobReplacer {
 public:
  GlobReplacer(BigStr* regex, BigStr* replace_str, syntax_asdl::Token* slash_tok);
  BigStr* Replace(BigStr* s, suffix_op::PatSub* op);
  BigStr* regex;
  BigStr* replace_str;
  syntax_asdl::Token* slash_tok;

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassScanned(3, sizeof(GlobReplacer));
  }

  DISALLOW_COPY_AND_ASSIGN(GlobReplacer)
};

BigStr* ShellQuoteB(BigStr* s);

}  // declare namespace string_ops

namespace tdop {  // declare

using id_kind_asdl::Id;
using syntax_asdl::loc;
bool IsIndexable(syntax_asdl::arith_expr_t* node);
void CheckLhsExpr(syntax_asdl::arith_expr_t* node, syntax_asdl::word_t* blame_word);
syntax_asdl::arith_expr_t* NullError(tdop::TdopParser* p, syntax_asdl::word_t* t, int bp);
syntax_asdl::arith_expr_t* NullConstant(tdop::TdopParser* p, syntax_asdl::word_t* w, int bp);
syntax_asdl::arith_expr_t* NullParen(tdop::TdopParser* p, syntax_asdl::word_t* t, int bp);
syntax_asdl::arith_expr_t* NullPrefixOp(tdop::TdopParser* p, syntax_asdl::word_t* w, int bp);
syntax_asdl::arith_expr_t* LeftError(tdop::TdopParser* p, syntax_asdl::word_t* t, syntax_asdl::arith_expr_t* left, int rbp);
syntax_asdl::arith_expr_t* LeftBinaryOp(tdop::TdopParser* p, syntax_asdl::word_t* w, syntax_asdl::arith_expr_t* left, int rbp);
syntax_asdl::arith_expr_t* LeftAssign(tdop::TdopParser* p, syntax_asdl::word_t* w, syntax_asdl::arith_expr_t* left, int rbp);
class TdopParser {
 public:
  TdopParser(tdop::ParserSpec* spec, word_parse::WordParser* w_parser, optview::Parse* parse_opts);
  int CurrentId();
  bool AtToken(int token_type);
  void Eat(int token_type);
  bool Next();
  syntax_asdl::arith_expr_t* ParseUntil(int rbp);
  syntax_asdl::arith_expr_t* Parse();
  tdop::ParserSpec* spec;
  word_parse::WordParser* w_parser;
  optview::Parse* parse_opts;
  syntax_asdl::word_t* cur_word;
  int op_id;

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassScanned(4, sizeof(TdopParser));
  }

  DISALLOW_COPY_AND_ASSIGN(TdopParser)
};


}  // declare namespace tdop

namespace word_ {  // declare

using id_kind_asdl::Id;
using syntax_asdl::word;
using syntax_asdl::word_part;
int LiteralId(syntax_asdl::word_part_t* p);
Tuple3<bool, BigStr*, bool> _EvalWordPart(syntax_asdl::word_part_t* part);
BigStr* FastStrEval(syntax_asdl::CompoundWord* w);
Tuple3<bool, BigStr*, bool> StaticEval(syntax_asdl::word_t* UP_w);
syntax_asdl::CompoundWord* TildeDetect(syntax_asdl::word_t* UP_w);
syntax_asdl::CompoundWord* TildeDetect2(syntax_asdl::CompoundWord* w);
void TildeDetectAssign(syntax_asdl::CompoundWord* w);
List<syntax_asdl::word_t*>* TildeDetectAll(List<syntax_asdl::word_t*>* words);
bool HasArrayPart(syntax_asdl::CompoundWord* w);
BigStr* ShFunctionName(syntax_asdl::CompoundWord* w);
syntax_asdl::Token* LooksLikeArithVar(syntax_asdl::word_t* UP_w);
bool IsVarLike(syntax_asdl::CompoundWord* w);
Tuple3<syntax_asdl::Token*, syntax_asdl::Token*, int> DetectShAssignment(syntax_asdl::CompoundWord* w);
syntax_asdl::AssocPair* DetectAssocPair(syntax_asdl::CompoundWord* w);
Tuple2<id_kind_asdl::Kind_t, syntax_asdl::Token*> IsControlFlow(syntax_asdl::CompoundWord* w);
syntax_asdl::Token* LiteralToken(syntax_asdl::word_t* UP_w);
syntax_asdl::Token* BraceToken(syntax_asdl::word_t* UP_w);
syntax_asdl::Token* AsKeywordToken(syntax_asdl::word_t* UP_w);
syntax_asdl::Token* AsOperatorToken(syntax_asdl::word_t* word);
int ArithId(syntax_asdl::word_t* w);
int BoolId(syntax_asdl::word_t* w);
int CommandId(syntax_asdl::word_t* w);
id_kind_asdl::Kind_t CommandKind(syntax_asdl::word_t* w);
bool IsVarSub(syntax_asdl::word_t* w);
syntax_asdl::CompoundWord* ErrorWord(BigStr* error_str);
BigStr* Pretty(syntax_asdl::word_t* w);
class ctx_EmitDocToken {
 public:
  ctx_EmitDocToken(word_parse::WordParser* w_parser);
  ~ctx_EmitDocToken();
  word_parse::WordParser* w_parser;

  DISALLOW_COPY_AND_ASSIGN(ctx_EmitDocToken)
};

class ctx_Multiline {
 public:
  ctx_Multiline(word_parse::WordParser* w_parser);
  ~ctx_Multiline();
  word_parse::WordParser* w_parser;

  DISALLOW_COPY_AND_ASSIGN(ctx_Multiline)
};


}  // declare namespace word_

namespace word_compile {  // declare

using id_kind_asdl::Id;
syntax_asdl::CharCode* EvalCharLiteralForRegex(syntax_asdl::Token* tok);
BigStr* EvalCStringToken(int id_, BigStr* value);
BigStr* EvalSingleQuoted(int id_, List<syntax_asdl::Token*>* tokens);
bool _TokenConsistsOf(syntax_asdl::Token* tok, BigStr* byte_set);
bool _IsLeadingSpace(syntax_asdl::Token* tok);
bool _IsTrailingSpace(syntax_asdl::Token* tok);
void RemoveLeadingSpaceDQ(List<syntax_asdl::word_part_t*>* parts);
void RemoveLeadingSpaceSQ(List<syntax_asdl::Token*>* tokens);

}  // declare namespace word_compile

namespace word_eval {  // declare

using id_kind_asdl::Id;
using syntax_asdl::loc;
using syntax_asdl::suffix_op;
using syntax_asdl::word_part;
using runtime_asdl::part_value;
using runtime_asdl::cmd_value;
using value_asdl::sh_lvalue;
extern int QUOTED;
extern int IS_SUBST;
extern int EXTGLOB_FILES;
extern int EXTGLOB_MATCH;
extern int EXTGLOB_NESTED;
extern int QUOTE_FNMATCH;
extern int QUOTE_ERE;
extern List<BigStr*>* _STRING_AND_ARRAY;
bool ShouldArrayDecay(BigStr* var_name, optview::Exec* exec_opts, bool is_plain_var_sub = true);
value_asdl::value_t* DecayArray(value_asdl::value_t* val);
BigStr* GetArrayItem(List<BigStr*>* strs, int index);
bool _DetectMetaBuiltinStr(BigStr* s);
bool _DetectMetaBuiltin(runtime_asdl::part_value_t* val0);
runtime_asdl::AssignArg* _SplitAssignArg(BigStr* arg, syntax_asdl::CompoundWord* blame_word);
BigStr* _BackslashEscape(BigStr* s);
runtime_asdl::part_value_t* _ValueToPartValue(value_asdl::value_t* val, bool quoted, syntax_asdl::word_part_t* part_loc);
List<List<runtime_asdl::Piece*>*>* _MakeWordFrames(List<runtime_asdl::part_value_t*>* part_vals);
BigStr* _DecayPartValuesToString(List<runtime_asdl::part_value_t*>* part_vals, BigStr* join_char);
value_asdl::value_t* _PerformSlice(value_asdl::value_t* val, int begin, int length, bool has_length, syntax_asdl::BracedVarSub* part, value::Str* arg0_val);
class StringWordEvaluator {
 public:
  StringWordEvaluator();
  virtual value::Str* EvalWordToString(syntax_asdl::word_t* w, int eval_flags = 0);
  
  static constexpr uint32_t field_mask() {
    return kZeroMask;
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(StringWordEvaluator));
  }

  DISALLOW_COPY_AND_ASSIGN(StringWordEvaluator)
};

BigStr* _GetDollarHyphen(optview::Exec* exec_opts);
class TildeEvaluator {
 public:
  TildeEvaluator(state::Mem* mem, optview::Exec* exec_opts);
  BigStr* GetMyHomeDir();
  BigStr* Eval(word_part::TildeSub* part);
  state::Mem* mem;
  optview::Exec* exec_opts;

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassScanned(2, sizeof(TildeEvaluator));
  }

  DISALLOW_COPY_AND_ASSIGN(TildeEvaluator)
};

class AbstractWordEvaluator : public ::word_eval::StringWordEvaluator {
 public:
  AbstractWordEvaluator(state::Mem* mem, optview::Exec* exec_opts, state::MutableOpts* mutable_opts, word_eval::TildeEvaluator* tilde_ev, split::SplitContext* splitter, ui::ErrorFormatter* errfmt);
  virtual void CheckCircularDeps();
  virtual runtime_asdl::part_value_t* _EvalCommandSub(syntax_asdl::CommandSub* cs_part, bool quoted);
  virtual runtime_asdl::part_value_t* _EvalProcessSub(syntax_asdl::CommandSub* cs_part);
  value_asdl::value_t* _EvalVarNum(int var_num);
  value_asdl::value_t* _EvalSpecialVar(int op_id, bool quoted, runtime_asdl::VarSubState* vsub_state);
  bool _ApplyTestOp(value_asdl::value_t* val, suffix_op::Unary* op, bool quoted, List<runtime_asdl::part_value_t*>* part_vals, runtime_asdl::VTestPlace* vtest_place, syntax_asdl::Token* blame_token);
  int _Length(value_asdl::value_t* val, syntax_asdl::Token* token);
  value_asdl::value_t* _Keys(value_asdl::value_t* val, syntax_asdl::Token* token);
  value_asdl::value_t* _EvalVarRef(value_asdl::value_t* val, syntax_asdl::Token* blame_tok, bool quoted, runtime_asdl::VarSubState* vsub_state, runtime_asdl::VTestPlace* vtest_place);
  value_asdl::value_t* _ApplyUnarySuffixOp(value_asdl::value_t* val, suffix_op::Unary* op);
  value_asdl::value_t* _PatSub(value_asdl::value_t* val, suffix_op::PatSub* op);
  value_asdl::value_t* _Slice(value_asdl::value_t* val, suffix_op::Slice* op, BigStr* var_name, syntax_asdl::BracedVarSub* part);
  Tuple2<value::Str*, bool> _Nullary(value_asdl::value_t* val, syntax_asdl::Token* op, BigStr* var_name);
  value_asdl::value_t* _WholeArray(value_asdl::value_t* val, syntax_asdl::BracedVarSub* part, bool quoted, runtime_asdl::VarSubState* vsub_state);
  value_asdl::value_t* _ArrayIndex(value_asdl::value_t* val, syntax_asdl::BracedVarSub* part, runtime_asdl::VTestPlace* vtest_place);
  void _EvalDoubleQuoted(List<syntax_asdl::word_part_t*>* parts, List<runtime_asdl::part_value_t*>* part_vals);
  BigStr* EvalDoubleQuotedToString(syntax_asdl::DoubleQuoted* dq_part);
  value::Str* _DecayArray(value::BashArray* val);
  value_asdl::value_t* _EmptyStrOrError(value_asdl::value_t* val, syntax_asdl::Token* token);
  value_asdl::value_t* _EmptyBashArrayOrError(syntax_asdl::Token* token);
  value_asdl::value_t* _EvalBracketOp(value_asdl::value_t* val, syntax_asdl::BracedVarSub* part, bool quoted, runtime_asdl::VarSubState* vsub_state, runtime_asdl::VTestPlace* vtest_place);
  value_asdl::value_t* _VarRefValue(syntax_asdl::BracedVarSub* part, bool quoted, runtime_asdl::VarSubState* vsub_state, runtime_asdl::VTestPlace* vtest_place);
  void _EvalBracedVarSub(syntax_asdl::BracedVarSub* part, List<runtime_asdl::part_value_t*>* part_vals, bool quoted);
  BigStr* _ConcatPartVals(List<runtime_asdl::part_value_t*>* part_vals, syntax_asdl::loc_t* location);
  BigStr* EvalBracedVarSubToString(syntax_asdl::BracedVarSub* part);
  void _EvalSimpleVarSub(syntax_asdl::SimpleVarSub* part, List<runtime_asdl::part_value_t*>* part_vals, bool quoted);
  BigStr* EvalSimpleVarSubToString(syntax_asdl::SimpleVarSub* node);
  void _EvalExtGlob(word_part::ExtGlob* part, List<runtime_asdl::part_value_t*>* part_vals);
  void _TranslateExtGlob(List<runtime_asdl::part_value_t*>* part_vals, syntax_asdl::CompoundWord* w, List<BigStr*>* glob_parts, List<BigStr*>* fnmatch_parts);
  void _EvalWordPart(syntax_asdl::word_part_t* part, List<runtime_asdl::part_value_t*>* part_vals, int flags);
  void _EvalRhsWordToParts(syntax_asdl::rhs_word_t* w, List<runtime_asdl::part_value_t*>* part_vals, int eval_flags = 0);
  void _EvalWordToParts(syntax_asdl::CompoundWord* w, List<runtime_asdl::part_value_t*>* part_vals, int eval_flags = 0);
  void _PartValsToString(List<runtime_asdl::part_value_t*>* part_vals, syntax_asdl::CompoundWord* w, int eval_flags, List<BigStr*>* strs);
  virtual value::Str* EvalWordToString(syntax_asdl::word_t* UP_w, int eval_flags = 0);
  Tuple2<value::Str*, bool> EvalWordToPattern(syntax_asdl::rhs_word_t* UP_w);
  value::Str* EvalForPlugin(syntax_asdl::CompoundWord* w);
  value_asdl::value_t* EvalRhsWord(syntax_asdl::rhs_word_t* UP_w);
  void _EvalWordFrame(List<runtime_asdl::Piece*>* frame, List<BigStr*>* argv);
  List<BigStr*>* _EvalWordToArgv(syntax_asdl::CompoundWord* w);
  cmd_value::Assign* _EvalAssignBuiltin(int builtin_id, BigStr* arg0, List<syntax_asdl::CompoundWord*>* words, int meta_offset);
  cmd_value::Assign* _DetectAssignBuiltinStr(BigStr* arg0, List<syntax_asdl::CompoundWord*>* words, int meta_offset);
  cmd_value::Assign* _DetectAssignBuiltin(runtime_asdl::part_value_t* val0, List<syntax_asdl::CompoundWord*>* words, int meta_offset);
  runtime_asdl::cmd_value_t* SimpleEvalWordSequence2(List<syntax_asdl::CompoundWord*>* words, bool allow_assign);
  runtime_asdl::cmd_value_t* EvalWordSequence2(List<syntax_asdl::CompoundWord*>* words, bool allow_assign = false);
  List<BigStr*>* EvalWordSequence(List<syntax_asdl::CompoundWord*>* words);

  sh_expr_eval::ArithEvaluator* arith_ev;
  ui::ErrorFormatter* errfmt;
  optview::Exec* exec_opts;
  expr_eval::ExprEvaluator* expr_ev;
  glob_::Globber* globber;
  state::Mem* mem;
  state::MutableOpts* mutable_opts;
  prompt::Evaluator* prompt_ev;
  split::SplitContext* splitter;
  word_eval::TildeEvaluator* tilde_ev;
  sh_expr_eval::UnsafeArith* unsafe_arith;
  
  static constexpr uint32_t field_mask() {
    return ::word_eval::StringWordEvaluator::field_mask()
         | maskbit(offsetof(AbstractWordEvaluator, arith_ev))
         | maskbit(offsetof(AbstractWordEvaluator, errfmt))
         | maskbit(offsetof(AbstractWordEvaluator, exec_opts))
         | maskbit(offsetof(AbstractWordEvaluator, expr_ev))
         | maskbit(offsetof(AbstractWordEvaluator, globber))
         | maskbit(offsetof(AbstractWordEvaluator, mem))
         | maskbit(offsetof(AbstractWordEvaluator, mutable_opts))
         | maskbit(offsetof(AbstractWordEvaluator, prompt_ev))
         | maskbit(offsetof(AbstractWordEvaluator, splitter))
         | maskbit(offsetof(AbstractWordEvaluator, tilde_ev))
         | maskbit(offsetof(AbstractWordEvaluator, unsafe_arith));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(AbstractWordEvaluator));
  }

  DISALLOW_COPY_AND_ASSIGN(AbstractWordEvaluator)
};

class NormalWordEvaluator : public ::word_eval::AbstractWordEvaluator {
 public:
  NormalWordEvaluator(state::Mem* mem, optview::Exec* exec_opts, state::MutableOpts* mutable_opts, word_eval::TildeEvaluator* tilde_ev, split::SplitContext* splitter, ui::ErrorFormatter* errfmt);
  virtual void CheckCircularDeps();
  virtual runtime_asdl::part_value_t* _EvalCommandSub(syntax_asdl::CommandSub* cs_part, bool quoted);
  virtual runtime_asdl::Piece* _EvalProcessSub(syntax_asdl::CommandSub* cs_part);

  vm::_Executor* shell_ex;
  
  static constexpr uint32_t field_mask() {
    return ::word_eval::AbstractWordEvaluator::field_mask()
         | maskbit(offsetof(NormalWordEvaluator, shell_ex));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(NormalWordEvaluator));
  }

  DISALLOW_COPY_AND_ASSIGN(NormalWordEvaluator)
};

extern BigStr* _DUMMY;
class CompletionWordEvaluator : public ::word_eval::AbstractWordEvaluator {
 public:
  CompletionWordEvaluator(state::Mem* mem, optview::Exec* exec_opts, state::MutableOpts* mutable_opts, word_eval::TildeEvaluator* tilde_ev, split::SplitContext* splitter, ui::ErrorFormatter* errfmt);
  virtual void CheckCircularDeps();
  virtual runtime_asdl::part_value_t* _EvalCommandSub(syntax_asdl::CommandSub* cs_part, bool quoted);
  virtual runtime_asdl::Piece* _EvalProcessSub(syntax_asdl::CommandSub* cs_part);
  
  static constexpr uint32_t field_mask() {
    return ::word_eval::AbstractWordEvaluator::field_mask();
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(CompletionWordEvaluator));
  }

  DISALLOW_COPY_AND_ASSIGN(CompletionWordEvaluator)
};


}  // declare namespace word_eval

namespace word_parse {  // declare

using id_kind_asdl::Id;
using types_asdl::lex_mode_e;
using syntax_asdl::loc;
using syntax_asdl::suffix_op;
using syntax_asdl::word_part;
extern List<id_kind_asdl::Kind_t>* KINDS_THAT_END_WORDS;
class WordEmitter {
 public:
  WordEmitter();
  virtual syntax_asdl::word_t* ReadWord(types_asdl::lex_mode_t lex_mode);
  
  static constexpr uint32_t field_mask() {
    return kZeroMask;
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(WordEmitter));
  }

  DISALLOW_COPY_AND_ASSIGN(WordEmitter)
};

class WordParser : public ::word_parse::WordEmitter {
 public:
  WordParser(parse_lib::ParseContext* parse_ctx, lexer::Lexer* lexer, reader::_Reader* line_reader);
  void Init(types_asdl::lex_mode_t lex_mode);
  void Reset();
  void _GetToken();
  void _SetNext(types_asdl::lex_mode_t lex_mode);
  syntax_asdl::rhs_word_t* _ReadVarOpArg(types_asdl::lex_mode_t arg_lex_mode);
  syntax_asdl::CompoundWord* _ReadVarOpArg2(types_asdl::lex_mode_t arg_lex_mode, int eof_type, bool empty_ok);
  suffix_op::Slice* _ReadSliceVarOp();
  suffix_op::PatSub* _ReadPatSubVarOp();
  syntax_asdl::bracket_op_t* _ReadSubscript();
  syntax_asdl::BracedVarSub* _ParseVarOf();
  syntax_asdl::BracedVarSub* _ParseVarExpr(types_asdl::lex_mode_t arg_lex_mode, bool allow_query = false);
  word_part::ZshVarSub* _ReadZshVarSub(syntax_asdl::Token* left_token);
  Tuple2<syntax_asdl::BracedVarSub*, syntax_asdl::Token*> ReadBracedVarSub(syntax_asdl::Token* left_token);
  syntax_asdl::BracedVarSub* _ReadBracedVarSub(syntax_asdl::Token* left_token, bool d_quoted);
  syntax_asdl::SingleQuoted* _ReadSingleQuoted(syntax_asdl::Token* left_token, types_asdl::lex_mode_t lex_mode);
  syntax_asdl::Token* ReadSingleQuoted(types_asdl::lex_mode_t lex_mode, syntax_asdl::Token* left_token, List<syntax_asdl::Token*>* out_tokens, bool is_ysh_expr);
  syntax_asdl::word_part_t* _ReadDoubleQuotedLeftParts();
  syntax_asdl::CompoundWord* _ReadYshSingleQuoted(int left_id);
  syntax_asdl::word_part_t* _ReadUnquotedLeftParts(syntax_asdl::BoolParamBox* triple_out);
  word_part::ExtGlob* _ReadExtGlob();
  word_part::BashRegexGroup* _ReadBashRegexGroup();
  void _ReadLikeDQ(syntax_asdl::Token* left_token, bool is_ysh_expr, List<syntax_asdl::word_part_t*>* out_parts);
  syntax_asdl::DoubleQuoted* _ReadDoubleQuoted(syntax_asdl::Token* left_token);
  syntax_asdl::Token* ReadDoubleQuoted(syntax_asdl::Token* left_token, List<syntax_asdl::word_part_t*>* parts);
  syntax_asdl::CommandSub* _ReadCommandSub(int left_id, bool d_quoted = false);
  word_part::ExprSub* _ReadExprSub(types_asdl::lex_mode_t lex_mode);
  command::VarDecl* ParseVarDecl(syntax_asdl::Token* kw_token);
  command::Mutation* ParseMutation(syntax_asdl::Token* kw_token, cmd_parse::VarChecker* var_checker);
  syntax_asdl::expr_t* ParseBareDecl();
  syntax_asdl::expr_t* ParseYshExprForCommand();
  syntax_asdl::expr_t* ParseCommandExpr();
  void ParseProc(syntax_asdl::Proc* node);
  void ParseFunc(syntax_asdl::Func* node);
  Tuple2<syntax_asdl::pat_t*, syntax_asdl::Token*> ParseYshCasePattern();
  int NewlineOkForYshCase();
  syntax_asdl::arith_expr_t* _ReadArithExpr(int end_id);
  word_part::ArithSub* _ReadArithSub();
  Tuple2<syntax_asdl::arith_expr_t*, syntax_asdl::Token*> ReadDParen();
  void _NextNonSpace();
  command::ForExpr* ReadForExpression();
  syntax_asdl::word_part_t* _ReadArrayLiteral();
  syntax_asdl::ArgList* ParseProcCallArgs(int start_symbol);
  bool _MaybeReadWordPart(bool is_first, types_asdl::lex_mode_t lex_mode, List<syntax_asdl::word_part_t*>* parts);
  syntax_asdl::CompoundWord* _ReadCompoundWord(types_asdl::lex_mode_t lex_mode);
  syntax_asdl::CompoundWord* _ReadCompoundWord3(types_asdl::lex_mode_t lex_mode, int eof_type, bool empty_ok);
  syntax_asdl::word_t* _ReadArithWord();
  syntax_asdl::word_t* _ReadWord(types_asdl::lex_mode_t word_mode);
  syntax_asdl::BracedVarSub* ParseVarRef();
  int LookPastSpace();
  bool LookAheadFuncParens();
  virtual syntax_asdl::word_t* ReadWord(types_asdl::lex_mode_t word_mode);
  syntax_asdl::word_t* ReadArithWord();
  void ReadHereDocBody(List<syntax_asdl::word_part_t*>* parts);
  syntax_asdl::CompoundWord* ReadForPlugin();
  void EmitDocToken(bool b);
  void Multiline(bool b);

  tdop::TdopParser* a_parser;
  alloc::Arena* arena;
  syntax_asdl::word_t* buffered_word;
  syntax_asdl::Token* cur_token;
  bool emit_doc_token;
  lexer::Lexer* lexer;
  reader::_Reader* line_reader;
  bool multiline;
  int newline_state;
  types_asdl::lex_mode_t next_lex_mode;
  parse_lib::ParseContext* parse_ctx;
  optview::Parse* parse_opts;
  bool returned_newline;
  id_kind_asdl::Kind_t token_kind;
  int token_type;
  
  static constexpr uint32_t field_mask() {
    return ::word_parse::WordEmitter::field_mask()
         | maskbit(offsetof(WordParser, a_parser))
         | maskbit(offsetof(WordParser, arena))
         | maskbit(offsetof(WordParser, buffered_word))
         | maskbit(offsetof(WordParser, cur_token))
         | maskbit(offsetof(WordParser, lexer))
         | maskbit(offsetof(WordParser, line_reader))
         | maskbit(offsetof(WordParser, parse_ctx))
         | maskbit(offsetof(WordParser, parse_opts));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(WordParser));
  }

  DISALLOW_COPY_AND_ASSIGN(WordParser)
};


}  // declare namespace word_parse

namespace parse {  // declare

extern int NT_OFFSET;
class ParseError {
 public:
  ParseError(BigStr* msg, int type_, syntax_asdl::Token* tok);
  BigStr* msg;
  syntax_asdl::Token* tok;
  int type;

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassScanned(2, sizeof(ParseError));
  }

  DISALLOW_COPY_AND_ASSIGN(ParseError)
};

class _StackItem {
 public:
  _StackItem(Tuple2<List<List<Tuple2<int, int>*>*>*, Dict<int, int>*>* dfa, int state, pnode::PNode* node);
  Tuple2<List<List<Tuple2<int, int>*>*>*, Dict<int, int>*>* dfa;
  pnode::PNode* node;
  int state;

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassScanned(2, sizeof(_StackItem));
  }

  DISALLOW_COPY_AND_ASSIGN(_StackItem)
};

class Parser {
 public:
  Parser(grammar::Grammar* grammar);
  void setup(int start, pnode::PNodeAllocator* pnode_alloc);
  bool addtoken(int typ, syntax_asdl::Token* opaque, int ilabel);
  void shift(int typ, syntax_asdl::Token* opaque, int newstate);
  void push(int typ, syntax_asdl::Token* opaque, Tuple2<List<List<Tuple2<int, int>*>*>*, Dict<int, int>*>* newdfa, int newstate);
  void pop();
  grammar::Grammar* grammar;
  pnode::PNode* rootnode;
  List<parse::_StackItem*>* stack;
  pnode::PNodeAllocator* pnode_alloc;

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassScanned(4, sizeof(Parser));
  }

  DISALLOW_COPY_AND_ASSIGN(Parser)
};


}  // declare namespace parse

namespace cgi {  // declare

BigStr* escape(BigStr* s);

}  // declare namespace cgi

namespace os_path {  // declare

extern BigStr* extsep;
extern BigStr* sep;
BigStr* join(BigStr* s1, BigStr* s2);
Tuple2<BigStr*, BigStr*> split(BigStr* p);
Tuple2<BigStr*, BigStr*> _splitext(BigStr* p, BigStr* sep, BigStr* extsep);
Tuple2<BigStr*, BigStr*> splitext(BigStr* p);
BigStr* basename(BigStr* p);
BigStr* dirname(BigStr* p);
BigStr* normpath(BigStr* path);
bool isabs(BigStr* s);
BigStr* abspath(BigStr* path);

}  // declare namespace os_path

namespace fmt {  // declare

void Format(alloc::Arena* arena, syntax_asdl::command_t* node);

}  // declare namespace fmt

namespace ysh_ify {  // declare

using id_kind_asdl::Id;
using syntax_asdl::loc;
using syntax_asdl::word_part;
class Cursor {
 public:
  Cursor(alloc::Arena* arena, mylib::Writer* f);
  void _PrintUntilSpid(int until_span_id);
  void _SkipUntilSpid(int next_span_id);
  void SkipUntil(syntax_asdl::Token* tok);
  void SkipPast(syntax_asdl::Token* tok);
  void PrintUntil(syntax_asdl::Token* tok);
  void PrintIncluding(syntax_asdl::Token* tok);
  void PrintUntilEnd();
  alloc::Arena* arena;
  mylib::Writer* f;
  int next_span_id;

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassScanned(2, sizeof(Cursor));
  }

  DISALLOW_COPY_AND_ASSIGN(Cursor)
};

void LosslessCat(alloc::Arena* arena);
void PrintTokens(alloc::Arena* arena);
void Ysh_ify(alloc::Arena* arena, syntax_asdl::command_t* node);
runtime_asdl::word_style_t _GetRhsStyle(syntax_asdl::rhs_word_t* w);
class YshPrinter {
 public:
  YshPrinter(ysh_ify::Cursor* cursor, alloc::Arena* arena, mylib::Writer* f);
  void _DebugSpid(int spid);
  void End();
  void DoRedirect(syntax_asdl::Redir* node, Dict<BigStr*, bool>* local_symbols);
  void DoShAssignment(command::ShAssignment* node, bool at_top_level, Dict<BigStr*, bool>* local_symbols);
  void _DoSimple(command::Simple* node, Dict<BigStr*, bool>* local_symbols);
  void DoCommand(syntax_asdl::command_t* node, Dict<BigStr*, bool>* local_symbols, bool at_top_level = false);
  void DoRhsWord(syntax_asdl::rhs_word_t* node, Dict<BigStr*, bool>* local_symbols);
  void DoWordInCommand(syntax_asdl::word_t* node, Dict<BigStr*, bool>* local_symbols);
  void DoWordPart(syntax_asdl::word_part_t* node, Dict<BigStr*, bool>* local_symbols, bool quoted = false);
  ysh_ify::Cursor* cursor;
  alloc::Arena* arena;
  mylib::Writer* f;

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassScanned(3, sizeof(YshPrinter));
  }

  DISALLOW_COPY_AND_ASSIGN(YshPrinter)
};


}  // declare namespace ysh_ify

namespace expr_eval {  // declare

using id_kind_asdl::Id;
using syntax_asdl::loc;
using syntax_asdl::word_part;
using runtime_asdl::scope_e;
using runtime_asdl::part_value;
value_asdl::value_t* LookupVar(state::Mem* mem, BigStr* var_name, runtime_asdl::scope_t which_scopes, syntax_asdl::loc_t* var_loc);
mops::BigInt _ConvertToInt(value_asdl::value_t* val, BigStr* msg, syntax_asdl::loc_t* blame_loc);
Tuple3<runtime_asdl::coerced_t, mops::BigInt, double> _ConvertToNumber(value_asdl::value_t* val);
Tuple5<runtime_asdl::coerced_t, mops::BigInt, mops::BigInt, double, double> _ConvertForBinaryOp(value_asdl::value_t* left, value_asdl::value_t* right);
class ExprEvaluator {
 public:
  ExprEvaluator(state::Mem* mem, state::MutableOpts* mutable_opts, Dict<int, Dict<BigStr*, vm::_Callable*>*>* methods, split::SplitContext* splitter, ui::ErrorFormatter* errfmt);
  void CheckCircularDeps();
  value_asdl::value_t* _LookupVar(BigStr* name, syntax_asdl::loc_t* var_loc);
  void EvalAugmented(value_asdl::y_lvalue_t* lval, value_asdl::value_t* rhs_val, syntax_asdl::Token* op, runtime_asdl::scope_t which_scopes);
  value_asdl::value_t* _EvalLeftLocalOrGlobal(syntax_asdl::expr_t* lhs, runtime_asdl::scope_t which_scopes);
  value_asdl::y_lvalue_t* _EvalLhsExpr(syntax_asdl::y_lhs_t* lhs, runtime_asdl::scope_t which_scopes);
  value_asdl::value_t* EvalExpr(syntax_asdl::expr_t* node, syntax_asdl::loc_t* blame_loc);
  value_asdl::y_lvalue_t* EvalLhsExpr(syntax_asdl::y_lhs_t* lhs, runtime_asdl::scope_t which_scopes);
  runtime_asdl::part_value_t* EvalExprSub(word_part::ExprSub* part);
  value_asdl::value_t* PluginCall(value::Func* func_val, List<value_asdl::value_t*>* pos_args);
  value_asdl::value_t* CallConvertFunc(value_asdl::value_t* func_val, value_asdl::value_t* arg, syntax_asdl::Token* convert_tok, syntax_asdl::loc_t* call_loc);
  List<BigStr*>* SpliceValue(value_asdl::value_t* val, word_part::Splice* part);
  value_asdl::value_t* _EvalConst(expr::Const* node);
  value_asdl::value_t* _EvalUnary(expr::Unary* node);
  value_asdl::value_t* _ArithIntFloat(value_asdl::value_t* left, value_asdl::value_t* right, syntax_asdl::Token* op);
  value_asdl::value_t* _ArithIntOnly(value_asdl::value_t* left, value_asdl::value_t* right, syntax_asdl::Token* op);
  value_asdl::value_t* _Concat(value_asdl::value_t* left, value_asdl::value_t* right, syntax_asdl::Token* op);
  value_asdl::value_t* _EvalBinary(expr::Binary* node);
  bool _CompareNumeric(value_asdl::value_t* left, value_asdl::value_t* right, syntax_asdl::Token* op);
  value_asdl::value_t* _EvalCompare(expr::Compare* node);
  value_asdl::value_t* _CallFunc(value_asdl::value_t* to_call, typed_args::Reader* rd);
  value_asdl::value_t* _EvalFuncCall(expr::FuncCall* node);
  value_asdl::value_t* _EvalSubscript(value_asdl::value_t* obj, value_asdl::value_t* index);
  value_asdl::value_t* _EvalDot(syntax_asdl::Attribute* node, value_asdl::value_t* obj);
  value_asdl::value_t* _EvalAttribute(syntax_asdl::Attribute* node);
  value_asdl::value_t* _EvalExpr(syntax_asdl::expr_t* node);
  value::Eggex* EvalEggex(syntax_asdl::Eggex* node);
  vm::_Executor* shell_ex;
  cmd_eval::CommandEvaluator* cmd_ev;
  word_eval::AbstractWordEvaluator* word_ev;
  state::Mem* mem;
  state::MutableOpts* mutable_opts;
  Dict<int, Dict<BigStr*, vm::_Callable*>*>* methods;
  split::SplitContext* splitter;
  ui::ErrorFormatter* errfmt;

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassScanned(8, sizeof(ExprEvaluator));
  }

  DISALLOW_COPY_AND_ASSIGN(ExprEvaluator)
};

class EggexEvaluator {
 public:
  EggexEvaluator(state::Mem* mem, BigStr* canonical_flags);
  value_asdl::value_t* _LookupVar(BigStr* name, syntax_asdl::loc_t* var_loc);
  void _EvalClassLiteralTerm(syntax_asdl::class_literal_term_t* term, List<syntax_asdl::char_class_term_t*>* out);
  syntax_asdl::re_t* EvalE(syntax_asdl::re_t* node);
  state::Mem* mem;
  BigStr* canonical_flags;
  List<value_asdl::value_t*>* convert_funcs;
  List<syntax_asdl::Token*>* convert_toks;

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassScanned(4, sizeof(EggexEvaluator));
  }

  DISALLOW_COPY_AND_ASSIGN(EggexEvaluator)
};


}  // declare namespace expr_eval

namespace expr_parse {  // declare

using syntax_asdl::loc;
using id_kind_asdl::Id;
using types_asdl::lex_mode_e;
int _Classify(grammar::Grammar* gr, syntax_asdl::Token* tok);
extern Dict<int, int>* _OTHER_BALANCE;
syntax_asdl::Token* _PushYshTokens(parse_lib::ParseContext* parse_ctx, grammar::Grammar* gr, parse::Parser* p, lexer::Lexer* lex);
class ExprParser {
 public:
  ExprParser(parse_lib::ParseContext* parse_ctx, grammar::Grammar* gr);
  Tuple2<pnode::PNode*, syntax_asdl::Token*> Parse(lexer::Lexer* lexer, int start_symbol);
  parse_lib::ParseContext* parse_ctx;
  grammar::Grammar* gr;
  parse::Parser* push_parser;
  pnode::PNodeAllocator* pnode_alloc;

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassScanned(4, sizeof(ExprParser));
  }

  DISALLOW_COPY_AND_ASSIGN(ExprParser)
};

class ctx_PNodeAllocator {
 public:
  ctx_PNodeAllocator(expr_parse::ExprParser* ep);
  ~ctx_PNodeAllocator();
  expr_parse::ExprParser* expr_parser;

  DISALLOW_COPY_AND_ASSIGN(ctx_PNodeAllocator)
};


}  // declare namespace expr_parse

namespace expr_to_ast {  // declare

using id_kind_asdl::Id;
using syntax_asdl::loc;
extern Dict<BigStr*, BigStr*>* PERL_CLASSES;
extern List<BigStr*>* POSIX_CLASSES;
extern BigStr* RANGE_POINT_TOO_LONG;
extern BigStr* POS_ARG_MISPLACED;
extern int NT_OFFSET;
class Transformer {
 public:
  Transformer(grammar::Grammar* gr);
  syntax_asdl::expr_t* _LeftAssoc(pnode::PNode* p_node);
  syntax_asdl::expr_t* _Trailer(syntax_asdl::expr_t* base, pnode::PNode* p_trailer);
  Tuple2<syntax_asdl::expr_t*, syntax_asdl::expr_t*> _DictPair(pnode::PNode* p_node);
  expr::Dict* _Dict(pnode::PNode* parent, pnode::PNode* p_node);
  syntax_asdl::expr_t* _Tuple(pnode::PNode* parent);
  syntax_asdl::expr_t* _TestlistComp(pnode::PNode* parent, pnode::PNode* p_node, int id0);
  syntax_asdl::expr_t* _Atom(pnode::PNode* parent);
  syntax_asdl::NameType* _NameType(pnode::PNode* p_node);
  List<syntax_asdl::NameType*>* _NameTypeList(pnode::PNode* p_node);
  syntax_asdl::Comprehension* _CompFor(pnode::PNode* p_node);
  syntax_asdl::expr_t* _CompareChain(pnode::PNode* parent);
  syntax_asdl::expr_t* _Subscript(pnode::PNode* parent);
  syntax_asdl::expr_t* Expr(pnode::PNode* pnode);
  void _CheckLhs(syntax_asdl::expr_t* lhs);
  List<syntax_asdl::y_lhs_t*>* _LhsExprList(pnode::PNode* p_node);
  command::VarDecl* MakeVarDecl(pnode::PNode* p_node);
  command::Mutation* MakeMutation(pnode::PNode* p_node);
  syntax_asdl::EggexFlag* _EggexFlag(pnode::PNode* p_node);
  syntax_asdl::Eggex* _Eggex(pnode::PNode* p_node);
  syntax_asdl::pat_t* YshCasePattern(pnode::PNode* pnode);
  syntax_asdl::expr_t* _BlockArg(pnode::PNode* p_node);
  void _Argument(pnode::PNode* p_node, bool after_semi, syntax_asdl::ArgList* arglist);
  void _ArgGroup(pnode::PNode* p_node, bool after_semi, syntax_asdl::ArgList* arglist);
  void _ArgList(pnode::PNode* p_node, syntax_asdl::ArgList* arglist);
  void ProcCallArgs(pnode::PNode* pnode, syntax_asdl::ArgList* arglist);
  syntax_asdl::TypeExpr* _TypeExpr(pnode::PNode* pnode);
  syntax_asdl::Param* _Param(pnode::PNode* pnode);
  syntax_asdl::ParamGroup* _ParamGroup(pnode::PNode* p_node);
  syntax_asdl::proc_sig_t* Proc(pnode::PNode* p_node);
  void YshFunc(pnode::PNode* p_node, syntax_asdl::Func* out);
  syntax_asdl::CharCode* _RangeCharSingleQuoted(pnode::PNode* p_node);
  syntax_asdl::Token* _OtherRangeToken(pnode::PNode* p_node);
  syntax_asdl::class_literal_term_t* _NonRangeChars(pnode::PNode* p_node);
  syntax_asdl::class_literal_term_t* _ClassLiteralTerm(pnode::PNode* p_node);
  List<syntax_asdl::class_literal_term_t*>* _ClassLiteral(pnode::PNode* p_node);
  syntax_asdl::re_t* _NameInRegex(syntax_asdl::Token* negated_tok, syntax_asdl::Token* tok);
  syntax_asdl::class_literal_term_t* _NameInClass(syntax_asdl::Token* negated_tok, syntax_asdl::Token* tok);
  syntax_asdl::re_t* _ReAtom(pnode::PNode* p_atom);
  syntax_asdl::re_repeat_t* _RepeatOp(pnode::PNode* p_repeat);
  syntax_asdl::re_t* _ReAlt(pnode::PNode* p_node);
  syntax_asdl::re_t* _Regex(pnode::PNode* p_node);
  Dict<int, BigStr*>* number2symbol;

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassScanned(1, sizeof(Transformer));
  }

  DISALLOW_COPY_AND_ASSIGN(Transformer)
};


}  // declare namespace expr_to_ast

namespace func_proc {  // declare

using id_kind_asdl::Id;
using runtime_asdl::cmd_value;
using syntax_asdl::loc;
void _DisallowMutableDefault(value_asdl::value_t* val, syntax_asdl::loc_t* blame_loc);
List<value_asdl::value_t*>* _EvalPosDefaults(expr_eval::ExprEvaluator* expr_ev, List<syntax_asdl::Param*>* pos_params);
Dict<BigStr*, value_asdl::value_t*>* _EvalNamedDefaults(expr_eval::ExprEvaluator* expr_ev, List<syntax_asdl::Param*>* named_params);
Tuple2<List<value_asdl::value_t*>*, Dict<BigStr*, value_asdl::value_t*>*> EvalFuncDefaults(expr_eval::ExprEvaluator* expr_ev, syntax_asdl::Func* func);
value_asdl::ProcDefaults* EvalProcDefaults(expr_eval::ExprEvaluator* expr_ev, proc_sig::Closed* sig);
void _EvalPosArgs(expr_eval::ExprEvaluator* expr_ev, List<syntax_asdl::expr_t*>* exprs, List<value_asdl::value_t*>* pos_args);
Dict<BigStr*, value_asdl::value_t*>* _EvalNamedArgs(expr_eval::ExprEvaluator* expr_ev, List<syntax_asdl::NamedArg*>* named_exprs);
Tuple2<List<value_asdl::value_t*>*, Dict<BigStr*, value_asdl::value_t*>*> _EvalArgList(expr_eval::ExprEvaluator* expr_ev, syntax_asdl::ArgList* args, value_asdl::value_t* me = nullptr);
void EvalTypedArgsToProc(expr_eval::ExprEvaluator* expr_ev, state::MutableOpts* mutable_opts, command::Simple* node, cmd_value::Argv* cmd_val);
void _BindWords(BigStr* proc_name, syntax_asdl::ParamGroup* group, List<value_asdl::value_t*>* defaults, cmd_value::Argv* cmd_val, state::Mem* mem, syntax_asdl::loc_t* blame_loc);
void _BindTyped(BigStr* code_name, syntax_asdl::ParamGroup* group, List<value_asdl::value_t*>* defaults, List<value_asdl::value_t*>* pos_args, state::Mem* mem, syntax_asdl::loc_t* blame_loc);
void _BindNamed(BigStr* code_name, syntax_asdl::ParamGroup* group, Dict<BigStr*, value_asdl::value_t*>* defaults, Dict<BigStr*, value_asdl::value_t*>* named_args, state::Mem* mem, syntax_asdl::loc_t* blame_loc);
void _BindFuncArgs(value::Func* func, typed_args::Reader* rd, state::Mem* mem);
void BindProcArgs(value::Proc* proc, cmd_value::Argv* cmd_val, state::Mem* mem);
value_asdl::value_t* CallUserFunc(value::Func* func, typed_args::Reader* rd, state::Mem* mem, cmd_eval::CommandEvaluator* cmd_ev);

}  // declare namespace func_proc

namespace regex_translate {  // declare

using id_kind_asdl::Id;
extern Dict<BigStr*, BigStr*>* PERL_CLASS;
extern int CH_RBRACKET;
extern int CH_BACKSLASH;
extern int CH_CARET;
extern int CH_HYPHEN;
extern int FLAG_RBRACKET;
extern int FLAG_BACKSLASH;
extern int FLAG_CARET;
extern int FLAG_HYPHEN;
void _CharCodeToEre(syntax_asdl::CharCode* term, List<BigStr*>* parts, List<int>* special_char_flags);
void _CharClassTermToEre(syntax_asdl::char_class_term_t* term, List<BigStr*>* parts, List<int>* special_char_flags);
void _AsPosixEre(syntax_asdl::re_t* node, List<BigStr*>* parts, List<BigStr*>* capture_names);
BigStr* AsPosixEre(value::Eggex* eggex);
BigStr* CanonicalFlags(List<syntax_asdl::EggexFlag*>* flags);
int LibcFlags(BigStr* canonical_flags);

}  // declare namespace regex_translate

namespace val_ops {  // declare

using syntax_asdl::loc;
int ToInt(value_asdl::value_t* val, BigStr* msg, syntax_asdl::loc_t* blame_loc);
double ToFloat(value_asdl::value_t* val, BigStr* msg, syntax_asdl::loc_t* blame_loc);
BigStr* ToStr(value_asdl::value_t* val, BigStr* msg, syntax_asdl::loc_t* blame_loc);
List<value_asdl::value_t*>* ToList(value_asdl::value_t* val, BigStr* msg, syntax_asdl::loc_t* blame_loc);
Dict<BigStr*, value_asdl::value_t*>* ToDict(value_asdl::value_t* val, BigStr* msg, syntax_asdl::loc_t* blame_loc);
syntax_asdl::command_t* ToCommand(value_asdl::value_t* val, BigStr* msg, syntax_asdl::loc_t* blame_loc);
BigStr* Stringify(value_asdl::value_t* val, syntax_asdl::loc_t* blame_loc, BigStr* prefix = str2200);
List<BigStr*>* ToShellArray(value_asdl::value_t* val, syntax_asdl::loc_t* blame_loc, BigStr* prefix = str2206);
class Iterator {
 public:
  Iterator();
  int Index();
  void Next();
  virtual value_asdl::value_t* FirstValue();
  virtual value_asdl::value_t* SecondValue();
  int i;
  
  static constexpr uint32_t field_mask() {
    return kZeroMask;
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(Iterator));
  }

  DISALLOW_COPY_AND_ASSIGN(Iterator)
};

class StdinIterator : public ::val_ops::Iterator {
 public:
  StdinIterator(syntax_asdl::loc_t* blame_loc);
  virtual value_asdl::value_t* FirstValue();

  syntax_asdl::loc_t* blame_loc;
  mylib::LineReader* f;
  
  static constexpr uint32_t field_mask() {
    return ::val_ops::Iterator::field_mask()
         | maskbit(offsetof(StdinIterator, blame_loc))
         | maskbit(offsetof(StdinIterator, f));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(StdinIterator));
  }

  DISALLOW_COPY_AND_ASSIGN(StdinIterator)
};

class ArrayIter : public ::val_ops::Iterator {
 public:
  ArrayIter(List<BigStr*>* strs);
  virtual value_asdl::value_t* FirstValue();

  int n;
  List<BigStr*>* strs;
  
  static constexpr uint32_t field_mask() {
    return ::val_ops::Iterator::field_mask()
         | maskbit(offsetof(ArrayIter, strs));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(ArrayIter));
  }

  DISALLOW_COPY_AND_ASSIGN(ArrayIter)
};

class RangeIterator : public ::val_ops::Iterator {
 public:
  RangeIterator(value::Range* val);
  virtual value_asdl::value_t* FirstValue();

  value::Range* val;
  
  static constexpr uint32_t field_mask() {
    return ::val_ops::Iterator::field_mask()
         | maskbit(offsetof(RangeIterator, val));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(RangeIterator));
  }

  DISALLOW_COPY_AND_ASSIGN(RangeIterator)
};

class ListIterator : public ::val_ops::Iterator {
 public:
  ListIterator(value::List* val);
  virtual value_asdl::value_t* FirstValue();

  int n;
  value::List* val;
  
  static constexpr uint32_t field_mask() {
    return ::val_ops::Iterator::field_mask()
         | maskbit(offsetof(ListIterator, val));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(ListIterator));
  }

  DISALLOW_COPY_AND_ASSIGN(ListIterator)
};

class DictIterator : public ::val_ops::Iterator {
 public:
  DictIterator(value::Dict* val);
  virtual value_asdl::value_t* FirstValue();
  virtual value_asdl::value_t* SecondValue();

  List<BigStr*>* keys;
  int n;
  List<value_asdl::value_t*>* values;
  
  static constexpr uint32_t field_mask() {
    return ::val_ops::Iterator::field_mask()
         | maskbit(offsetof(DictIterator, keys))
         | maskbit(offsetof(DictIterator, values));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(DictIterator));
  }

  DISALLOW_COPY_AND_ASSIGN(DictIterator)
};

bool ToBool(value_asdl::value_t* val);
bool ExactlyEqual(value_asdl::value_t* left, value_asdl::value_t* right, syntax_asdl::loc_t* blame_loc);
bool Contains(value_asdl::value_t* needle, value_asdl::value_t* haystack);
bool MatchRegex(value_asdl::value_t* left, value_asdl::value_t* right, state::Mem* mem);

}  // declare namespace val_ops

namespace bracket_osh {  // declare

using id_kind_asdl::Id;
using syntax_asdl::loc;
using syntax_asdl::word;
using types_asdl::lex_mode_e;
class _StringWordEmitter : public ::word_parse::WordEmitter {
 public:
  _StringWordEmitter(cmd_value::Argv* cmd_val);
  virtual word::String* ReadWord(types_asdl::lex_mode_t unused_lex_mode);
  word::String* Read();
  BigStr* Peek(int offset);
  void Rewind(int offset);

  cmd_value::Argv* cmd_val;
  int i;
  int n;
  
  static constexpr uint32_t field_mask() {
    return ::word_parse::WordEmitter::field_mask()
         | maskbit(offsetof(_StringWordEmitter, cmd_val));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(_StringWordEmitter));
  }

  DISALLOW_COPY_AND_ASSIGN(_StringWordEmitter)
};

class _WordEvaluator : public ::word_eval::StringWordEvaluator {
 public:
  _WordEvaluator();
  virtual value::Str* EvalWordToString(syntax_asdl::word_t* w, int eval_flags = 0);
  
  static constexpr uint32_t field_mask() {
    return ::word_eval::StringWordEvaluator::field_mask();
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(_WordEvaluator));
  }

  DISALLOW_COPY_AND_ASSIGN(_WordEvaluator)
};

syntax_asdl::bool_expr_t* _TwoArgs(bracket_osh::_StringWordEmitter* w_parser);
syntax_asdl::bool_expr_t* _ThreeArgs(bracket_osh::_StringWordEmitter* w_parser);
class Test : public ::vm::_Builtin {
 public:
  Test(bool need_right_bracket, optview::Exec* exec_opts, state::Mem* mem, ui::ErrorFormatter* errfmt);
  virtual int Run(cmd_value::Argv* cmd_val);

  ui::ErrorFormatter* errfmt;
  optview::Exec* exec_opts;
  state::Mem* mem;
  bool need_right_bracket;
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Builtin::field_mask()
         | maskbit(offsetof(Test, errfmt))
         | maskbit(offsetof(Test, exec_opts))
         | maskbit(offsetof(Test, mem));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(Test));
  }

  DISALLOW_COPY_AND_ASSIGN(Test)
};


}  // declare namespace bracket_osh

namespace completion_osh {  // declare

using syntax_asdl::loc;
class _FixedWordsAction : public ::completion::CompletionAction {
 public:
  _FixedWordsAction(List<BigStr*>* d);
  virtual void Matches(completion::Api* comp, List<BigStr*>* _out_yield_acc);
  virtual void Print(mylib::BufWriter* f);

  List<BigStr*>* d;
  
  static constexpr uint32_t field_mask() {
    return ::completion::CompletionAction::field_mask()
         | maskbit(offsetof(_FixedWordsAction, d));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(_FixedWordsAction));
  }

  DISALLOW_COPY_AND_ASSIGN(_FixedWordsAction)
};

class _DynamicProcDictAction : public ::completion::CompletionAction {
 public:
  _DynamicProcDictAction(Dict<BigStr*, value::Proc*>* d);
  virtual void Matches(completion::Api* comp, List<BigStr*>* _out_yield_acc);
  virtual void Print(mylib::BufWriter* f);

  Dict<BigStr*, value::Proc*>* d;
  
  static constexpr uint32_t field_mask() {
    return ::completion::CompletionAction::field_mask()
         | maskbit(offsetof(_DynamicProcDictAction, d));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(_DynamicProcDictAction));
  }

  DISALLOW_COPY_AND_ASSIGN(_DynamicProcDictAction)
};

class _DynamicStrDictAction : public ::completion::CompletionAction {
 public:
  _DynamicStrDictAction(Dict<BigStr*, BigStr*>* d);
  virtual void Matches(completion::Api* comp, List<BigStr*>* _out_yield_acc);
  virtual void Print(mylib::BufWriter* f);

  Dict<BigStr*, BigStr*>* d;
  
  static constexpr uint32_t field_mask() {
    return ::completion::CompletionAction::field_mask()
         | maskbit(offsetof(_DynamicStrDictAction, d));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(_DynamicStrDictAction));
  }

  DISALLOW_COPY_AND_ASSIGN(_DynamicStrDictAction)
};

class SpecBuilder {
 public:
  SpecBuilder(cmd_eval::CommandEvaluator* cmd_ev, parse_lib::ParseContext* parse_ctx, word_eval::NormalWordEvaluator* word_ev, split::SplitContext* splitter, completion::Lookup* comp_lookup, Dict<BigStr*, BigStr*>* help_data, ui::ErrorFormatter* errfmt);
  completion::UserSpec* Build(List<BigStr*>* argv, args::_Attributes* attrs, Dict<BigStr*, bool>* base_opts);
  cmd_eval::CommandEvaluator* cmd_ev;
  parse_lib::ParseContext* parse_ctx;
  word_eval::NormalWordEvaluator* word_ev;
  split::SplitContext* splitter;
  completion::Lookup* comp_lookup;
  Dict<BigStr*, BigStr*>* help_data;
  List<BigStr*>* topic_list;
  ui::ErrorFormatter* errfmt;

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassScanned(8, sizeof(SpecBuilder));
  }

  DISALLOW_COPY_AND_ASSIGN(SpecBuilder)
};

class Complete : public ::vm::_Builtin {
 public:
  Complete(completion_osh::SpecBuilder* spec_builder, completion::Lookup* comp_lookup);
  virtual int Run(cmd_value::Argv* cmd_val);

  completion::Lookup* comp_lookup;
  completion_osh::SpecBuilder* spec_builder;
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Builtin::field_mask()
         | maskbit(offsetof(Complete, comp_lookup))
         | maskbit(offsetof(Complete, spec_builder));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(Complete));
  }

  DISALLOW_COPY_AND_ASSIGN(Complete)
};

class CompGen : public ::vm::_Builtin {
 public:
  CompGen(completion_osh::SpecBuilder* spec_builder);
  virtual int Run(cmd_value::Argv* cmd_val);

  completion_osh::SpecBuilder* spec_builder;
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Builtin::field_mask()
         | maskbit(offsetof(CompGen, spec_builder));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(CompGen));
  }

  DISALLOW_COPY_AND_ASSIGN(CompGen)
};

class CompOpt : public ::vm::_Builtin {
 public:
  CompOpt(completion::OptionState* comp_state, ui::ErrorFormatter* errfmt);
  virtual int Run(cmd_value::Argv* cmd_val);

  completion::OptionState* comp_state;
  ui::ErrorFormatter* errfmt;
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Builtin::field_mask()
         | maskbit(offsetof(CompOpt, comp_state))
         | maskbit(offsetof(CompOpt, errfmt));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(CompOpt));
  }

  DISALLOW_COPY_AND_ASSIGN(CompOpt)
};

class CompAdjust : public ::vm::_Builtin {
 public:
  CompAdjust(state::Mem* mem);
  virtual int Run(cmd_value::Argv* cmd_val);

  state::Mem* mem;
  
  static constexpr uint32_t field_mask() {
    return ::vm::_Builtin::field_mask()
         | maskbit(offsetof(CompAdjust, mem));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(CompAdjust));
  }

  DISALLOW_COPY_AND_ASSIGN(CompAdjust)
};


}  // declare namespace completion_osh

namespace shell {  // declare

using runtime_asdl::scope_e;
using syntax_asdl::loc;
void _InitDefaultCompletions(cmd_eval::CommandEvaluator* cmd_ev, completion_osh::Complete* complete_builtin, completion::Lookup* comp_lookup);
void _CompletionDemo(completion::Lookup* comp_lookup);
void SourceStartupFile(process::FdState* fd_state, BigStr* rc_path, BigStr* lang, parse_lib::ParseContext* parse_ctx, cmd_eval::CommandEvaluator* cmd_ev, ui::ErrorFormatter* errfmt);
class ShellOptHook : public ::state::OptHook {
 public:
  ShellOptHook(py_readline::Readline* readline);
  virtual bool OnChange(List<bool>* opt0_array, BigStr* opt_name, bool b);

  py_readline::Readline* readline;
  
  static constexpr uint32_t field_mask() {
    return ::state::OptHook::field_mask()
         | maskbit(offsetof(ShellOptHook, readline));
  }

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassFixed(field_mask(), sizeof(ShellOptHook));
  }

  DISALLOW_COPY_AND_ASSIGN(ShellOptHook)
};

void _SetGlobalFunc(state::Mem* mem, BigStr* name, vm::_Callable* func);
Dict<int, vm::_AssignBuiltin*>* InitAssignmentBuiltins(state::Mem* mem, Dict<BigStr*, value::Proc*>* procs, optview::Exec* exec_opts, ui::ErrorFormatter* errfmt);
class ShellFiles {
 public:
  ShellFiles(BigStr* lang, BigStr* home_dir, state::Mem* mem, arg_types::main* flag);
  BigStr* _HistVar();
  BigStr* _DefaultHistoryFile();
  void InitAfterLoadingEnv();
  BigStr* HistoryFile();
  BigStr* lang;
  BigStr* home_dir;
  state::Mem* mem;
  arg_types::main* flag;

  static constexpr ObjHeader obj_header() {
    return ObjHeader::ClassScanned(4, sizeof(ShellFiles));
  }

  DISALLOW_COPY_AND_ASSIGN(ShellFiles)
};

int Main(BigStr* lang, args::Reader* arg_r, Dict<BigStr*, BigStr*>* environ, bool login_shell, pyutil::_ResourceLoader* loader, py_readline::Readline* readline);

}  // declare namespace shell

namespace runtime {  // define

using hnode_asdl::hnode;
using hnode_asdl::color_t;
using hnode_asdl::color_e;
int NO_SPID = -1;

hnode::Record* NewRecord(BigStr* node_type) {
  StackRoot _root0(&node_type);

  return Alloc<hnode::Record>(node_type, Alloc<List<hnode_asdl::Field*>>(), false, str0, str1, Alloc<List<hnode_asdl::hnode_t*>>());
}

hnode::Leaf* NewLeaf(BigStr* s, hnode_asdl::color_t e_color) {
  StackRoot _root0(&s);

  if (s == nullptr) {
    return Alloc<hnode::Leaf>(str2, color_e::OtherConst);
  }
  else {
    return Alloc<hnode::Leaf>(s, e_color);
  }
}

TraversalState::TraversalState() {
  this->seen = Alloc<Dict<int, bool>>();
  this->ref_count = Alloc<Dict<int, int>>();
}
BigStr* TRUE_STR = str3;
BigStr* FALSE_STR = str4;

}  // define namespace runtime

namespace vm {  // define

using id_kind_asdl::Id;
using runtime_asdl::CommandStatus;
using runtime_asdl::StatusArray;
using runtime_asdl::flow_e;
using runtime_asdl::flow_t;
using syntax_asdl::Token;
using value_asdl::value;
using value_asdl::value_t;

IntControlFlow::IntControlFlow(syntax_asdl::Token* token, int arg) {
  this->token = token;
  this->arg = arg;
}

bool IntControlFlow::IsReturn() {
  return this->token->id == Id::ControlFlow_Return;
}

bool IntControlFlow::IsBreak() {
  return this->token->id == Id::ControlFlow_Break;
}

bool IntControlFlow::IsContinue() {
  return this->token->id == Id::ControlFlow_Continue;
}

int IntControlFlow::StatusCode() {
  return (this->arg & 255);
}

runtime_asdl::flow_t IntControlFlow::HandleLoop() {
  if (this->IsBreak()) {
    this->arg -= 1;
    if (this->arg == 0) {
      return flow_e::Break;
    }
  }
  else {
    if (this->IsContinue()) {
      this->arg -= 1;
      if (this->arg == 0) {
        return flow_e::Nothing;
      }
    }
  }
  return flow_e::Raise;
}

ValueControlFlow::ValueControlFlow(syntax_asdl::Token* token, value_asdl::value_t* value) {
  this->token = token;
  this->value = value;
}

void InitUnsafeArith(state::Mem* mem, word_eval::NormalWordEvaluator* word_ev, sh_expr_eval::UnsafeArith* unsafe_arith) {
  StackRoot _root0(&mem);
  StackRoot _root1(&word_ev);
  StackRoot _root2(&unsafe_arith);

  mem->unsafe_arith = unsafe_arith;
  word_ev->unsafe_arith = unsafe_arith;
}

void InitCircularDeps(sh_expr_eval::ArithEvaluator* arith_ev, sh_expr_eval::BoolEvaluator* bool_ev, expr_eval::ExprEvaluator* expr_ev, word_eval::NormalWordEvaluator* word_ev, cmd_eval::CommandEvaluator* cmd_ev, vm::_Executor* shell_ex, prompt::Evaluator* prompt_ev, value::IO* global_io, dev::Tracer* tracer) {
  StackRoot _root0(&arith_ev);
  StackRoot _root1(&bool_ev);
  StackRoot _root2(&expr_ev);
  StackRoot _root3(&word_ev);
  StackRoot _root4(&cmd_ev);
  StackRoot _root5(&shell_ex);
  StackRoot _root6(&prompt_ev);
  StackRoot _root7(&global_io);
  StackRoot _root8(&tracer);

  arith_ev->word_ev = word_ev;
  bool_ev->word_ev = word_ev;
  if (expr_ev) {
    expr_ev->shell_ex = shell_ex;
    expr_ev->cmd_ev = cmd_ev;
    expr_ev->word_ev = word_ev;
  }
  word_ev->arith_ev = arith_ev;
  word_ev->expr_ev = expr_ev;
  word_ev->prompt_ev = prompt_ev;
  word_ev->shell_ex = shell_ex;
  cmd_ev->shell_ex = shell_ex;
  cmd_ev->arith_ev = arith_ev;
  cmd_ev->bool_ev = bool_ev;
  cmd_ev->expr_ev = expr_ev;
  cmd_ev->word_ev = word_ev;
  cmd_ev->tracer = tracer;
  shell_ex->cmd_ev = cmd_ev;
  prompt_ev->word_ev = word_ev;
  prompt_ev->expr_ev = expr_ev;
  prompt_ev->global_io = global_io;
  tracer->word_ev = word_ev;
  arith_ev->CheckCircularDeps();
  bool_ev->CheckCircularDeps();
  if (expr_ev) {
    expr_ev->CheckCircularDeps();
  }
  word_ev->CheckCircularDeps();
  cmd_ev->CheckCircularDeps();
  shell_ex->CheckCircularDeps();
  prompt_ev->CheckCircularDeps();
  tracer->CheckCircularDeps();
}

_Executor::_Executor() {
  this->cmd_ev = nullptr;
}

void _Executor::CheckCircularDeps() {
  ;  // pass
}

int _Executor::RunBuiltin(int builtin_id, cmd_value::Argv* cmd_val) {
  StackRoot _root0(&cmd_val);

  return 0;
}

int _Executor::RunSimpleCommand(cmd_value::Argv* cmd_val, runtime_asdl::CommandStatus* cmd_st, int run_flags) {
  StackRoot _root0(&cmd_val);
  StackRoot _root1(&cmd_st);

  return 0;
}

int _Executor::RunBackgroundJob(syntax_asdl::command_t* node) {
  StackRoot _root0(&node);

  return 0;
}

void _Executor::RunPipeline(command::Pipeline* node, runtime_asdl::CommandStatus* status_out) {
  StackRoot _root0(&node);
  StackRoot _root1(&status_out);

  ;  // pass
}

int _Executor::RunSubshell(syntax_asdl::command_t* node) {
  StackRoot _root0(&node);

  return 0;
}

BigStr* _Executor::RunCommandSub(syntax_asdl::CommandSub* cs_part) {
  StackRoot _root0(&cs_part);

  return str7;
}

BigStr* _Executor::RunProcessSub(syntax_asdl::CommandSub* cs_part) {
  StackRoot _root0(&cs_part);

  return str8;
}

void _Executor::PushRedirects(List<runtime_asdl::RedirValue*>* redirects, List<IOError_OSError*>* err_out) {
  StackRoot _root0(&redirects);
  StackRoot _root1(&err_out);

  ;  // pass
}

void _Executor::PopRedirects(int num_redirects, List<IOError_OSError*>* err_out) {
  StackRoot _root0(&err_out);

  ;  // pass
}

void _Executor::PushProcessSub() {
  ;  // pass
}

void _Executor::PopProcessSub(runtime_asdl::StatusArray* compound_st) {
  StackRoot _root0(&compound_st);

  ;  // pass
}

_AssignBuiltin::_AssignBuiltin() {
  ;  // pass
}

int _AssignBuiltin::Run(cmd_value::Assign* cmd_val) {
  StackRoot _root0(&cmd_val);

  FAIL(kNotImplemented);  // Python NotImplementedError
}

_Builtin::_Builtin() {
  ;  // pass
}

int _Builtin::Run(cmd_value::Argv* cmd_val) {
  StackRoot _root0(&cmd_val);

  FAIL(kNotImplemented);  // Python NotImplementedError
}

_Callable::_Callable() {
  ;  // pass
}

value_asdl::value_t* _Callable::Call(typed_args::Reader* args) {
  StackRoot _root0(&args);

  FAIL(kNotImplemented);  // Python NotImplementedError
}

ctx_Redirect::ctx_Redirect(vm::_Executor* shell_ex, int num_redirects, List<IOError_OSError*>* err_out) {
  gHeap.PushRoot(reinterpret_cast<RawObject**>(&(this->err_out)));
  gHeap.PushRoot(reinterpret_cast<RawObject**>(&(this->shell_ex)));
  this->shell_ex = shell_ex;
  this->num_redirects = num_redirects;
  this->err_out = err_out;
}

ctx_Redirect::~ctx_Redirect() {
  this->shell_ex->PopRedirects(this->num_redirects, this->err_out);
  gHeap.PopRoot();
  gHeap.PopRoot();
}

ctx_ProcessSub::ctx_ProcessSub(vm::_Executor* shell_ex, runtime_asdl::StatusArray* process_sub_status) {
  gHeap.PushRoot(reinterpret_cast<RawObject**>(&(this->process_sub_status)));
  gHeap.PushRoot(reinterpret_cast<RawObject**>(&(this->shell_ex)));
  shell_ex->PushProcessSub();
  this->shell_ex = shell_ex;
  this->process_sub_status = process_sub_status;
}

ctx_ProcessSub::~ctx_ProcessSub() {
  this->shell_ex->PopProcessSub(this->process_sub_status);
  gHeap.PopRoot();
  gHeap.PopRoot();
}

ctx_FlushStdout::ctx_FlushStdout(List<IOError_OSError*>* err_out) {
  gHeap.PushRoot(reinterpret_cast<RawObject**>(&(this->err_out)));
  this->err_out = err_out;
}

ctx_FlushStdout::~ctx_FlushStdout() {
  IOError_OSError* err = pyos::FlushStdout();
  if (err != nullptr) {
    this->err_out->append(err);
  }
  gHeap.PopRoot();
}

}  // define namespace vm

namespace format {  // define

using hnode_asdl::hnode;
using hnode_asdl::hnode_e;
using hnode_asdl::hnode_t;
using hnode_asdl::color_e;
using hnode_asdl::color_t;

format::ColorOutput* DetectConsoleOutput(mylib::Writer* f) {
  StackRoot _root0(&f);

  if (f->isatty()) {
    return Alloc<AnsiOutput>(f);
  }
  else {
    return Alloc<TextOutput>(f);
  }
}

ColorOutput::ColorOutput(mylib::Writer* f) {
  this->f = f;
  this->num_chars = 0;
}

format::ColorOutput* ColorOutput::NewTempBuffer() {
  FAIL(kNotImplemented);  // Python NotImplementedError
}

void ColorOutput::FileHeader() {
  ;  // pass
}

void ColorOutput::FileFooter() {
  ;  // pass
}

void ColorOutput::PushColor(hnode_asdl::color_t e_color) {
  FAIL(kNotImplemented);  // Python NotImplementedError
}

void ColorOutput::PopColor() {
  FAIL(kNotImplemented);  // Python NotImplementedError
}

void ColorOutput::write(BigStr* s) {
  StackRoot _root0(&s);

  this->f->write(s);
  this->num_chars += len(s);
}

void ColorOutput::WriteRaw(Tuple2<BigStr*, int>* raw) {
  BigStr* s = nullptr;
  int num_chars;
  StackRoot _root0(&raw);
  StackRoot _root1(&s);

  Tuple2<BigStr*, int>* tup0 = raw;
  s = tup0->at0();
  num_chars = tup0->at1();
  this->f->write(s);
  this->num_chars += num_chars;
}

int ColorOutput::NumChars() {
  return this->num_chars;
}

Tuple2<BigStr*, int> ColorOutput::GetRaw() {
  mylib::BufWriter* f = nullptr;
  StackRoot _root0(&f);

  f = static_cast<mylib::BufWriter*>(this->f);
  return Tuple2<BigStr*, int>(f->getvalue(), this->num_chars);
}

TextOutput::TextOutput(mylib::Writer* f) : ::format::ColorOutput(f) {
}

format::TextOutput* TextOutput::NewTempBuffer() {
  return Alloc<TextOutput>(Alloc<mylib::BufWriter>());
}

void TextOutput::PushColor(hnode_asdl::color_t e_color) {
  ;  // pass
}

void TextOutput::PopColor() {
  ;  // pass
}

HtmlOutput::HtmlOutput(mylib::Writer* f) : ::format::ColorOutput(f) {
}

format::HtmlOutput* HtmlOutput::NewTempBuffer() {
  return Alloc<HtmlOutput>(Alloc<mylib::BufWriter>());
}

void HtmlOutput::FileHeader() {
  this->f->write(str9);
}

void HtmlOutput::FileFooter() {
  this->f->write(str10);
}

void HtmlOutput::PushColor(hnode_asdl::color_t e_color) {
  BigStr* css_class = nullptr;
  StackRoot _root0(&css_class);

  if (e_color == color_e::TypeName) {
    css_class = str11;
  }
  else {
    if (e_color == color_e::StringConst) {
      css_class = str12;
    }
    else {
      if (e_color == color_e::OtherConst) {
        css_class = str13;
      }
      else {
        if (e_color == color_e::External) {
          css_class = str14;
        }
        else {
          if (e_color == color_e::UserType) {
            css_class = str15;
          }
          else {
            assert(0);  // AssertionError
          }
        }
      }
    }
  }
  this->f->write(StrFormat("<span class=\"%s\">", css_class));
}

void HtmlOutput::PopColor() {
  this->f->write(str17);
}

void HtmlOutput::write(BigStr* s) {
  StackRoot _root0(&s);

  this->f->write(cgi::escape(s));
  this->num_chars += len(s);
}

AnsiOutput::AnsiOutput(mylib::Writer* f) : ::format::ColorOutput(f) {
}

format::AnsiOutput* AnsiOutput::NewTempBuffer() {
  return Alloc<AnsiOutput>(Alloc<mylib::BufWriter>());
}

void AnsiOutput::PushColor(hnode_asdl::color_t e_color) {
  if (e_color == color_e::TypeName) {
    this->f->write(ansi::YELLOW);
  }
  else {
    if (e_color == color_e::StringConst) {
      this->f->write(ansi::BOLD);
    }
    else {
      if (e_color == color_e::OtherConst) {
        this->f->write(ansi::GREEN);
      }
      else {
        if (e_color == color_e::External) {
          this->f->write(str_concat(ansi::BOLD, ansi::BLUE));
        }
        else {
          if (e_color == color_e::UserType) {
            this->f->write(ansi::GREEN);
          }
          else {
            assert(0);  // AssertionError
          }
        }
      }
    }
  }
}

void AnsiOutput::PopColor() {
  this->f->write(ansi::RESET);
}
int INDENT = 2;

_PrettyPrinter::_PrettyPrinter(int max_col) {
  this->max_col = max_col;
}

bool _PrettyPrinter::_PrintWrappedArray(List<hnode_asdl::hnode_t*>* array, int prefix_len, format::ColorOutput* f, int indent) {
  bool all_fit;
  int chars_so_far;
  int i;
  format::ColorOutput* single_f = nullptr;
  BigStr* s = nullptr;
  int num_chars;
  StackRoot _root0(&array);
  StackRoot _root1(&f);
  StackRoot _root2(&single_f);
  StackRoot _root3(&s);

  all_fit = true;
  chars_so_far = prefix_len;
  i = 0;
  for (ListIter<hnode_asdl::hnode_t*> it(array); !it.Done(); it.Next(), ++i) {
    hnode_asdl::hnode_t* val = it.Value();
    StackRoot _for(&val  );
    if (i != 0) {
      f->write(str18);
    }
    single_f = f->NewTempBuffer();
    if (_TrySingleLine(val, single_f, (this->max_col - chars_so_far))) {
      Tuple2<BigStr*, int> tup1 = single_f->GetRaw();
      s = tup1.at0();
      num_chars = tup1.at1();
      f->WriteRaw((Alloc<Tuple2<BigStr*, int>>(s, num_chars)));
      chars_so_far += single_f->NumChars();
    }
    else {
      f->write(str19);
      this->PrintNode(val, f, (indent + INDENT));
      chars_so_far = 0;
      all_fit = false;
    }
  }
  return all_fit;
}

bool _PrettyPrinter::_PrintWholeArray(List<hnode_asdl::hnode_t*>* array, int prefix_len, format::ColorOutput* f, int indent) {
  bool all_fit;
  List<Tuple2<BigStr*, int>*>* pieces = nullptr;
  int chars_so_far;
  format::ColorOutput* single_f = nullptr;
  BigStr* s = nullptr;
  int num_chars;
  int i;
  StackRoot _root0(&array);
  StackRoot _root1(&f);
  StackRoot _root2(&pieces);
  StackRoot _root3(&single_f);
  StackRoot _root4(&s);

  all_fit = true;
  pieces = Alloc<List<Tuple2<BigStr*, int>*>>();
  chars_so_far = prefix_len;
  for (ListIter<hnode_asdl::hnode_t*> it(array); !it.Done(); it.Next()) {
    hnode_asdl::hnode_t* item = it.Value();
    StackRoot _for(&item  );
    single_f = f->NewTempBuffer();
    if (_TrySingleLine(item, single_f, (this->max_col - chars_so_far))) {
      Tuple2<BigStr*, int> tup2 = single_f->GetRaw();
      s = tup2.at0();
      num_chars = tup2.at1();
      pieces->append((Alloc<Tuple2<BigStr*, int>>(s, num_chars)));
      chars_so_far += single_f->NumChars();
    }
    else {
      all_fit = false;
      break;
    }
  }
  if (all_fit) {
    i = 0;
    for (ListIter<Tuple2<BigStr*, int>*> it(pieces); !it.Done(); it.Next(), ++i) {
      Tuple2<BigStr*, int>* p = it.Value();
      StackRoot _for(&p    );
      if (i != 0) {
        f->write(str20);
      }
      f->WriteRaw(p);
    }
    f->write(str21);
  }
  return all_fit;
}

void _PrettyPrinter::_PrintRecord(hnode::Record* node, format::ColorOutput* f, int indent) {
  BigStr* ind = nullptr;
  BigStr* prefix = nullptr;
  int prefix_len;
  bool all_fit;
  BigStr* name = nullptr;
  hnode_asdl::hnode_t* val = nullptr;
  BigStr* ind1 = nullptr;
  hnode_asdl::hnode_t* UP_val = nullptr;
  int tag;
  BigStr* name_str = nullptr;
  format::ColorOutput* single_f = nullptr;
  BigStr* s = nullptr;
  int num_chars;
  StackRoot _root0(&node);
  StackRoot _root1(&f);
  StackRoot _root2(&ind);
  StackRoot _root3(&prefix);
  StackRoot _root4(&name);
  StackRoot _root5(&val);
  StackRoot _root6(&ind1);
  StackRoot _root7(&UP_val);
  StackRoot _root8(&name_str);
  StackRoot _root9(&single_f);
  StackRoot _root10(&s);

  ind = str_repeat(str22, indent);
  if (node->abbrev) {
    prefix = str_concat(ind, node->left);
    f->write(prefix);
    if (len(node->node_type)) {
      f->PushColor(color_e::TypeName);
      f->write(node->node_type);
      f->PopColor();
      f->write(str23);
    }
    prefix_len = ((len(prefix) + len(node->node_type)) + 1);
    all_fit = this->_PrintWrappedArray(node->unnamed_fields, prefix_len, f, indent);
    if (!all_fit) {
      f->write(str24);
      f->write(ind);
    }
    f->write(node->right);
  }
  else {
    f->write(str_concat(ind, node->left));
    f->PushColor(color_e::TypeName);
    f->write(node->node_type);
    f->PopColor();
    f->write(str25);
    for (ListIter<hnode_asdl::Field*> it(node->fields); !it.Done(); it.Next()) {
      hnode_asdl::Field* field = it.Value();
      StackRoot _for(&field    );
      name = field->name;
      val = field->val;
      ind1 = str_repeat(str26, (indent + INDENT));
      UP_val = val;
      tag = val->tag();
      if (tag == hnode_e::Array) {
        hnode::Array* val = static_cast<hnode::Array*>(UP_val);
        name_str = StrFormat("%s%s: [", ind1, name);
        f->write(name_str);
        prefix_len = len(name_str);
        if (!this->_PrintWholeArray(val->children, prefix_len, f, indent)) {
          f->write(str28);
          for (ListIter<hnode_asdl::hnode_t*> it(val->children); !it.Done(); it.Next()) {
            hnode_asdl::hnode_t* child = it.Value();
            StackRoot _for(&child          );
            this->PrintNode(child, f, ((indent + INDENT) + INDENT));
            f->write(str29);
          }
          f->write(StrFormat("%s]", ind1));
        }
      }
      else {
        name_str = StrFormat("%s%s: ", ind1, name);
        f->write(name_str);
        prefix_len = len(name_str);
        single_f = f->NewTempBuffer();
        if (_TrySingleLine(val, single_f, (this->max_col - prefix_len))) {
          Tuple2<BigStr*, int> tup3 = single_f->GetRaw();
          s = tup3.at0();
          num_chars = tup3.at1();
          f->WriteRaw((Alloc<Tuple2<BigStr*, int>>(s, num_chars)));
        }
        else {
          f->write(str32);
          this->PrintNode(val, f, ((indent + INDENT) + INDENT));
        }
      }
      f->write(str33);
    }
    f->write(str_concat(ind, node->right));
  }
}

void _PrettyPrinter::PrintNode(hnode_asdl::hnode_t* node, format::ColorOutput* f, int indent) {
  BigStr* ind = nullptr;
  format::ColorOutput* single_f = nullptr;
  BigStr* s = nullptr;
  int num_chars;
  hnode_asdl::hnode_t* UP_node = nullptr;
  int tag;
  StackRoot _root0(&node);
  StackRoot _root1(&f);
  StackRoot _root2(&ind);
  StackRoot _root3(&single_f);
  StackRoot _root4(&s);
  StackRoot _root5(&UP_node);

  ind = str_repeat(str34, indent);
  single_f = f->NewTempBuffer();
  single_f->write(ind);
  if (_TrySingleLine(node, single_f, (this->max_col - indent))) {
    Tuple2<BigStr*, int> tup4 = single_f->GetRaw();
    s = tup4.at0();
    num_chars = tup4.at1();
    f->WriteRaw((Alloc<Tuple2<BigStr*, int>>(s, num_chars)));
    return ;
  }
  UP_node = node;
  tag = node->tag();
  if (tag == hnode_e::Leaf) {
    hnode::Leaf* node = static_cast<hnode::Leaf*>(UP_node);
    f->PushColor(node->color);
    f->write(j8_lite::EncodeString(node->s, true));
    f->PopColor();
  }
  else {
    if (tag == hnode_e::External) {
      hnode::External* node = static_cast<hnode::External*>(UP_node);
      f->PushColor(color_e::External);
      // if not PYTHON
      {
        f->write(str35);
      }
      // endif MYCPP
      f->PopColor();
    }
    else {
      if (tag == hnode_e::Record) {
        hnode::Record* node = static_cast<hnode::Record*>(UP_node);
        this->_PrintRecord(node, f, indent);
      }
      else {
        if (tag == hnode_e::AlreadySeen) {
          hnode::AlreadySeen* node = static_cast<hnode::AlreadySeen*>(UP_node);
          f->write(StrFormat("...0x%s", mylib::hex_lower(node->heap_id)));
        }
        else {
          assert(0);  // AssertionError
        }
      }
    }
  }
}

bool _TrySingleLineObj(hnode::Record* node, format::ColorOutput* f, int max_chars) {
  int i;
  StackRoot _root0(&node);
  StackRoot _root1(&f);

  f->write(node->left);
  if (node->abbrev) {
    if (len(node->node_type)) {
      f->PushColor(color_e::TypeName);
      f->write(node->node_type);
      f->PopColor();
      f->write(str37);
    }
    i = 0;
    for (ListIter<hnode_asdl::hnode_t*> it(node->unnamed_fields); !it.Done(); it.Next(), ++i) {
      hnode_asdl::hnode_t* val = it.Value();
      StackRoot _for(&val    );
      if (i != 0) {
        f->write(str38);
      }
      if (!_TrySingleLine(val, f, max_chars)) {
        return false;
      }
    }
  }
  else {
    f->PushColor(color_e::TypeName);
    f->write(node->node_type);
    f->PopColor();
    for (ListIter<hnode_asdl::Field*> it(node->fields); !it.Done(); it.Next()) {
      hnode_asdl::Field* field = it.Value();
      StackRoot _for(&field    );
      f->write(StrFormat(" %s:", field->name));
      if (!_TrySingleLine(field->val, f, max_chars)) {
        return false;
      }
    }
  }
  f->write(node->right);
  return true;
}

bool _TrySingleLine(hnode_asdl::hnode_t* node, format::ColorOutput* f, int max_chars) {
  hnode_asdl::hnode_t* UP_node = nullptr;
  int tag;
  int i;
  int num_chars_so_far;
  StackRoot _root0(&node);
  StackRoot _root1(&f);
  StackRoot _root2(&UP_node);

  UP_node = node;
  tag = node->tag();
  if (tag == hnode_e::Leaf) {
    hnode::Leaf* node = static_cast<hnode::Leaf*>(UP_node);
    f->PushColor(node->color);
    f->write(j8_lite::EncodeString(node->s, true));
    f->PopColor();
  }
  else {
    if (tag == hnode_e::External) {
      hnode::External* node = static_cast<hnode::External*>(UP_node);
      f->PushColor(color_e::External);
      // if not PYTHON
      {
        f->write(str40);
      }
      // endif MYCPP
      f->PopColor();
    }
    else {
      if (tag == hnode_e::Array) {
        hnode::Array* node = static_cast<hnode::Array*>(UP_node);
        f->write(str41);
        i = 0;
        for (ListIter<hnode_asdl::hnode_t*> it(node->children); !it.Done(); it.Next(), ++i) {
          hnode_asdl::hnode_t* item = it.Value();
          StackRoot _for(&item        );
          if (i != 0) {
            f->write(str42);
          }
          if (!_TrySingleLine(item, f, max_chars)) {
            return false;
          }
        }
        f->write(str43);
      }
      else {
        if (tag == hnode_e::Record) {
          hnode::Record* node = static_cast<hnode::Record*>(UP_node);
          return _TrySingleLineObj(node, f, max_chars);
        }
        else {
          if (tag == hnode_e::AlreadySeen) {
            hnode::AlreadySeen* node = static_cast<hnode::AlreadySeen*>(UP_node);
            f->write(StrFormat("...0x%s", mylib::hex_lower(node->heap_id)));
          }
          else {
            assert(0);  // AssertionError
          }
        }
      }
    }
  }
  num_chars_so_far = f->NumChars();
  if (num_chars_so_far > max_chars) {
    return false;
  }
  return true;
}

void PrintTree(hnode_asdl::hnode_t* node, format::ColorOutput* f) {
  format::_PrettyPrinter* pp = nullptr;
  StackRoot _root0(&node);
  StackRoot _root1(&f);
  StackRoot _root2(&pp);

  pp = Alloc<_PrettyPrinter>(100);
  pp->PrintNode(node, f, 0);
}

}  // define namespace format

namespace oils_for_unix {  // define

using syntax_asdl::loc;
using syntax_asdl::CompoundWord;
using mylib::print_stderr;

int CaperDispatch() {
  List<int>* fd_out = nullptr;
  BigStr* msg = nullptr;
  BigStr* command = nullptr;
  BigStr* arg = nullptr;
  StackRoot _root0(&fd_out);
  StackRoot _root1(&msg);
  StackRoot _root2(&command);
  StackRoot _root3(&arg);

  mylib::print_stderr(str45);
  fd_out = Alloc<List<int>>();
  while (true) {
    try {
      msg = fanos::recv(0, fd_out);
    }
    catch (ValueError* e) {
      mylib::print_stderr(StrFormat("FANOS error: %s", e));
      fanos::send(1, StrFormat("ERROR %s", e));
      continue;
    }
    mylib::print_stderr(StrFormat("msg = %r", msg));
    Tuple2<BigStr*, BigStr*> tup0 = mylib::split_once(msg, str49);
    command = tup0.at0();
    arg = tup0.at1();
    if (str_equals(command, str50)) {
      ;  // pass
    }
    else {
      if (str_equals(command, str51)) {
        ;  // pass
      }
      else {
        if (str_equals(command, str52)) {
          ;  // pass
        }
        else {
          if (str_equals(command, str53)) {
            ;  // pass
          }
        }
      }
    }
  }
  return 0;
}

int AppBundleMain(List<BigStr*>* argv) {
  pyutil::_ResourceLoader* loader = nullptr;
  BigStr* b = nullptr;
  BigStr* main_name = nullptr;
  BigStr* ext = nullptr;
  syntax_asdl::CompoundWord* missing = nullptr;
  args::Reader* arg_r = nullptr;
  bool login_shell;
  BigStr* bundle = nullptr;
  BigStr* first_arg = nullptr;
  BigStr* applet = nullptr;
  py_readline::Readline* readline = nullptr;
  Dict<BigStr*, BigStr*>* environ = nullptr;
  StackRoot _root0(&argv);
  StackRoot _root1(&loader);
  StackRoot _root2(&b);
  StackRoot _root3(&main_name);
  StackRoot _root4(&ext);
  StackRoot _root5(&missing);
  StackRoot _root6(&arg_r);
  StackRoot _root7(&bundle);
  StackRoot _root8(&first_arg);
  StackRoot _root9(&applet);
  StackRoot _root10(&readline);
  StackRoot _root11(&environ);

  loader = pyutil::GetResourceLoader();
  b = os_path::basename(argv->at(0));
  Tuple2<BigStr*, BigStr*> tup1 = os_path::splitext(b);
  main_name = tup1.at0();
  ext = tup1.at1();
  missing = nullptr;
  arg_r = Alloc<args::Reader>(argv, list_repeat(missing, len(argv)));
  login_shell = false;
  // if not PYTHON
  {
    bundle = str54;
  }
  // endif MYCPP
  if ((str_equals(main_name, bundle) or (str_equals(main_name, str55) and len(ext)))) {
    arg_r->Next();
    first_arg = arg_r->Peek();
    if (first_arg == nullptr) {
      throw Alloc<error::Usage>(str56, loc::Missing);
    }
    if ((str_equals(first_arg, str57) || str_equals(first_arg, str58))) {
      util::HelpFlag(loader, str59, mylib::Stdout());
      return 0;
    }
    if ((str_equals(first_arg, str60) || str_equals(first_arg, str61))) {
      util::VersionFlag(loader, mylib::Stdout());
      return 0;
    }
    if (str_equals(first_arg, str62)) {
      return CaperDispatch();
    }
    applet = first_arg;
  }
  else {
    applet = main_name;
    if (applet->startswith(str63)) {
      login_shell = true;
      applet = applet->slice(1);
    }
  }
  readline = py_readline::MaybeGetReadline();
  environ = pyos::Environ();
  if ((str_equals(applet, str64) || str_equals(applet, str65))) {
    return shell::Main(str66, arg_r, environ, login_shell, loader, readline);
  }
  else {
    if (applet->endswith(str67)) {
      return shell::Main(str68, arg_r, environ, login_shell, loader, readline);
    }
    else {
      if (str_equals(applet, str69)) {
        return 0;
      }
      else {
        if (str_equals(applet, str70)) {
          return 1;
        }
        else {
          if (str_equals(applet, str71)) {
            // if not PYTHON
            {
              print_stderr(str72);
              return 2;
            }
            // endif MYCPP
          }
          else {
            throw Alloc<error::Usage>(StrFormat("Invalid applet %r", applet), loc::Missing);
          }
        }
      }
    }
  }
}

int main(List<BigStr*>* argv) {
  StackRoot _root0(&argv);

  try {
    return AppBundleMain(argv);
  }
  catch (error::Usage* e) {
    mylib::print_stderr(StrFormat("oils: %s", e->msg));
    return 2;
  }
  catch (KeyboardInterrupt*) {
    print(str75);
    return 130;
  }
  catch (IOError_OSError* e) {
    print_stderr(StrFormat("oils I/O error (main): %s", posix::strerror(e->errno_)));
    return 2;
  }
}

}  // define namespace oils_for_unix

namespace assign_osh {  // define

using option_asdl::builtin_i;
using runtime_asdl::scope_e;
using runtime_asdl::cmd_value;
using runtime_asdl::AssignArg;
using value_asdl::value;
using value_asdl::value_e;
using value_asdl::value_t;
using value_asdl::LeftName;
using syntax_asdl::loc;
using syntax_asdl::loc_t;
using syntax_asdl::word_t;
using error::e_usage;
int _OTHER = 0;
int _READONLY = 1;
int _EXPORT = 2;

int _PrintVariables(state::Mem* mem, cmd_value::Assign* cmd_val, args::_Attributes* attrs, bool print_flags, int builtin) {
  Dict<BigStr*, value_asdl::value_t*>* flag = nullptr;
  value_asdl::value_t* tmp_g = nullptr;
  value_asdl::value_t* tmp_a = nullptr;
  value_asdl::value_t* tmp_A = nullptr;
  bool flag_g;
  bool flag_a;
  bool flag_A;
  value_asdl::value_t* tmp_n = nullptr;
  value_asdl::value_t* tmp_r = nullptr;
  value_asdl::value_t* tmp_x = nullptr;
  BigStr* flag_n = nullptr;
  BigStr* flag_r = nullptr;
  BigStr* flag_x = nullptr;
  runtime_asdl::scope_t which_scopes;
  bool print_all;
  Dict<BigStr*, runtime_asdl::Cell*>* cells = nullptr;
  List<BigStr*>* names = nullptr;
  BigStr* name = nullptr;
  BigStr* s = nullptr;
  BigStr* invalid = nullptr;
  int count;
  runtime_asdl::Cell* cell = nullptr;
  value_asdl::value_t* val = nullptr;
  List<BigStr*>* decl = nullptr;
  List<BigStr*>* flags = nullptr;
  value::Str* str_val = nullptr;
  value::BashArray* array_val = nullptr;
  bool has_holes;
  bool first;
  int i;
  List<BigStr*>* body = nullptr;
  value::BashAssoc* assoc_val = nullptr;
  BigStr* key_quoted = nullptr;
  BigStr* value_quoted = nullptr;
  StackRoot _root0(&mem);
  StackRoot _root1(&cmd_val);
  StackRoot _root2(&attrs);
  StackRoot _root3(&flag);
  StackRoot _root4(&tmp_g);
  StackRoot _root5(&tmp_a);
  StackRoot _root6(&tmp_A);
  StackRoot _root7(&tmp_n);
  StackRoot _root8(&tmp_r);
  StackRoot _root9(&tmp_x);
  StackRoot _root10(&flag_n);
  StackRoot _root11(&flag_r);
  StackRoot _root12(&flag_x);
  StackRoot _root13(&cells);
  StackRoot _root14(&names);
  StackRoot _root15(&name);
  StackRoot _root16(&s);
  StackRoot _root17(&invalid);
  StackRoot _root18(&cell);
  StackRoot _root19(&val);
  StackRoot _root20(&decl);
  StackRoot _root21(&flags);
  StackRoot _root22(&str_val);
  StackRoot _root23(&array_val);
  StackRoot _root24(&body);
  StackRoot _root25(&assoc_val);
  StackRoot _root26(&key_quoted);
  StackRoot _root27(&value_quoted);

  flag = attrs->attrs;
  tmp_g = flag->get(str77);
  tmp_a = flag->get(str78);
  tmp_A = flag->get(str79);
  flag_g = (tmp_g and tmp_g->tag() == value_e::Bool) ? static_cast<value::Bool*>(tmp_g)->b : false;
  flag_a = (tmp_a and tmp_a->tag() == value_e::Bool) ? static_cast<value::Bool*>(tmp_a)->b : false;
  flag_A = (tmp_A and tmp_A->tag() == value_e::Bool) ? static_cast<value::Bool*>(tmp_A)->b : false;
  tmp_n = flag->get(str80);
  tmp_r = flag->get(str81);
  tmp_x = flag->get(str82);
  flag_n = (tmp_n and tmp_n->tag() == value_e::Str) ? static_cast<value::Str*>(tmp_n)->s : nullptr;
  flag_r = (tmp_r and tmp_r->tag() == value_e::Str) ? static_cast<value::Str*>(tmp_r)->s : nullptr;
  flag_x = (tmp_x and tmp_x->tag() == value_e::Str) ? static_cast<value::Str*>(tmp_x)->s : nullptr;
  if (cmd_val->builtin_id == builtin_i::local) {
    if ((flag_g and !mem->IsGlobalScope())) {
      return 1;
    }
    which_scopes = scope_e::LocalOnly;
  }
  else {
    if (flag_g) {
      which_scopes = scope_e::GlobalOnly;
    }
    else {
      which_scopes = mem->ScopesForReading();
    }
  }
  if (len(cmd_val->pairs) == 0) {
    print_all = true;
    cells = mem->GetAllCells(which_scopes);
    names = sorted(cells);
  }
  else {
    print_all = false;
    names = Alloc<List<BigStr*>>();
    cells = Alloc<Dict<BigStr*, runtime_asdl::Cell*>>();
    for (ListIter<runtime_asdl::AssignArg*> it(cmd_val->pairs); !it.Done(); it.Next()) {
      runtime_asdl::AssignArg* pair = it.Value();
      StackRoot _for(&pair    );
      name = pair->var_name;
      if ((pair->rval and pair->rval->tag() == value_e::Str)) {
        s = static_cast<value::Str*>(pair->rval)->s;
        invalid = StrFormat("%s=%s", name, s);
        names->append(invalid);
        cells->set(invalid, nullptr);
      }
      else {
        names->append(name);
        cells->set(name, mem->GetCell(name, which_scopes));
      }
    }
  }
  count = 0;
  for (ListIter<BigStr*> it(names); !it.Done(); it.Next()) {
    BigStr* name = it.Value();
    StackRoot _for(&name  );
    cell = cells->at(name);
    if (cell == nullptr) {
      continue;
    }
    val = cell->val;
    if (val->tag() == value_e::Undef) {
      continue;
    }
    if ((builtin == _READONLY and !cell->readonly)) {
      continue;
    }
    if ((builtin == _EXPORT and !cell->exported)) {
      continue;
    }
    if ((maybe_str_equals(flag_n, str84) and !cell->nameref)) {
      continue;
    }
    if ((maybe_str_equals(flag_n, str85) and cell->nameref)) {
      continue;
    }
    if ((maybe_str_equals(flag_r, str86) and !cell->readonly)) {
      continue;
    }
    if ((maybe_str_equals(flag_r, str87) and cell->readonly)) {
      continue;
    }
    if ((maybe_str_equals(flag_x, str88) and !cell->exported)) {
      continue;
    }
    if ((maybe_str_equals(flag_x, str89) and cell->exported)) {
      continue;
    }
    if ((flag_a and val->tag() != value_e::BashArray)) {
      continue;
    }
    if ((flag_A and val->tag() != value_e::BashAssoc)) {
      continue;
    }
    decl = Alloc<List<BigStr*>>();
    if (print_flags) {
      flags = Alloc<List<BigStr*>>();
      if (cell->nameref) {
        flags->append(str90);
      }
      if (cell->readonly) {
        flags->append(str91);
      }
      if (cell->exported) {
        flags->append(str92);
      }
      if (val->tag() == value_e::BashArray) {
        flags->append(str93);
      }
      else {
        if (val->tag() == value_e::BashAssoc) {
          flags->append(str94);
        }
      }
      if (len(flags) == 0) {
        flags->append(str95);
      }
      decl->extend(NewList<BigStr*>(std::initializer_list<BigStr*>{str96, str97->join(flags), str98, name}));
    }
    else {
      decl->append(name);
    }
    if (val->tag() == value_e::Str) {
      str_val = static_cast<value::Str*>(val);
      decl->extend(NewList<BigStr*>(std::initializer_list<BigStr*>{str99, j8_lite::MaybeShellEncode(str_val->s)}));
    }
    else {
      if (val->tag() == value_e::BashArray) {
        array_val = static_cast<value::BashArray*>(val);
        has_holes = false;
        for (ListIter<BigStr*> it(array_val->strs); !it.Done(); it.Next()) {
          BigStr* s = it.Value();
          StackRoot _for(&s        );
          if (s == nullptr) {
            has_holes = true;
            break;
          }
        }
        if (has_holes) {
          decl->append(str100);
          first = true;
          i = 0;
          for (ListIter<BigStr*> it(array_val->strs); !it.Done(); it.Next(), ++i) {
            BigStr* element = it.Value();
            StackRoot _for(&element          );
            if (element != nullptr) {
              if (first) {
                decl->append(str101);
                first = false;
              }
              decl->extend(NewList<BigStr*>(std::initializer_list<BigStr*>{str102, name, str103, str(i), str104, j8_lite::MaybeShellEncode(element)}));
            }
          }
        }
        else {
          body = Alloc<List<BigStr*>>();
          for (ListIter<BigStr*> it(array_val->strs); !it.Done(); it.Next()) {
            BigStr* element = it.Value();
            StackRoot _for(&element          );
            if (len(body) > 0) {
              body->append(str105);
            }
            body->append(j8_lite::MaybeShellEncode(element));
          }
          decl->extend(NewList<BigStr*>(std::initializer_list<BigStr*>{str106, str107->join(body), str108}));
        }
      }
      else {
        if (val->tag() == value_e::BashAssoc) {
          assoc_val = static_cast<value::BashAssoc*>(val);
          body = Alloc<List<BigStr*>>();
          for (ListIter<BigStr*> it(sorted(assoc_val->d)); !it.Done(); it.Next()) {
            BigStr* key = it.Value();
            StackRoot _for(&key          );
            if (len(body) > 0) {
              body->append(str109);
            }
            key_quoted = j8_lite::ShellEncode(key);
            value_quoted = j8_lite::MaybeShellEncode(assoc_val->d->at(key));
            body->extend(NewList<BigStr*>(std::initializer_list<BigStr*>{str110, key_quoted, str111, value_quoted}));
          }
          if (len(body) > 0) {
            decl->extend(NewList<BigStr*>(std::initializer_list<BigStr*>{str112, str113->join(body), str114}));
          }
        }
        else {
          ;  // pass
        }
      }
    }
    print(str115->join(decl));
    count += 1;
  }
  if ((print_all or count == len(names))) {
    return 0;
  }
  else {
    return 1;
  }
}

void _ExportReadonly(state::Mem* mem, runtime_asdl::AssignArg* pair, int flags) {
  runtime_asdl::scope_t which_scopes;
  value_asdl::LeftName* lval = nullptr;
  value_asdl::value_t* old_val = nullptr;
  value_asdl::value_t* val = nullptr;
  StackRoot _root0(&mem);
  StackRoot _root1(&pair);
  StackRoot _root2(&lval);
  StackRoot _root3(&old_val);
  StackRoot _root4(&val);

  which_scopes = mem->ScopesForWriting();
  lval = Alloc<LeftName>(pair->var_name, pair->blame_word);
  if (pair->plus_eq) {
    old_val = sh_expr_eval::OldValue(lval, mem, nullptr);
    val = cmd_eval::PlusEquals(old_val, pair->rval);
  }
  else {
    val = pair->rval;
  }
  mem->SetNamed(lval, val, which_scopes, flags);
}

Export::Export(state::Mem* mem, ui::ErrorFormatter* errfmt) {
  this->mem = mem;
  this->errfmt = errfmt;
}

int Export::Run(cmd_value::Assign* cmd_val) {
  args::Reader* arg_r = nullptr;
  args::_Attributes* attrs = nullptr;
  arg_types::export_* arg = nullptr;
  StackRoot _root0(&cmd_val);
  StackRoot _root1(&arg_r);
  StackRoot _root2(&attrs);
  StackRoot _root3(&arg);

  arg_r = Alloc<args::Reader>(cmd_val->argv, cmd_val->arg_locs);
  arg_r->Next();
  attrs = flag_util::Parse(str116, arg_r);
  arg = Alloc<arg_types::export_>(attrs->attrs);
  if (arg->f) {
    e_usage(str117, loc::Missing);
  }
  if ((arg->p or len(cmd_val->pairs) == 0)) {
    return _PrintVariables(this->mem, cmd_val, attrs, true, _EXPORT);
  }
  if (arg->n) {
    for (ListIter<runtime_asdl::AssignArg*> it(cmd_val->pairs); !it.Done(); it.Next()) {
      runtime_asdl::AssignArg* pair = it.Value();
      StackRoot _for(&pair    );
      if (pair->rval != nullptr) {
        e_usage(str118, Alloc<loc::Word>(pair->blame_word));
      }
      this->mem->ClearFlag(pair->var_name, state::ClearExport);
    }
  }
  else {
    for (ListIter<runtime_asdl::AssignArg*> it(cmd_val->pairs); !it.Done(); it.Next()) {
      runtime_asdl::AssignArg* pair = it.Value();
      StackRoot _for(&pair    );
      _ExportReadonly(this->mem, pair, state::SetExport);
    }
  }
  return 0;
}

value_asdl::value_t* _ReconcileTypes(value_asdl::value_t* rval, bool flag_a, bool flag_A, syntax_asdl::word_t* blame_word) {
  value::BashArray* array_val = nullptr;
  StackRoot _root0(&rval);
  StackRoot _root1(&blame_word);
  StackRoot _root2(&array_val);

  if ((flag_a and (rval != nullptr and rval->tag() != value_e::BashArray))) {
    e_usage(str119, Alloc<loc::Word>(blame_word));
  }
  if ((flag_A and rval)) {
    if (rval->tag() == value_e::BashArray) {
      array_val = static_cast<value::BashArray*>(rval);
      if (len(array_val->strs) == 0) {
        return Alloc<value::BashAssoc>(Alloc<Dict<BigStr*, BigStr*>>());
      }
    }
    if (rval->tag() != value_e::BashAssoc) {
      e_usage(str120, Alloc<loc::Word>(blame_word));
    }
  }
  return rval;
}

Readonly::Readonly(state::Mem* mem, ui::ErrorFormatter* errfmt) {
  this->mem = mem;
  this->errfmt = errfmt;
}

int Readonly::Run(cmd_value::Assign* cmd_val) {
  args::Reader* arg_r = nullptr;
  args::_Attributes* attrs = nullptr;
  arg_types::readonly* arg = nullptr;
  value_asdl::value_t* rval = nullptr;
  StackRoot _root0(&cmd_val);
  StackRoot _root1(&arg_r);
  StackRoot _root2(&attrs);
  StackRoot _root3(&arg);
  StackRoot _root4(&rval);

  arg_r = Alloc<args::Reader>(cmd_val->argv, cmd_val->arg_locs);
  arg_r->Next();
  attrs = flag_util::Parse(str121, arg_r);
  arg = Alloc<arg_types::readonly>(attrs->attrs);
  if ((arg->p or len(cmd_val->pairs) == 0)) {
    return _PrintVariables(this->mem, cmd_val, attrs, true, _READONLY);
  }
  for (ListIter<runtime_asdl::AssignArg*> it(cmd_val->pairs); !it.Done(); it.Next()) {
    runtime_asdl::AssignArg* pair = it.Value();
    StackRoot _for(&pair  );
    if (pair->rval == nullptr) {
      if (arg->a) {
        rval = Alloc<value::BashArray>(Alloc<List<BigStr*>>());
      }
      else {
        if (arg->A) {
          rval = Alloc<value::BashAssoc>(Alloc<Dict<BigStr*, BigStr*>>());
        }
        else {
          rval = nullptr;
        }
      }
    }
    else {
      rval = pair->rval;
    }
    rval = _ReconcileTypes(rval, arg->a, arg->A, pair->blame_word);
    _ExportReadonly(this->mem, pair, state::SetReadOnly);
  }
  return 0;
}

NewVar::NewVar(state::Mem* mem, Dict<BigStr*, value::Proc*>* procs, optview::Exec* exec_opts, ui::ErrorFormatter* errfmt) {
  this->mem = mem;
  this->procs = procs;
  this->exec_opts = exec_opts;
  this->errfmt = errfmt;
}

int NewVar::_PrintFuncs(List<BigStr*>* names) {
  int status;
  StackRoot _root0(&names);

  status = 0;
  for (ListIter<BigStr*> it(names); !it.Done(); it.Next()) {
    BigStr* name = it.Value();
    StackRoot _for(&name  );
    if (dict_contains(this->procs, name)) {
      print(name);
    }
    else {
      status = 1;
    }
  }
  return status;
}

int NewVar::Run(cmd_value::Assign* cmd_val) {
  args::Reader* arg_r = nullptr;
  args::_Attributes* attrs = nullptr;
  arg_types::new_var* arg = nullptr;
  int status;
  List<BigStr*>* names = nullptr;
  runtime_asdl::scope_t which_scopes;
  int flags;
  value_asdl::value_t* rval = nullptr;
  value_asdl::value_t* old_val = nullptr;
  value_asdl::LeftName* lval = nullptr;
  StackRoot _root0(&cmd_val);
  StackRoot _root1(&arg_r);
  StackRoot _root2(&attrs);
  StackRoot _root3(&arg);
  StackRoot _root4(&names);
  StackRoot _root5(&rval);
  StackRoot _root6(&old_val);
  StackRoot _root7(&lval);

  arg_r = Alloc<args::Reader>(cmd_val->argv, cmd_val->arg_locs);
  arg_r->Next();
  attrs = flag_util::Parse(str122, arg_r);
  arg = Alloc<arg_types::new_var>(attrs->attrs);
  status = 0;
  if (arg->f) {
    names = arg_r->Rest();
    if (len(names)) {
      status = this->_PrintFuncs(names);
    }
    else {
      e_usage(str123, loc::Missing);
    }
    return status;
  }
  if (arg->F) {
    names = arg_r->Rest();
    if (len(names)) {
      status = this->_PrintFuncs(names);
    }
    else {
      for (ListIter<BigStr*> it(sorted(this->procs)); !it.Done(); it.Next()) {
        BigStr* func_name = it.Value();
        StackRoot _for(&func_name      );
        print(StrFormat("declare -f %s", func_name));
      }
    }
    return status;
  }
  if (arg->p) {
    return _PrintVariables(this->mem, cmd_val, attrs, true);
  }
  else {
    if (len(cmd_val->pairs) == 0) {
      return _PrintVariables(this->mem, cmd_val, attrs, false);
    }
  }
  if (!this->exec_opts->ignore_flags_not_impl()) {
    if (arg->i) {
      e_usage(str125, loc::Missing);
    }
    if ((arg->l or arg->u)) {
      this->errfmt->Print_(str126, loc::Missing);
    }
  }
  if (cmd_val->builtin_id == builtin_i::local) {
    which_scopes = scope_e::LocalOnly;
  }
  else {
    if (arg->g) {
      which_scopes = scope_e::GlobalOnly;
    }
    else {
      which_scopes = scope_e::LocalOnly;
    }
  }
  flags = 0;
  if (maybe_str_equals(arg->x, str127)) {
    flags |= state::SetExport;
  }
  if (maybe_str_equals(arg->r, str128)) {
    flags |= state::SetReadOnly;
  }
  if (maybe_str_equals(arg->n, str129)) {
    flags |= state::SetNameref;
  }
  if (maybe_str_equals(arg->x, str130)) {
    flags |= state::ClearExport;
  }
  if (maybe_str_equals(arg->r, str131)) {
    flags |= state::ClearReadOnly;
  }
  if (maybe_str_equals(arg->n, str132)) {
    flags |= state::ClearNameref;
  }
  for (ListIter<runtime_asdl::AssignArg*> it(cmd_val->pairs); !it.Done(); it.Next()) {
    runtime_asdl::AssignArg* pair = it.Value();
    StackRoot _for(&pair  );
    rval = pair->rval;
    if ((rval == nullptr and (arg->a or arg->A))) {
      old_val = this->mem->GetValue(pair->var_name);
      if (arg->a) {
        if (old_val->tag() != value_e::BashArray) {
          rval = Alloc<value::BashArray>(Alloc<List<BigStr*>>());
        }
      }
      else {
        if (arg->A) {
          if (old_val->tag() != value_e::BashAssoc) {
            rval = Alloc<value::BashAssoc>(Alloc<Dict<BigStr*, BigStr*>>());
          }
        }
      }
    }
    lval = Alloc<LeftName>(pair->var_name, pair->blame_word);
    if (pair->plus_eq) {
      old_val = sh_expr_eval::OldValue(lval, this->mem, nullptr);
      rval = cmd_eval::PlusEquals(old_val, pair->rval);
    }
    else {
      rval = _ReconcileTypes(rval, arg->a, arg->A, pair->blame_word);
    }
    this->mem->SetNamed(lval, rval, which_scopes, flags);
  }
  return status;
}

Unset::Unset(state::Mem* mem, Dict<BigStr*, value::Proc*>* procs, sh_expr_eval::UnsafeArith* unsafe_arith, ui::ErrorFormatter* errfmt) {
  this->mem = mem;
  this->procs = procs;
  this->unsafe_arith = unsafe_arith;
  this->errfmt = errfmt;
}

bool Unset::_UnsetVar(BigStr* arg, syntax_asdl::loc_t* location, bool proc_fallback) {
  value_asdl::sh_lvalue_t* lval = nullptr;
  bool found;
  BigStr* msg = nullptr;
  StackRoot _root0(&arg);
  StackRoot _root1(&location);
  StackRoot _root2(&lval);
  StackRoot _root3(&msg);

  lval = this->unsafe_arith->ParseLValue(arg, location);
  found = false;
  try {
    found = this->mem->Unset(lval, scope_e::Shopt);
  }
  catch (error::Runtime* e) {
    msg = e->UserErrorString();
    this->errfmt->Print_(msg, location);
    return false;
  }
  if ((proc_fallback and !found)) {
    mylib::dict_erase(this->procs, arg);
  }
  return true;
}

int Unset::Run(cmd_value::Argv* cmd_val) {
  args::_Attributes* attrs = nullptr;
  args::Reader* arg_r = nullptr;
  arg_types::unset* arg = nullptr;
  List<BigStr*>* argv = nullptr;
  List<syntax_asdl::CompoundWord*>* arg_locs = nullptr;
  int i;
  syntax_asdl::CompoundWord* location = nullptr;
  StackRoot _root0(&cmd_val);
  StackRoot _root1(&attrs);
  StackRoot _root2(&arg_r);
  StackRoot _root3(&arg);
  StackRoot _root4(&argv);
  StackRoot _root5(&arg_locs);
  StackRoot _root6(&location);

  Tuple2<args::_Attributes*, args::Reader*> tup0 = flag_util::ParseCmdVal(str133, cmd_val);
  attrs = tup0.at0();
  arg_r = tup0.at1();
  arg = Alloc<arg_types::unset>(attrs->attrs);
  Tuple2<List<BigStr*>*, List<syntax_asdl::CompoundWord*>*> tup1 = arg_r->Rest2();
  argv = tup1.at0();
  arg_locs = tup1.at1();
  i = 0;
  for (ListIter<BigStr*> it(argv); !it.Done(); it.Next(), ++i) {
    BigStr* name = it.Value();
    StackRoot _for(&name  );
    location = arg_locs->at(i);
    if (arg->f) {
      mylib::dict_erase(this->procs, name);
    }
    else {
      if (arg->v) {
        if (!this->_UnsetVar(name, location, false)) {
          return 1;
        }
      }
      else {
        if (!this->_UnsetVar(name, location, true)) {
          return 1;
        }
      }
    }
  }
  return 0;
}

Shift::Shift(state::Mem* mem) {
  this->mem = mem;
}

int Shift::Run(cmd_value::Argv* cmd_val) {
  int num_args;
  int n;
  BigStr* arg = nullptr;
  StackRoot _root0(&cmd_val);
  StackRoot _root1(&arg);

  num_args = (len(cmd_val->argv) - 1);
  if (num_args == 0) {
    n = 1;
  }
  else {
    if (num_args == 1) {
      arg = cmd_val->argv->at(1);
      try {
        n = to_int(arg);
      }
      catch (ValueError*) {
        e_usage(StrFormat("Invalid shift argument %r", arg), loc::Missing);
      }
    }
    else {
      e_usage(str135, loc::Missing);
    }
  }
  return this->mem->Shift(n);
}

}  // define namespace assign_osh

namespace completion_ysh {  // define

using syntax_asdl::loc;
using error::e_usage;

CompExport::CompExport(completion::RootCompleter* root_comp) {
  this->root_comp = root_comp;
}

int CompExport::Run(cmd_value::Argv* cmd_val) {
  args::Reader* arg_r = nullptr;
  args::_Attributes* attrs = nullptr;
  arg_types::compexport* arg = nullptr;
  int arg_begin;
  int arg_end;
  int begin;
  int end;
  completion::Api* comp = nullptr;
  List<BigStr*>* comp_matches = nullptr;
  mylib::BufWriter* buf = nullptr;
  StackRoot _root0(&cmd_val);
  StackRoot _root1(&arg_r);
  StackRoot _root2(&attrs);
  StackRoot _root3(&arg);
  StackRoot _root4(&comp);
  StackRoot _root5(&comp_matches);
  StackRoot _root6(&buf);

  arg_r = Alloc<args::Reader>(cmd_val->argv, cmd_val->arg_locs);
  arg_r->Next();
  attrs = flag_util::ParseMore(str136, arg_r);
  arg = Alloc<arg_types::compexport>(attrs->attrs);
  if (arg->c == nullptr) {
    e_usage(str137, loc::Missing);
  }
  arg_begin = mops::BigTruncate(arg->begin);
  arg_end = mops::BigTruncate(arg->end);
  begin = arg_begin == -1 ? 0 : arg_begin;
  end = arg_end == -1 ? len(arg->c) : arg_end;
  comp = Alloc<completion::Api>(arg->c, begin, end);
  List<BigStr*> _iter_buf_it;
  this->root_comp->Matches(comp, &_iter_buf_it);
  ListIter<BigStr*> it(&_iter_buf_it);
  comp_matches = list(it);
  comp_matches->reverse();
  if (maybe_str_equals(arg->format, str138)) {
    buf = Alloc<mylib::BufWriter>();
    for (ListIter<BigStr*> it(comp_matches); !it.Done(); it.Next()) {
      BigStr* m = it.Value();
      StackRoot _for(&m    );
      j8::EncodeString(m, buf);
      print(buf->getvalue());
      buf->clear();
    }
  }
  else {
    if (maybe_str_equals(arg->format, str139)) {
      mylib::print_stderr(str140);
    }
    else {
      assert(0);  // AssertionError
    }
  }
  return 0;
}

}  // define namespace completion_ysh

namespace dirs_osh {  // define

using runtime_asdl::cmd_value;
using error::e_usage;

DirStack::DirStack() {
  this->stack = Alloc<List<BigStr*>>();
  this->Reset();
}

void DirStack::Reset() {
  this->stack->clear();
  this->stack->append(posix::getcwd());
}

void DirStack::Replace(BigStr* d) {
  StackRoot _root0(&d);

  this->stack->set(-1, d);
}

void DirStack::Push(BigStr* entry) {
  StackRoot _root0(&entry);

  this->stack->append(entry);
}

BigStr* DirStack::Pop() {
  if (len(this->stack) <= 1) {
    return nullptr;
  }
  this->stack->pop();
  return this->stack->at(-1);
}

List<BigStr*>* DirStack::Iter() {
  List<BigStr*>* ret = nullptr;
  StackRoot _root0(&ret);

  ret = Alloc<List<BigStr*>>();
  ret->extend(this->stack);
  ret->reverse();
  return ret;
}

ctx_CdBlock::ctx_CdBlock(dirs_osh::DirStack* dir_stack, BigStr* dest_dir, state::Mem* mem, ui::ErrorFormatter* errfmt, List<bool>* out_errs) {
  gHeap.PushRoot(reinterpret_cast<RawObject**>(&(this->dir_stack)));
  gHeap.PushRoot(reinterpret_cast<RawObject**>(&(this->errfmt)));
  gHeap.PushRoot(reinterpret_cast<RawObject**>(&(this->mem)));
  gHeap.PushRoot(reinterpret_cast<RawObject**>(&(this->out_errs)));
  dir_stack->Push(dest_dir);
  this->dir_stack = dir_stack;
  this->mem = mem;
  this->errfmt = errfmt;
  this->out_errs = out_errs;
}

ctx_CdBlock::~ctx_CdBlock() {
  _PopDirStack(str141, this->mem, this->dir_stack, this->errfmt, this->out_errs);
  gHeap.PopRoot();
  gHeap.PopRoot();
  gHeap.PopRoot();
  gHeap.PopRoot();
}

Cd::Cd(state::Mem* mem, dirs_osh::DirStack* dir_stack, cmd_eval::CommandEvaluator* cmd_ev, ui::ErrorFormatter* errfmt) {
  this->mem = mem;
  this->dir_stack = dir_stack;
  this->cmd_ev = cmd_ev;
  this->errfmt = errfmt;
}

int Cd::Run(cmd_value::Argv* cmd_val) {
  args::_Attributes* attrs = nullptr;
  args::Reader* arg_r = nullptr;
  arg_types::cd* arg = nullptr;
  syntax_asdl::command_t* cmd = nullptr;
  BigStr* dest_dir = nullptr;
  syntax_asdl::loc_t* arg_loc = nullptr;
  BigStr* extra = nullptr;
  syntax_asdl::loc_t* extra_loc = nullptr;
  BigStr* pwd = nullptr;
  BigStr* abspath = nullptr;
  BigStr* real_dest_dir = nullptr;
  int err_num;
  List<bool>* out_errs = nullptr;
  int unused;
  StackRoot _root0(&cmd_val);
  StackRoot _root1(&attrs);
  StackRoot _root2(&arg_r);
  StackRoot _root3(&arg);
  StackRoot _root4(&cmd);
  StackRoot _root5(&dest_dir);
  StackRoot _root6(&arg_loc);
  StackRoot _root7(&extra);
  StackRoot _root8(&extra_loc);
  StackRoot _root9(&pwd);
  StackRoot _root10(&abspath);
  StackRoot _root11(&real_dest_dir);
  StackRoot _root12(&out_errs);

  Tuple2<args::_Attributes*, args::Reader*> tup0 = flag_util::ParseCmdVal(str142, cmd_val, true);
  attrs = tup0.at0();
  arg_r = tup0.at1();
  arg = Alloc<arg_types::cd>(attrs->attrs);
  cmd = typed_args::OptionalBlock(cmd_val);
  Tuple2<BigStr*, syntax_asdl::loc_t*> tup1 = arg_r->Peek2();
  dest_dir = tup1.at0();
  arg_loc = tup1.at1();
  if (dest_dir == nullptr) {
    if (cmd) {
      throw Alloc<error::Usage>(str143, cmd_val->arg_locs->at(0));
    }
    else {
      try {
        dest_dir = state::GetString(this->mem, str144);
      }
      catch (error::Runtime* e) {
        this->errfmt->Print_(e->UserErrorString());
        return 1;
      }
    }
  }
  arg_r->Next();
  Tuple2<BigStr*, syntax_asdl::loc_t*> tup2 = arg_r->Peek2();
  extra = tup2.at0();
  extra_loc = tup2.at1();
  if (extra != nullptr) {
    throw Alloc<error::Usage>(str145, extra_loc);
  }
  if (str_equals(dest_dir, str146)) {
    try {
      dest_dir = state::GetString(this->mem, str147);
      print(dest_dir);
    }
    catch (error::Runtime* e) {
      this->errfmt->Print_(e->UserErrorString());
      return 1;
    }
  }
  try {
    pwd = state::GetString(this->mem, str148);
  }
  catch (error::Runtime* e) {
    this->errfmt->Print_(e->UserErrorString());
    return 1;
  }
  abspath = os_path::join(pwd, dest_dir);
  if (arg->P) {
    real_dest_dir = libc::realpath(abspath);
  }
  else {
    real_dest_dir = os_path::normpath(abspath);
  }
  err_num = pyos::Chdir(real_dest_dir);
  if (err_num != 0) {
    this->errfmt->Print_(StrFormat("cd %r: %s", real_dest_dir, posix::strerror(err_num)), arg_loc);
    return 1;
  }
  state::ExportGlobalString(this->mem, str150, real_dest_dir);
  this->mem->SetPwd(real_dest_dir);
  if (cmd) {
    out_errs = Alloc<List<bool>>();
    {  // with
      ctx_CdBlock ctx{this->dir_stack, real_dest_dir, this->mem, this->errfmt, out_errs};

      unused = this->cmd_ev->EvalCommand(cmd);
    }
    if (len(out_errs)) {
      return 1;
    }
  }
  else {
    state::ExportGlobalString(this->mem, str151, pwd);
    this->dir_stack->Replace(real_dest_dir);
  }
  return 0;
}
int WITH_LINE_NUMBERS = 1;
int WITHOUT_LINE_NUMBERS = 2;
int SINGLE_LINE = 3;

void _PrintDirStack(dirs_osh::DirStack* dir_stack, int style, BigStr* home_dir) {
  int i;
  List<BigStr*>* parts = nullptr;
  BigStr* s = nullptr;
  StackRoot _root0(&dir_stack);
  StackRoot _root1(&home_dir);
  StackRoot _root2(&parts);
  StackRoot _root3(&s);

  if (style == WITH_LINE_NUMBERS) {
    i = 0;
    for (ListIter<BigStr*> it(dir_stack->Iter()); !it.Done(); it.Next(), ++i) {
      BigStr* entry = it.Value();
      StackRoot _for(&entry    );
      print(StrFormat("%2d  %s", i, ui::PrettyDir(entry, home_dir)));
    }
  }
  else {
    if (style == WITHOUT_LINE_NUMBERS) {
      for (ListIter<BigStr*> it(dir_stack->Iter()); !it.Done(); it.Next()) {
        BigStr* entry = it.Value();
        StackRoot _for(&entry      );
        print(ui::PrettyDir(entry, home_dir));
      }
    }
    else {
      if (style == SINGLE_LINE) {
        parts = Alloc<List<BigStr*>>();
        for (ListIter<BigStr*> it(dir_stack->Iter()); !it.Done(); it.Next()) {
          BigStr* entry = it.Value();
          parts->append(ui::PrettyDir(entry, home_dir));
        }
        s = str153->join(parts);
        print(s);
      }
    }
  }
}

Pushd::Pushd(state::Mem* mem, dirs_osh::DirStack* dir_stack, ui::ErrorFormatter* errfmt) {
  this->mem = mem;
  this->dir_stack = dir_stack;
  this->errfmt = errfmt;
}

int Pushd::Run(cmd_value::Argv* cmd_val) {
  args::Reader* arg_r = nullptr;
  BigStr* dir_arg = nullptr;
  syntax_asdl::loc_t* dir_arg_loc = nullptr;
  BigStr* extra = nullptr;
  syntax_asdl::loc_t* extra_loc = nullptr;
  BigStr* dest_dir = nullptr;
  int err_num;
  StackRoot _root0(&cmd_val);
  StackRoot _root1(&arg_r);
  StackRoot _root2(&dir_arg);
  StackRoot _root3(&dir_arg_loc);
  StackRoot _root4(&extra);
  StackRoot _root5(&extra_loc);
  StackRoot _root6(&dest_dir);

  Tuple2<args::_Attributes*, args::Reader*> tup3 = flag_util::ParseCmdVal(str154, cmd_val);
  arg_r = tup3.at1();
  Tuple2<BigStr*, syntax_asdl::loc_t*> tup4 = arg_r->Peek2();
  dir_arg = tup4.at0();
  dir_arg_loc = tup4.at1();
  if (dir_arg == nullptr) {
    this->errfmt->Print_(str155);
    return 1;
  }
  arg_r->Next();
  Tuple2<BigStr*, syntax_asdl::loc_t*> tup5 = arg_r->Peek2();
  extra = tup5.at0();
  extra_loc = tup5.at1();
  if (extra != nullptr) {
    e_usage(str156, extra_loc);
  }
  dest_dir = os_path::abspath(dir_arg);
  err_num = pyos::Chdir(dest_dir);
  if (err_num != 0) {
    this->errfmt->Print_(StrFormat("pushd: %r: %s", dest_dir, posix::strerror(err_num)), dir_arg_loc);
    return 1;
  }
  this->dir_stack->Push(dest_dir);
  _PrintDirStack(this->dir_stack, SINGLE_LINE, state::MaybeString(this->mem, str158));
  state::ExportGlobalString(this->mem, str159, dest_dir);
  this->mem->SetPwd(dest_dir);
  return 0;
}

bool _PopDirStack(BigStr* label, state::Mem* mem, dirs_osh::DirStack* dir_stack, ui::ErrorFormatter* errfmt, List<bool>* out_errs) {
  BigStr* dest_dir = nullptr;
  int err_num;
  StackRoot _root0(&label);
  StackRoot _root1(&mem);
  StackRoot _root2(&dir_stack);
  StackRoot _root3(&errfmt);
  StackRoot _root4(&out_errs);
  StackRoot _root5(&dest_dir);

  dest_dir = dir_stack->Pop();
  if (dest_dir == nullptr) {
    errfmt->Print_(StrFormat("%s: directory stack is empty", label));
    out_errs->append(true);
    return false;
  }
  err_num = pyos::Chdir(dest_dir);
  if (err_num != 0) {
    errfmt->Print_(StrFormat("%s: %r: %s", label, dest_dir, posix::strerror(err_num)));
    out_errs->append(true);
    return false;
  }
  state::SetGlobalString(mem, str162, dest_dir);
  mem->SetPwd(dest_dir);
  return true;
}

Popd::Popd(state::Mem* mem, dirs_osh::DirStack* dir_stack, ui::ErrorFormatter* errfmt) {
  this->mem = mem;
  this->dir_stack = dir_stack;
  this->errfmt = errfmt;
}

int Popd::Run(cmd_value::Argv* cmd_val) {
  args::Reader* arg_r = nullptr;
  BigStr* extra = nullptr;
  syntax_asdl::loc_t* extra_loc = nullptr;
  List<bool>* out_errs = nullptr;
  StackRoot _root0(&cmd_val);
  StackRoot _root1(&arg_r);
  StackRoot _root2(&extra);
  StackRoot _root3(&extra_loc);
  StackRoot _root4(&out_errs);

  Tuple2<args::_Attributes*, args::Reader*> tup6 = flag_util::ParseCmdVal(str163, cmd_val);
  arg_r = tup6.at1();
  Tuple2<BigStr*, syntax_asdl::loc_t*> tup7 = arg_r->Peek2();
  extra = tup7.at0();
  extra_loc = tup7.at1();
  if (extra != nullptr) {
    e_usage(str164, extra_loc);
  }
  out_errs = Alloc<List<bool>>();
  _PopDirStack(str165, this->mem, this->dir_stack, this->errfmt, out_errs);
  if (len(out_errs)) {
    return 1;
  }
  _PrintDirStack(this->dir_stack, SINGLE_LINE, state::MaybeString(this->mem, str166));
  return 0;
}

Dirs::Dirs(state::Mem* mem, dirs_osh::DirStack* dir_stack, ui::ErrorFormatter* errfmt) {
  this->mem = mem;
  this->dir_stack = dir_stack;
  this->errfmt = errfmt;
}

int Dirs::Run(cmd_value::Argv* cmd_val) {
  args::_Attributes* attrs = nullptr;
  args::Reader* arg_r = nullptr;
  arg_types::dirs* arg = nullptr;
  BigStr* home_dir = nullptr;
  int style;
  StackRoot _root0(&cmd_val);
  StackRoot _root1(&attrs);
  StackRoot _root2(&arg_r);
  StackRoot _root3(&arg);
  StackRoot _root4(&home_dir);

  Tuple2<args::_Attributes*, args::Reader*> tup8 = flag_util::ParseCmdVal(str167, cmd_val);
  attrs = tup8.at0();
  arg_r = tup8.at1();
  arg = Alloc<arg_types::dirs>(attrs->attrs);
  home_dir = state::MaybeString(this->mem, str168);
  style = SINGLE_LINE;
  if (arg->l) {
    home_dir = nullptr;
  }
  if (arg->c) {
    this->dir_stack->Reset();
    return 0;
  }
  else {
    if (arg->v) {
      style = WITH_LINE_NUMBERS;
    }
    else {
      if (arg->p) {
        style = WITHOUT_LINE_NUMBERS;
      }
    }
  }
  _PrintDirStack(this->dir_stack, style, home_dir);
  return 0;
}

Pwd::Pwd(state::Mem* mem, ui::ErrorFormatter* errfmt) {
  this->mem = mem;
  this->errfmt = errfmt;
}

int Pwd::Run(cmd_value::Argv* cmd_val) {
  args::_Attributes* attrs = nullptr;
  args::Reader* arg_r = nullptr;
  arg_types::pwd* arg = nullptr;
  BigStr* pwd = nullptr;
  StackRoot _root0(&cmd_val);
  StackRoot _root1(&attrs);
  StackRoot _root2(&arg_r);
  StackRoot _root3(&arg);
  StackRoot _root4(&pwd);

  Tuple2<args::_Attributes*, args::Reader*> tup9 = flag_util::ParseCmdVal(str169, cmd_val);
  attrs = tup9.at0();
  arg_r = tup9.at1();
  arg = Alloc<arg_types::pwd>(attrs->attrs);
  pwd = this->mem->pwd;
  if (arg->P) {
    pwd = libc::realpath(pwd);
  }
  print(pwd);
  return 0;
}

}  // define namespace dirs_osh

namespace error_ysh {  // define

using option_asdl::option_i;
using runtime_asdl::cmd_value;
using runtime_asdl::CommandStatus;
using syntax_asdl::loc;
using value_asdl::value;
using value_asdl::value_e;
using error::e_die_status;
using error::e_usage;

ctx_Try::ctx_Try(state::MutableOpts* mutable_opts) {
  gHeap.PushRoot(reinterpret_cast<RawObject**>(&(this->mutable_opts)));
  mutable_opts->Push(option_i::errexit, true);
  this->mutable_opts = mutable_opts;
}

ctx_Try::~ctx_Try() {
  this->mutable_opts->Pop(option_i::errexit);
  gHeap.PopRoot();
}

Try::Try(state::MutableOpts* mutable_opts, state::Mem* mem, cmd_eval::CommandEvaluator* cmd_ev, vm::_Executor* shell_ex, ui::ErrorFormatter* errfmt) {
  this->mutable_opts = mutable_opts;
  this->mem = mem;
  this->shell_ex = shell_ex;
  this->cmd_ev = cmd_ev;
  this->errfmt = errfmt;
}

int Try::Run(cmd_value::Argv* cmd_val) {
  args::Reader* arg_r = nullptr;
  typed_args::Reader* rd = nullptr;
  syntax_asdl::command_t* cmd = nullptr;
  value::Dict* error_dict = nullptr;
  int status;
  int unused;
  StackRoot _root0(&cmd_val);
  StackRoot _root1(&arg_r);
  StackRoot _root2(&rd);
  StackRoot _root3(&cmd);
  StackRoot _root4(&error_dict);

  Tuple2<args::_Attributes*, args::Reader*> tup0 = flag_util::ParseCmdVal(str170, cmd_val, true);
  arg_r = tup0.at1();
  rd = typed_args::ReaderForProc(cmd_val);
  cmd = rd->RequiredBlock();
  rd->Done();
  error_dict = nullptr;
  status = 0;
  try {
    {  // with
      ctx_Try ctx{this->mutable_opts};

      unused = this->cmd_ev->EvalCommand(cmd);
    }
  }
  catch (error::Expr* e) {
    status = e->ExitStatus();
  }
  catch (error::ErrExit* e) {
    status = e->ExitStatus();
  }
  catch (error::Structured* e) {
    status = e->ExitStatus();
    error_dict = e->ToDict();
  }
  if (error_dict == nullptr) {
    error_dict = Alloc<value::Dict>(Alloc<Dict<BigStr*, value_asdl::value_t*>>(std::initializer_list<BigStr*>{str171}, std::initializer_list<value_asdl::value_t*>{num::ToBig(status)}));
  }
  this->mem->SetTryError(error_dict);
  this->mem->SetTryStatus(status);
  return 0;
}

Failed::Failed(state::Mem* mem) {
  this->mem = mem;
}

int Failed::Run(cmd_value::Argv* cmd_val) {
  args::Reader* arg_r = nullptr;
  value::Dict* err = nullptr;
  value_asdl::value_t* code = nullptr;
  value_asdl::value_t* UP_code = nullptr;
  StackRoot _root0(&cmd_val);
  StackRoot _root1(&arg_r);
  StackRoot _root2(&err);
  StackRoot _root3(&code);
  StackRoot _root4(&UP_code);

  Tuple2<args::_Attributes*, args::Reader*> tup1 = flag_util::ParseCmdVal(str172, cmd_val);
  arg_r = tup1.at1();
  arg_r->Done();
  err = this->mem->TryError();
  code = err->d->get(str173);
  if (code == nullptr) {
    return 1;
  }
  UP_code = code;
  switch (code->tag()) {
    case value_e::Int: {
      value::Int* code = static_cast<value::Int*>(UP_code);
      return mops::Equal(code->i, mops::ZERO) ? 1 : 0;
    }
      break;
    default: {
      assert(0);  // AssertionError
    }
  }
}

Error::Error() {
  ;  // pass
}

int Error::Run(cmd_value::Argv* cmd_val) {
  args::Reader* arg_r = nullptr;
  BigStr* message = nullptr;
  typed_args::Reader* rd = nullptr;
  int status;
  Dict<BigStr*, value_asdl::value_t*>* properties = nullptr;
  StackRoot _root0(&cmd_val);
  StackRoot _root1(&arg_r);
  StackRoot _root2(&message);
  StackRoot _root3(&rd);
  StackRoot _root4(&properties);

  Tuple2<args::_Attributes*, args::Reader*> tup2 = flag_util::ParseCmdVal(str174, cmd_val, true);
  arg_r = tup2.at1();
  message = arg_r->Peek();
  if (message == nullptr) {
    throw Alloc<error::Usage>(str175, cmd_val->arg_locs->at(0));
  }
  rd = typed_args::ReaderForProc(cmd_val);
  status = mops::BigTruncate(rd->NamedInt(str176, 10));
  properties = rd->RestNamed();
  rd->Done();
  if (status == 0) {
    throw Alloc<error::Usage>(str177, cmd_val->arg_locs->at(0));
  }
  throw Alloc<error::Structured>(status, message, cmd_val->arg_locs->at(0), properties);
}

BoolStatus::BoolStatus(vm::_Executor* shell_ex, ui::ErrorFormatter* errfmt) {
  this->shell_ex = shell_ex;
  this->errfmt = errfmt;
}

int BoolStatus::Run(cmd_value::Argv* cmd_val) {
  args::Reader* arg_r = nullptr;
  List<BigStr*>* argv = nullptr;
  List<syntax_asdl::CompoundWord*>* locs = nullptr;
  cmd_value::Argv* cmd_val2 = nullptr;
  runtime_asdl::CommandStatus* cmd_st = nullptr;
  int status;
  StackRoot _root0(&cmd_val);
  StackRoot _root1(&arg_r);
  StackRoot _root2(&argv);
  StackRoot _root3(&locs);
  StackRoot _root4(&cmd_val2);
  StackRoot _root5(&cmd_st);

  Tuple2<args::_Attributes*, args::Reader*> tup3 = flag_util::ParseCmdVal(str178, cmd_val);
  arg_r = tup3.at1();
  if (arg_r->Peek() == nullptr) {
    e_usage(str179, loc::Missing);
  }
  Tuple2<List<BigStr*>*, List<syntax_asdl::CompoundWord*>*> tup4 = arg_r->Rest2();
  argv = tup4.at0();
  locs = tup4.at1();
  cmd_val2 = Alloc<cmd_value::Argv>(argv, locs, cmd_val->typed_args, cmd_val->pos_args, cmd_val->named_args, cmd_val->block_arg);
  cmd_st = CommandStatus::CreateNull(true);
  status = this->shell_ex->RunSimpleCommand(cmd_val2, cmd_st, executor::DO_FORK);
  if ((status != 0 && status != 1)) {
    e_die_status(status, StrFormat("boolstatus expected status 0 or 1, got %d", status), locs->at(0));
  }
  return status;
}

}  // define namespace error_ysh

namespace func_eggex {  // define

using syntax_asdl::loc_t;
using syntax_asdl::Token;
using value_asdl::value;
using value_asdl::value_e;
using value_asdl::value_t;
using value_asdl::eggex_ops;
using value_asdl::eggex_ops_e;
using value_asdl::eggex_ops_t;
using value_asdl::regex_match_e;
using value_asdl::RegexMatch;
int G = 0;
int S = 1;
int E = 2;

_MatchCallable::_MatchCallable(int to_return, expr_eval::ExprEvaluator* expr_ev) {
  this->to_return = to_return;
  this->expr_ev = expr_ev;
}

value_asdl::value_t* _MatchCallable::_ReturnValue(value_asdl::RegexMatch* match, int group_index, syntax_asdl::loc_t* blame_loc) {
  int num_groups;
  int start;
  int end;
  value_asdl::value_t* val = nullptr;
  value_asdl::value_t* convert_func = nullptr;
  syntax_asdl::Token* convert_tok = nullptr;
  eggex_ops::Yes* ops = nullptr;
  StackRoot _root0(&match);
  StackRoot _root1(&blame_loc);
  StackRoot _root2(&val);
  StackRoot _root3(&convert_func);
  StackRoot _root4(&convert_tok);
  StackRoot _root5(&ops);

  num_groups = (len(match->indices) / 2);
  if (group_index < num_groups) {
    start = match->indices->at((2 * group_index));
    if (this->to_return == S) {
      return num::ToBig(start);
    }
    end = match->indices->at(((2 * group_index) + 1));
    if (this->to_return == E) {
      return num::ToBig(end);
    }
    if (start == -1) {
      return value::Null;
    }
    else {
      val = Alloc<value::Str>(match->s->slice(start, end));
      convert_func = nullptr;
      convert_tok = nullptr;
      switch (match->ops->tag()) {
        case eggex_ops_e::Yes: {
          ops = static_cast<eggex_ops::Yes*>(match->ops);
          if ((len(ops->convert_funcs) and group_index != 0)) {
            convert_func = ops->convert_funcs->at((group_index - 1));
            convert_tok = ops->convert_toks->at((group_index - 1));
          }
        }
          break;
      }
      if (convert_func != nullptr) {
        val = this->expr_ev->CallConvertFunc(convert_func, val, convert_tok, blame_loc);
      }
      return val;
    }
  }
  else {
    throw Alloc<error::Expr>(StrFormat("Expected capture group less than %d, got %d", num_groups, group_index), blame_loc);
  }
}

value_asdl::value_t* _MatchCallable::_Call(value_asdl::RegexMatch* match, value_asdl::value_t* group_arg, syntax_asdl::loc_t* blame_loc) {
  int group_index;
  StackRoot _root0(&match);
  StackRoot _root1(&group_arg);
  StackRoot _root2(&blame_loc);

  group_index = _GetGroupIndex(group_arg, match->ops, blame_loc);
  return this->_ReturnValue(match, group_index, blame_loc);
}

int _GetGroupIndex(value_asdl::value_t* group, value_asdl::eggex_ops_t* ops, syntax_asdl::loc_t* blame_loc) {
  value_asdl::value_t* UP_group = nullptr;
  int group_index;
  mops::BigInt group_index_big;
  value_asdl::eggex_ops_t* UP_ops = nullptr;
  int i;
  StackRoot _root0(&group);
  StackRoot _root1(&ops);
  StackRoot _root2(&blame_loc);
  StackRoot _root3(&UP_group);
  StackRoot _root4(&UP_ops);

  UP_group = group;
  group_index = -1;
  switch (group->tag()) {
    case value_e::Int: {
      value::Int* group = static_cast<value::Int*>(UP_group);
      group_index_big = group->i;
      group_index = mops::BigTruncate(group_index_big);
    }
      break;
    case value_e::Str: {
      value::Str* group = static_cast<value::Str*>(UP_group);
      UP_ops = ops;
      switch (ops->tag()) {
        case eggex_ops_e::No: {
          throw Alloc<error::Expr>(StrFormat("ERE captures don't have names (%r)", group->s), blame_loc);
        }
          break;
        case eggex_ops_e::Yes: {
          eggex_ops::Yes* ops = static_cast<eggex_ops::Yes*>(UP_ops);
          i = 0;
          for (ListIter<BigStr*> it(ops->capture_names); !it.Done(); it.Next(), ++i) {
            BigStr* name = it.Value();
            StackRoot _for(&name          );
            if (str_equals(name, group->s)) {
              group_index = (i + 1);
              break;
            }
          }
          if (group_index == -1) {
            throw Alloc<error::Expr>(StrFormat("No such group %r", group->s), blame_loc);
          }
        }
          break;
      }
    }
      break;
    default: {
      throw Alloc<error::TypeErr>(group, str184, blame_loc);
    }
  }
  return group_index;
}

MatchFunc::MatchFunc(int to_return, expr_eval::ExprEvaluator* expr_ev, state::Mem* mem) : ::func_eggex::_MatchCallable(to_return, expr_ev) {
  this->mem = mem;
}

value_asdl::value_t* MatchFunc::Call(typed_args::Reader* rd) {
  value_asdl::value_t* group_arg = nullptr;
  value_asdl::regex_match_t* match = nullptr;
  value_asdl::regex_match_t* UP_match = nullptr;
  StackRoot _root0(&rd);
  StackRoot _root1(&group_arg);
  StackRoot _root2(&match);
  StackRoot _root3(&UP_match);

  group_arg = rd->PosValue();
  rd->Done();
  match = this->mem->GetRegexMatch();
  UP_match = match;
  switch (match->tag()) {
    case regex_match_e::No: {
      throw Alloc<error::Expr>(str185, rd->LeftParenToken());
    }
      break;
    case regex_match_e::Yes: {
      RegexMatch* match = static_cast<RegexMatch*>(UP_match);
      return this->_Call(match, group_arg, rd->LeftParenToken());
    }
      break;
  }
  assert(0);  // AssertionError
}

MatchMethod::MatchMethod(int to_return, expr_eval::ExprEvaluator* expr_ev) : ::func_eggex::_MatchCallable(to_return, expr_ev) {
}

value_asdl::value_t* MatchMethod::Call(typed_args::Reader* rd) {
  value_asdl::RegexMatch* match = nullptr;
  value_asdl::value_t* group_arg = nullptr;
  StackRoot _root0(&rd);
  StackRoot _root1(&match);
  StackRoot _root2(&group_arg);

  match = rd->PosMatch();
  group_arg = rd->PosValue();
  rd->Done();
  return this->_Call(match, group_arg, rd->LeftParenToken());
}

}  // define namespace func_eggex

namespace func_hay {  // define

using syntax_asdl::source;
using syntax_asdl::loc;
using syntax_asdl::command_t;
using value_asdl::value;

ParseHay::ParseHay(process::FdState* fd_state, parse_lib::ParseContext* parse_ctx, ui::ErrorFormatter* errfmt) {
  this->fd_state = fd_state;
  this->parse_ctx = parse_ctx;
  this->errfmt = errfmt;
}

value_asdl::value_t* ParseHay::_Call(BigStr* path) {
  syntax_asdl::loc__Missing* call_loc = nullptr;
  mylib::LineReader* f = nullptr;
  BigStr* msg = nullptr;
  alloc::Arena* arena = nullptr;
  reader::FileLineReader* line_reader = nullptr;
  optview::Parse* parse_opts = nullptr;
  cmd_parse::CommandParser* c_parser = nullptr;
  source::SourcedFile* src = nullptr;
  syntax_asdl::command_t* node = nullptr;
  StackRoot _root0(&path);
  StackRoot _root1(&call_loc);
  StackRoot _root2(&f);
  StackRoot _root3(&msg);
  StackRoot _root4(&arena);
  StackRoot _root5(&line_reader);
  StackRoot _root6(&parse_opts);
  StackRoot _root7(&c_parser);
  StackRoot _root8(&src);
  StackRoot _root9(&node);

  call_loc = loc::Missing;
  try {
    f = this->fd_state->Open(path);
  }
  catch (IOError_OSError* e) {
    msg = posix::strerror(e->errno_);
    throw Alloc<error::Expr>(StrFormat("Couldn't open %r: %s", path, msg), call_loc);
  }
  arena = this->parse_ctx->arena;
  line_reader = Alloc<reader::FileLineReader>(f, arena);
  parse_opts = state::MakeOilOpts();
  c_parser = this->parse_ctx->MakeConfigParser(line_reader);
  src = Alloc<source::SourcedFile>(path, call_loc);
  try {
    {  // with
      alloc::ctx_SourceCode ctx{arena, src};

      node = main_loop::ParseWholeFile(c_parser);
    }
  }
  catch (error::Parse* e) {
    this->errfmt->PrettyPrintError(e);
    return nullptr;
  }
  return Alloc<value::Command>(node);
}

value_asdl::value_t* ParseHay::Call(typed_args::Reader* rd) {
  BigStr* string = nullptr;
  StackRoot _root0(&rd);
  StackRoot _root1(&string);

  string = rd->PosStr();
  rd->Done();
  return this->_Call(string);
}

EvalHay::EvalHay(hay_ysh::HayState* hay_state, state::MutableOpts* mutable_opts, state::Mem* mem, cmd_eval::CommandEvaluator* cmd_ev) {
  this->hay_state = hay_state;
  this->mutable_opts = mutable_opts;
  this->mem = mem;
  this->cmd_ev = cmd_ev;
}

Dict<BigStr*, value_asdl::value_t*>* EvalHay::_Call(syntax_asdl::command_t* cmd) {
  int unused;
  StackRoot _root0(&cmd);

  {  // with
    hay_ysh::ctx_HayEval ctx{this->hay_state, this->mutable_opts, this->mem};

    unused = this->cmd_ev->EvalCommand(cmd);
  }
  return this->hay_state->Result();
}

value_asdl::value_t* EvalHay::Call(typed_args::Reader* rd) {
  syntax_asdl::command_t* cmd = nullptr;
  StackRoot _root0(&rd);
  StackRoot _root1(&cmd);

  cmd = rd->PosCommand();
  rd->Done();
  return Alloc<value::Dict>(this->_Call(cmd));
}

BlockAsStr::BlockAsStr(alloc::Arena* arena) {
  this->arena = arena;
}

value_asdl::value_t* BlockAsStr::_Call(value_asdl::value_t* block) {
  StackRoot _root0(&block);

  return block;
}

value_asdl::value_t* BlockAsStr::Call(typed_args::Reader* rd) {
  value_asdl::value_t* val = nullptr;
  StackRoot _root0(&rd);
  StackRoot _root1(&val);

  val = rd->PosValue();
  rd->Done();
  return this->_Call(val);
}

HayFunc::HayFunc(hay_ysh::HayState* hay_state) {
  this->hay_state = hay_state;
}

Dict<BigStr*, value_asdl::value_t*>* HayFunc::_Call() {
  return this->hay_state->HayRegister();
}

value_asdl::value_t* HayFunc::Call(typed_args::Reader* rd) {
  StackRoot _root0(&rd);

  return Alloc<value::Dict>(this->_Call());
}

}  // define namespace func_hay

namespace func_misc {  // define

using runtime_asdl::scope_e;
using value_asdl::value;
using value_asdl::value_e;
using value_asdl::value_t;
using value_asdl::value_str;

Len::Len() {
  ;  // pass
}

value_asdl::value_t* Len::Call(typed_args::Reader* rd) {
  value_asdl::value_t* x = nullptr;
  value_asdl::value_t* UP_x = nullptr;
  StackRoot _root0(&rd);
  StackRoot _root1(&x);
  StackRoot _root2(&UP_x);

  x = rd->PosValue();
  rd->Done();
  UP_x = x;
  switch (x->tag()) {
    case value_e::List: {
      value::List* x = static_cast<value::List*>(UP_x);
      return num::ToBig(len(x->items));
    }
      break;
    case value_e::Dict: {
      value::Dict* x = static_cast<value::Dict*>(UP_x);
      return num::ToBig(len(x->d));
    }
      break;
    case value_e::Str: {
      value::Str* x = static_cast<value::Str*>(UP_x);
      return num::ToBig(len(x->s));
    }
      break;
  }
  throw Alloc<error::TypeErr>(x, str187, rd->BlamePos());
}

Type::Type() {
  ;  // pass
}

value_asdl::value_t* Type::Call(typed_args::Reader* rd) {
  value_asdl::value_t* val = nullptr;
  StackRoot _root0(&rd);
  StackRoot _root1(&val);

  val = rd->PosValue();
  rd->Done();
  return Alloc<value::Str>(ui::ValType(val));
}

Repeat::Repeat() {
  ;  // pass
}

value_asdl::value_t* Repeat::Call(typed_args::Reader* rd) {
  StackRoot _root0(&rd);

  return value::Null;
}

Join::Join() {
  ;  // pass
}

value_asdl::value_t* Join::Call(typed_args::Reader* rd) {
  List<value_asdl::value_t*>* li = nullptr;
  BigStr* delim = nullptr;
  List<BigStr*>* strs = nullptr;
  int i;
  StackRoot _root0(&rd);
  StackRoot _root1(&li);
  StackRoot _root2(&delim);
  StackRoot _root3(&strs);

  li = rd->PosList();
  delim = rd->OptionalStr(str188);
  rd->Done();
  strs = Alloc<List<BigStr*>>();
  i = 0;
  for (ListIter<value_asdl::value_t*> it(li); !it.Done(); it.Next(), ++i) {
    value_asdl::value_t* el = it.Value();
    StackRoot _for(&el  );
    strs->append(val_ops::Stringify(el, rd->LeftParenToken()));
  }
  return Alloc<value::Str>(delim->join(strs));
}

Maybe::Maybe() {
  ;  // pass
}

value_asdl::value_t* Maybe::Call(typed_args::Reader* rd) {
  value_asdl::value_t* val = nullptr;
  BigStr* s = nullptr;
  StackRoot _root0(&rd);
  StackRoot _root1(&val);
  StackRoot _root2(&s);

  val = rd->PosValue();
  rd->Done();
  if (val == value::Null) {
    return Alloc<value::List>(Alloc<List<value_asdl::value_t*>>());
  }
  s = val_ops::ToStr(val, StrFormat("maybe() expected Str, but got %s", value_str(val->tag())), rd->LeftParenToken());
  if (len(s)) {
    return Alloc<value::List>(NewList<value_asdl::value_t*>(std::initializer_list<value_asdl::value_t*>{val}));
  }
  return Alloc<value::List>(Alloc<List<value_asdl::value_t*>>());
}

Bool::Bool() {
  ;  // pass
}

value_asdl::value_t* Bool::Call(typed_args::Reader* rd) {
  value_asdl::value_t* val = nullptr;
  StackRoot _root0(&rd);
  StackRoot _root1(&val);

  val = rd->PosValue();
  rd->Done();
  return Alloc<value::Bool>(val_ops::ToBool(val));
}

Int::Int() {
  ;  // pass
}

value_asdl::value_t* Int::Call(typed_args::Reader* rd) {
  value_asdl::value_t* val = nullptr;
  value_asdl::value_t* UP_val = nullptr;
  StackRoot _root0(&rd);
  StackRoot _root1(&val);
  StackRoot _root2(&UP_val);

  val = rd->PosValue();
  rd->Done();
  UP_val = val;
  switch (val->tag()) {
    case value_e::Int: {
      return val;
    }
      break;
    case value_e::Bool: {
      value::Bool* val = static_cast<value::Bool*>(UP_val);
      return Alloc<value::Int>(mops::FromBool(val->b));
    }
      break;
    case value_e::Float: {
      value::Float* val = static_cast<value::Float*>(UP_val);
      return Alloc<value::Int>(mops::FromFloat(val->f));
    }
      break;
    case value_e::Str: {
      value::Str* val = static_cast<value::Str*>(UP_val);
      if (!match::LooksLikeInteger(val->s)) {
        throw Alloc<error::Expr>(StrFormat("Cannot convert %s to Int", val->s), rd->BlamePos());
      }
      return Alloc<value::Int>(mops::FromStr(val->s));
    }
      break;
  }
  throw Alloc<error::TypeErr>(val, str191, rd->BlamePos());
}

Float::Float() {
  ;  // pass
}

value_asdl::value_t* Float::Call(typed_args::Reader* rd) {
  value_asdl::value_t* val = nullptr;
  value_asdl::value_t* UP_val = nullptr;
  StackRoot _root0(&rd);
  StackRoot _root1(&val);
  StackRoot _root2(&UP_val);

  val = rd->PosValue();
  rd->Done();
  UP_val = val;
  switch (val->tag()) {
    case value_e::Int: {
      value::Int* val = static_cast<value::Int*>(UP_val);
      return Alloc<value::Float>(mops::ToFloat(val->i));
    }
      break;
    case value_e::Float: {
      return val;
    }
      break;
    case value_e::Str: {
      value::Str* val = static_cast<value::Str*>(UP_val);
      if (!match::LooksLikeFloat(val->s)) {
        throw Alloc<error::Expr>(StrFormat("Cannot convert %s to Float", val->s), rd->BlamePos());
      }
      return Alloc<value::Float>(to_float(val->s));
    }
      break;
  }
  throw Alloc<error::TypeErr>(val, str193, rd->BlamePos());
}

Str_::Str_() {
  ;  // pass
}

value_asdl::value_t* Str_::Call(typed_args::Reader* rd) {
  value_asdl::value_t* val = nullptr;
  value_asdl::value_t* UP_val = nullptr;
  StackRoot _root0(&rd);
  StackRoot _root1(&val);
  StackRoot _root2(&UP_val);

  val = rd->PosValue();
  rd->Done();
  UP_val = val;
  switch (val->tag()) {
    case value_e::Int: {
      value::Int* val = static_cast<value::Int*>(UP_val);
      return Alloc<value::Str>(mops::ToStr(val->i));
    }
      break;
    case value_e::Float: {
      value::Float* val = static_cast<value::Float*>(UP_val);
      return Alloc<value::Str>(str(val->f));
    }
      break;
    case value_e::Str: {
      return val;
    }
      break;
  }
  throw Alloc<error::TypeErr>(val, str194, rd->BlamePos());
}

List_::List_() {
  ;  // pass
}

value_asdl::value_t* List_::Call(typed_args::Reader* rd) {
  value_asdl::value_t* val = nullptr;
  List<value_asdl::value_t*>* l = nullptr;
  val_ops::Iterator* it = nullptr;
  value_asdl::value_t* UP_val = nullptr;
  value_asdl::value_t* first = nullptr;
  StackRoot _root0(&rd);
  StackRoot _root1(&val);
  StackRoot _root2(&l);
  StackRoot _root3(&it);
  StackRoot _root4(&UP_val);
  StackRoot _root5(&first);

  val = rd->PosValue();
  rd->Done();
  l = Alloc<List<value_asdl::value_t*>>();
  it = nullptr;
  UP_val = val;
  switch (val->tag()) {
    case value_e::List: {
      value::List* val = static_cast<value::List*>(UP_val);
      it = Alloc<val_ops::ListIterator>(val);
    }
      break;
    case value_e::Dict: {
      value::Dict* val = static_cast<value::Dict*>(UP_val);
      it = Alloc<val_ops::DictIterator>(val);
    }
      break;
    case value_e::Range: {
      value::Range* val = static_cast<value::Range*>(UP_val);
      it = Alloc<val_ops::RangeIterator>(val);
    }
      break;
    default: {
      throw Alloc<error::TypeErr>(val, str195, rd->BlamePos());
    }
  }
  while (true) {
    first = it->FirstValue();
    if (first == nullptr) {
      break;
    }
    l->append(first);
    it->Next();
  }
  return Alloc<value::List>(l);
}

Dict_::Dict_() {
  ;  // pass
}

value_asdl::value_t* Dict_::Call(typed_args::Reader* rd) {
  value_asdl::value_t* val = nullptr;
  value_asdl::value_t* UP_val = nullptr;
  Dict<BigStr*, value_asdl::value_t*>* d = nullptr;
  StackRoot _root0(&rd);
  StackRoot _root1(&val);
  StackRoot _root2(&UP_val);
  StackRoot _root3(&d);

  val = rd->PosValue();
  rd->Done();
  UP_val = val;
  switch (val->tag()) {
    case value_e::Dict: {
      d = Alloc<Dict<BigStr*, value_asdl::value_t*>>();
      value::Dict* val = static_cast<value::Dict*>(UP_val);
      for (DictIter<BigStr*, value_asdl::value_t*> it(val->d); !it.Done(); it.Next()) {
        BigStr* k = it.Key();
        value_asdl::value_t* v = it.Value();
        d->set(k, v);
      }
      return Alloc<value::Dict>(d);
    }
      break;
    case value_e::BashAssoc: {
      d = Alloc<Dict<BigStr*, value_asdl::value_t*>>();
      value::BashAssoc* val = static_cast<value::BashAssoc*>(UP_val);
      for (DictIter<BigStr*, BigStr*> it(val->d); !it.Done(); it.Next()) {
        BigStr* k = it.Key();
        BigStr* s = it.Value();
        d->set(k, Alloc<value::Str>(s));
      }
      return Alloc<value::Dict>(d);
    }
      break;
  }
  throw Alloc<error::TypeErr>(val, str196, rd->BlamePos());
}

Runes::Runes() {
  ;  // pass
}

value_asdl::value_t* Runes::Call(typed_args::Reader* rd) {
  StackRoot _root0(&rd);

  return value::Null;
}

EncodeRunes::EncodeRunes() {
  ;  // pass
}

value_asdl::value_t* EncodeRunes::Call(typed_args::Reader* rd) {
  StackRoot _root0(&rd);

  return value::Null;
}

Bytes::Bytes() {
  ;  // pass
}

value_asdl::value_t* Bytes::Call(typed_args::Reader* rd) {
  StackRoot _root0(&rd);

  return value::Null;
}

EncodeBytes::EncodeBytes() {
  ;  // pass
}

value_asdl::value_t* EncodeBytes::Call(typed_args::Reader* rd) {
  StackRoot _root0(&rd);

  return value::Null;
}

Split::Split(split::SplitContext* splitter) : ::vm::_Callable() {
  this->splitter = splitter;
}

value_asdl::value_t* Split::Call(typed_args::Reader* rd) {
  BigStr* s = nullptr;
  BigStr* ifs = nullptr;
  List<value_asdl::value_t*>* l = nullptr;
  StackRoot _root0(&rd);
  StackRoot _root1(&s);
  StackRoot _root2(&ifs);
  StackRoot _root3(&l);

  s = rd->PosStr();
  ifs = rd->OptionalStr();
  rd->Done();
  l = Alloc<List<value_asdl::value_t*>>();
  for (ListIter<BigStr*> it(this->splitter->SplitForWordEval(s, ifs)); !it.Done(); it.Next()) {
    BigStr* elem = it.Value();
    l->append(Alloc<value::Str>(elem));
  }
  return Alloc<value::List>(l);
}

Glob::Glob(glob_::Globber* globber) : ::vm::_Callable() {
  this->globber = globber;
}

value_asdl::value_t* Glob::Call(typed_args::Reader* rd) {
  BigStr* s = nullptr;
  List<BigStr*>* out = nullptr;
  List<value_asdl::value_t*>* l = nullptr;
  StackRoot _root0(&rd);
  StackRoot _root1(&s);
  StackRoot _root2(&out);
  StackRoot _root3(&l);

  s = rd->PosStr();
  rd->Done();
  out = Alloc<List<BigStr*>>();
  this->globber->_Glob(s, out);
  l = Alloc<List<value_asdl::value_t*>>();
  for (ListIter<BigStr*> it(out); !it.Done(); it.Next()) {
    BigStr* elem = it.Value();
    l->append(Alloc<value::Str>(elem));
  }
  return Alloc<value::List>(l);
}

Shvar_get::Shvar_get(state::Mem* mem) : ::vm::_Callable() {
  this->mem = mem;
}

value_asdl::value_t* Shvar_get::Call(typed_args::Reader* rd) {
  BigStr* name = nullptr;
  StackRoot _root0(&rd);
  StackRoot _root1(&name);

  name = rd->PosStr();
  rd->Done();
  return state::DynamicGetVar(this->mem, name, scope_e::Dynamic);
}

GetVar::GetVar(state::Mem* mem) : ::vm::_Callable() {
  this->mem = mem;
}

value_asdl::value_t* GetVar::Call(typed_args::Reader* rd) {
  BigStr* name = nullptr;
  StackRoot _root0(&rd);
  StackRoot _root1(&name);

  name = rd->PosStr();
  rd->Done();
  return state::DynamicGetVar(this->mem, name, scope_e::LocalOrGlobal);
}

Assert::Assert() {
  ;  // pass
}

value_asdl::value_t* Assert::Call(typed_args::Reader* rd) {
  value_asdl::value_t* val = nullptr;
  BigStr* msg = nullptr;
  StackRoot _root0(&rd);
  StackRoot _root1(&val);
  StackRoot _root2(&msg);

  val = rd->PosValue();
  msg = rd->OptionalStr(str197);
  rd->Done();
  if (!val_ops::ToBool(val)) {
    throw Alloc<error::AssertionErr>(msg, rd->LeftParenToken());
  }
  return value::Null;
}

EvalExpr::EvalExpr(expr_eval::ExprEvaluator* expr_ev) {
  this->expr_ev = expr_ev;
}

value_asdl::value_t* EvalExpr::Call(typed_args::Reader* rd) {
  syntax_asdl::expr_t* lazy = nullptr;
  value_asdl::value_t* result = nullptr;
  StackRoot _root0(&rd);
  StackRoot _root1(&lazy);
  StackRoot _root2(&result);

  lazy = rd->PosExpr();
  rd->Done();
  result = this->expr_ev->EvalExpr(lazy, rd->LeftParenToken());
  return result;
}

ToJson8::ToJson8(bool is_j8) {
  this->is_j8 = is_j8;
}

value_asdl::value_t* ToJson8::Call(typed_args::Reader* rd) {
  value_asdl::value_t* val = nullptr;
  int space;
  int indent;
  mylib::BufWriter* buf = nullptr;
  StackRoot _root0(&rd);
  StackRoot _root1(&val);
  StackRoot _root2(&buf);

  val = rd->PosValue();
  space = mops::BigTruncate(rd->NamedInt(str198, 0));
  rd->Done();
  if (space <= 0) {
    indent = -1;
  }
  else {
    indent = space;
  }
  buf = Alloc<mylib::BufWriter>();
  try {
    if (this->is_j8) {
      j8::PrintMessage(val, buf, indent);
    }
    else {
      j8::PrintJsonMessage(val, buf, indent);
    }
  }
  catch (error::Encode* e) {
    throw Alloc<error::Structured>(4, e->Message(), rd->LeftParenToken());
  }
  return Alloc<value::Str>(buf->getvalue());
}

FromJson8::FromJson8(bool is_j8) {
  this->is_j8 = is_j8;
}

value_asdl::value_t* FromJson8::Call(typed_args::Reader* rd) {
  BigStr* s = nullptr;
  j8::Parser* p = nullptr;
  value_asdl::value_t* val = nullptr;
  Dict<BigStr*, value_asdl::value_t*>* props = nullptr;
  StackRoot _root0(&rd);
  StackRoot _root1(&s);
  StackRoot _root2(&p);
  StackRoot _root3(&val);
  StackRoot _root4(&props);

  s = rd->PosStr();
  rd->Done();
  p = Alloc<j8::Parser>(s, this->is_j8);
  try {
    val = p->ParseValue();
  }
  catch (error::Decode* e) {
    props = Alloc<Dict<BigStr*, value_asdl::value_t*>>(std::initializer_list<BigStr*>{str199, str200}, std::initializer_list<value_asdl::value_t*>{num::ToBig(e->start_pos), num::ToBig(e->end_pos)});
    throw Alloc<error::Structured>(4, e->Message(), rd->LeftParenToken(), props);
  }
  return val;
}

BashArrayToSparse::BashArrayToSparse() {
  ;  // pass
}

value_asdl::value_t* BashArrayToSparse::Call(typed_args::Reader* rd) {
  List<BigStr*>* strs = nullptr;
  Dict<mops::BigInt, BigStr*>* d = nullptr;
  mops::BigInt max_index;
  int i;
  mops::BigInt big_i;
  StackRoot _root0(&rd);
  StackRoot _root1(&strs);
  StackRoot _root2(&d);

  strs = rd->PosBashArray();
  rd->Done();
  d = Alloc<Dict<mops::BigInt, BigStr*>>();
  max_index = mops::MINUS_ONE;
  i = 0;
  for (ListIter<BigStr*> it(strs); !it.Done(); it.Next(), ++i) {
    BigStr* s = it.Value();
    StackRoot _for(&s  );
    if (s != nullptr) {
      big_i = mops::IntWiden(i);
      d->set(big_i, s);
      if (mops::Greater(big_i, max_index)) {
        max_index = big_i;
      }
    }
  }
  return Alloc<value::SparseArray>(d, max_index);
}

DictToSparse::DictToSparse() {
  ;  // pass
}

value_asdl::value_t* DictToSparse::Call(typed_args::Reader* rd) {
  Dict<BigStr*, value_asdl::value_t*>* d = nullptr;
  syntax_asdl::loc_t* blame_tok = nullptr;
  Dict<mops::BigInt, BigStr*>* mydict = nullptr;
  mops::BigInt i;
  BigStr* s = nullptr;
  mops::BigInt max_index;
  StackRoot _root0(&rd);
  StackRoot _root1(&d);
  StackRoot _root2(&blame_tok);
  StackRoot _root3(&mydict);
  StackRoot _root4(&s);

  d = rd->PosDict();
  rd->Done();
  blame_tok = rd->LeftParenToken();
  mydict = Alloc<Dict<mops::BigInt, BigStr*>>();
  for (DictIter<BigStr*, value_asdl::value_t*> it(d); !it.Done(); it.Next()) {
    BigStr* k = it.Key();
    value_asdl::value_t* v = it.Value();
    i = mops::FromStr(k);
    s = val_ops::ToStr(v, str201, blame_tok);
    mydict->set(i, s);
  }
  max_index = mops::MINUS_ONE;
  return Alloc<value::SparseArray>(mydict, max_index);
}

SparseOp::SparseOp() {
  ;  // pass
}

value_asdl::value_t* SparseOp::Call(typed_args::Reader* rd) {
  value::SparseArray* sp = nullptr;
  Dict<mops::BigInt, BigStr*>* d = nullptr;
  BigStr* op_name = nullptr;
  BigStr* no_str = nullptr;
  mops::BigInt index;
  BigStr* s = nullptr;
  mops::BigInt max_index;
  List<mops::BigInt>* keys = nullptr;
  List<BigStr*>* items = nullptr;
  int j;
  mops::BigInt start;
  mops::BigInt end;
  int n;
  List<BigStr*>* items2 = nullptr;
  mops::BigInt i;
  List<BigStr*>* strs = nullptr;
  mops::BigInt i2;
  StackRoot _root0(&rd);
  StackRoot _root1(&sp);
  StackRoot _root2(&d);
  StackRoot _root3(&op_name);
  StackRoot _root4(&no_str);
  StackRoot _root5(&s);
  StackRoot _root6(&keys);
  StackRoot _root7(&items);
  StackRoot _root8(&items2);
  StackRoot _root9(&strs);

  sp = rd->PosSparseArray();
  d = sp->d;
  op_name = rd->PosStr();
  no_str = nullptr;
  if (str_equals(op_name, str202)) {
    rd->Done();
    return num::ToBig(len(d));
  }
  else {
    if (str_equals(op_name, str203)) {
      index = rd->PosInt();
      rd->Done();
      s = d->get(index);
      if (s == nullptr) {
        return value::Null;
      }
      else {
        return Alloc<value::Str>(s);
      }
    }
    else {
      if (str_equals(op_name, str204)) {
        index = rd->PosInt();
        s = rd->PosStr();
        rd->Done();
        d->set(index, s);
        if (mops::Greater(index, sp->max_index)) {
          sp->max_index = index;
        }
        return Alloc<value::Int>(mops::ZERO);
      }
      else {
        if (str_equals(op_name, str205)) {
          index = rd->PosInt();
          rd->Done();
          mylib::dict_erase(d, index);
          max_index = mops::MINUS_ONE;
          for (DictIter<mops::BigInt, BigStr*> it(d); !it.Done(); it.Next()) {
            mops::BigInt i1 = it.Key();
            if (mops::Greater(i1, max_index)) {
              max_index = i1;
            }
          }
          sp->max_index = max_index;
          return Alloc<value::Int>(mops::ZERO);
        }
        else {
          if (str_equals(op_name, str206)) {
            keys = d->keys();
            mylib::BigIntSort(keys);
            items = list_repeat(no_str, len(d));
            j = 0;
            for (ListIter<mops::BigInt> it(keys); !it.Done(); it.Next()) {
              mops::BigInt i = it.Value();
              s = d->get(i);
              items->set(j, s);
              j += 1;
            }
            return Alloc<value::BashArray>(items);
          }
          else {
            if (str_equals(op_name, str207)) {
              keys = d->keys();
              mylib::BigIntSort(keys);
              items = Alloc<List<BigStr*>>();
              for (ListIter<mops::BigInt> it(keys); !it.Done(); it.Next()) {
                mops::BigInt k = it.Value();
                items->append(mops::ToStr(k));
              }
              return Alloc<value::BashArray>(items);
            }
            else {
              if (str_equals(op_name, str208)) {
                start = rd->PosInt();
                end = rd->PosInt();
                rd->Done();
                n = mops::BigTruncate(mops::Sub(end, start));
                items2 = list_repeat(no_str, n);
                j = 0;
                i = start;
                while (mops::Greater(end, i)) {
                  s = d->get(i);
                  if (s != nullptr) {
                    items2->set(j, s);
                    j += 1;
                  }
                  i = mops::Add(i, mops::ONE);
                }
                return Alloc<value::BashArray>(items2);
              }
              else {
                if (str_equals(op_name, str209)) {
                  strs = rd->PosBashArray();
{
                    max_index = sp->max_index;
                  }
                  i2 = mops::Add(max_index, mops::ONE);
                  for (ListIter<BigStr*> it(strs); !it.Done(); it.Next()) {
                    BigStr* s = it.Value();
                    StackRoot _for(&s                  );
                    d->set(i2, s);
                    i2 = mops::Add(i2, mops::ONE);
                  }
                  sp->max_index = mops::Add(sp->max_index, mops::IntWiden(len(strs)));
                  return Alloc<value::Int>(mops::ZERO);
                }
                else {
                  print(StrFormat("Invalid SparseArray operation %r", op_name));
                  return Alloc<value::Int>(mops::ZERO);
                }
              }
            }
          }
        }
      }
    }
  }
}

}  // define namespace func_misc

namespace hay_ysh {  // define

using option_asdl::option_i;
using runtime_asdl::scope_e;
using runtime_asdl::HayNode;
using syntax_asdl::loc;
using value_asdl::value;
using value_asdl::value_e;
using value_asdl::value_t;
namespace fmt = format;
using error::e_usage;
using error::e_die;
BigStr* _HAY_ACTION_ERROR = str211;

ctx_HayNode::ctx_HayNode(hay_ysh::HayState* hay_state, BigStr* hay_name) {
  gHeap.PushRoot(reinterpret_cast<RawObject**>(&(this->hay_state)));
  this->hay_state = hay_state;
  this->hay_state->Push(hay_name);
}

ctx_HayNode::~ctx_HayNode() {
  this->hay_state->Pop();
  gHeap.PopRoot();
}

ctx_HayEval::ctx_HayEval(hay_ysh::HayState* hay_state, state::MutableOpts* mutable_opts, state::Mem* mem) {
  gHeap.PushRoot(reinterpret_cast<RawObject**>(&(this->hay_state)));
  gHeap.PushRoot(reinterpret_cast<RawObject**>(&(this->mem)));
  gHeap.PushRoot(reinterpret_cast<RawObject**>(&(this->mutable_opts)));
  this->hay_state = hay_state;
  this->mutable_opts = mutable_opts;
  this->mem = mem;
  if (mutable_opts->Get(option_i::_running_hay)) {
    e_die(str212);
  }
  for (ListIter<int> it(consts::YSH_ALL); !it.Done(); it.Next()) {
    int opt_num = it.Value();
    mutable_opts->Push(opt_num, true);
  }
  mutable_opts->Push(option_i::_running_hay, true);
  this->hay_state->PushEval();
  this->mem->PushTemp();
}

ctx_HayEval::~ctx_HayEval() {
  this->mem->PopTemp();
  this->hay_state->PopEval();
  this->mutable_opts->Pop(option_i::_running_hay);
  for (ListIter<int> it(consts::YSH_ALL); !it.Done(); it.Next()) {
    int opt_num = it.Value();
    this->mutable_opts->Pop(opt_num);
  }
  gHeap.PopRoot();
  gHeap.PopRoot();
  gHeap.PopRoot();
}

HayState::HayState() {
  auto* ch = Alloc<Dict<BigStr*, runtime_asdl::HayNode*>>();
  this->root_defs = Alloc<HayNode>(ch);
  this->cur_defs = this->root_defs;
  this->def_stack = NewList<runtime_asdl::HayNode*>(std::initializer_list<runtime_asdl::HayNode*>{this->root_defs});
  Dict<BigStr*, value_asdl::value_t*>* node = this->_MakeOutputNode();
  this->result_stack = NewList<Dict<BigStr*, value_asdl::value_t*>*>(std::initializer_list<Dict<BigStr*, value_asdl::value_t*>*>{node});
  this->output = nullptr;
}

Dict<BigStr*, value_asdl::value_t*>* HayState::_MakeOutputNode() {
  Dict<BigStr*, value_asdl::value_t*>* d = nullptr;
  StackRoot _root0(&d);

  d = Alloc<Dict<BigStr*, value_asdl::value_t*>>();
  d->set(str213, value::Null);
  d->set(str214, Alloc<value::List>(Alloc<List<value_asdl::value_t*>>()));
  return d;
}

void HayState::PushEval() {
  Dict<BigStr*, value_asdl::value_t*>* node = nullptr;
  StackRoot _root0(&node);

  node = this->_MakeOutputNode();
  this->result_stack = NewList<Dict<BigStr*, value_asdl::value_t*>*>(std::initializer_list<Dict<BigStr*, value_asdl::value_t*>*>{node});
  this->output = nullptr;
}

void HayState::PopEval() {
  Dict<BigStr*, value_asdl::value_t*>* node = nullptr;
  StackRoot _root0(&node);

  this->output = this->result_stack->at(0);
  node = this->_MakeOutputNode();
  this->result_stack = NewList<Dict<BigStr*, value_asdl::value_t*>*>(std::initializer_list<Dict<BigStr*, value_asdl::value_t*>*>{node});
}

void HayState::AppendResult(Dict<BigStr*, value_asdl::value_t*>* d) {
  value_asdl::value_t* UP_children = nullptr;
  StackRoot _root0(&d);
  StackRoot _root1(&UP_children);

  UP_children = this->result_stack->at(-1)->at(str215);
  value::List* children = static_cast<value::List*>(UP_children);
  children->items->append(Alloc<value::Dict>(d));
}

Dict<BigStr*, value_asdl::value_t*>* HayState::Result() {
  return this->output;
}

Dict<BigStr*, value_asdl::value_t*>* HayState::HayRegister() {
  return this->result_stack->at(0);
}

bool HayState::Resolve(BigStr* first_word) {
  StackRoot _root0(&first_word);

  return dict_contains(this->cur_defs->children, first_word);
}

void HayState::DefinePath(List<BigStr*>* path) {
  runtime_asdl::HayNode* current = nullptr;
  Dict<BigStr*, runtime_asdl::HayNode*>* ch = nullptr;
  StackRoot _root0(&path);
  StackRoot _root1(&current);
  StackRoot _root2(&ch);

  current = this->root_defs;
  for (ListIter<BigStr*> it(path); !it.Done(); it.Next()) {
    BigStr* name = it.Value();
    StackRoot _for(&name  );
    if (!dict_contains(current->children, name)) {
      ch = Alloc<Dict<BigStr*, runtime_asdl::HayNode*>>();
      current->children->set(name, Alloc<HayNode>(ch));
    }
    current = current->children->at(name);
  }
}

void HayState::Reset() {
  Dict<BigStr*, runtime_asdl::HayNode*>* ch = nullptr;
  StackRoot _root0(&ch);

  ch = Alloc<Dict<BigStr*, runtime_asdl::HayNode*>>();
  this->root_defs = Alloc<HayNode>(ch);
  this->cur_defs = this->root_defs;
  this->PopEval();
}

void HayState::Push(BigStr* hay_name) {
  Dict<BigStr*, value_asdl::value_t*>* top = nullptr;
  value::List* children = nullptr;
  value::Dict* last_child = nullptr;
  StackRoot _root0(&hay_name);
  StackRoot _root1(&top);
  StackRoot _root2(&children);
  StackRoot _root3(&last_child);

  top = this->result_stack->at(-1);
  children = static_cast<value::List*>(top->at(str216));
  last_child = static_cast<value::Dict*>(children->items->at(-1));
  this->result_stack->append(last_child->d);
  if (hay_name == nullptr) {
    this->def_stack->append(this->cur_defs);
  }
  else {
    this->cur_defs = this->cur_defs->children->at(hay_name);
    this->def_stack->append(this->cur_defs);
  }
}

void HayState::Pop() {
  this->def_stack->pop();
  this->cur_defs = this->def_stack->at(-1);
  this->result_stack->pop();
}

Hay::Hay(hay_ysh::HayState* hay_state, state::MutableOpts* mutable_opts, state::Mem* mem, cmd_eval::CommandEvaluator* cmd_ev) {
  this->hay_state = hay_state;
  this->mutable_opts = mutable_opts;
  this->mem = mem;
  this->cmd_ev = cmd_ev;
}

int Hay::Run(cmd_value::Argv* cmd_val) {
  args::Reader* arg_r = nullptr;
  BigStr* action = nullptr;
  syntax_asdl::loc_t* action_loc = nullptr;
  BigStr* first = nullptr;
  List<BigStr*>* names = nullptr;
  List<syntax_asdl::CompoundWord*>* name_locs = nullptr;
  int i;
  List<BigStr*>* path = nullptr;
  BigStr* var_name = nullptr;
  syntax_asdl::command_t* cmd = nullptr;
  int unused;
  Dict<BigStr*, value_asdl::value_t*>* result = nullptr;
  value::Dict* val = nullptr;
  hnode_asdl::hnode_t* tree = nullptr;
  format::ColorOutput* ast_f = nullptr;
  StackRoot _root0(&cmd_val);
  StackRoot _root1(&arg_r);
  StackRoot _root2(&action);
  StackRoot _root3(&action_loc);
  StackRoot _root4(&first);
  StackRoot _root5(&names);
  StackRoot _root6(&name_locs);
  StackRoot _root7(&path);
  StackRoot _root8(&var_name);
  StackRoot _root9(&cmd);
  StackRoot _root10(&result);
  StackRoot _root11(&val);
  StackRoot _root12(&tree);
  StackRoot _root13(&ast_f);

  arg_r = Alloc<args::Reader>(cmd_val->argv, cmd_val->arg_locs);
  arg_r->Next();
  Tuple2<BigStr*, syntax_asdl::loc_t*> tup0 = arg_r->Peek2();
  action = tup0.at0();
  action_loc = tup0.at1();
  if (action == nullptr) {
    e_usage(_HAY_ACTION_ERROR, action_loc);
  }
  arg_r->Next();
  if (str_equals(action, str217)) {
    Tuple2<BigStr*, syntax_asdl::loc_t*> tup1 = arg_r->Peek2();
    first = tup1.at0();
    if (first == nullptr) {
      e_usage(str218, action_loc);
    }
    Tuple2<List<BigStr*>*, List<syntax_asdl::CompoundWord*>*> tup2 = arg_r->Rest2();
    names = tup2.at0();
    name_locs = tup2.at1();
    i = 0;
    for (ListIter<BigStr*> it(names); !it.Done(); it.Next(), ++i) {
      BigStr* name = it.Value();
      StackRoot _for(&name    );
      path = name->split(str219);
      for (ListIter<BigStr*> it(path); !it.Done(); it.Next()) {
        BigStr* p = it.Value();
        StackRoot _for(&p      );
        if (len(p) == 0) {
          e_usage(StrFormat("got invalid path %r.  Parts can't be empty.", name), name_locs->at(i));
        }
      }
      this->hay_state->DefinePath(path);
    }
  }
  else {
    if (str_equals(action, str221)) {
      Tuple2<BigStr*, syntax_asdl::loc_t*> tup3 = arg_r->ReadRequired2(str222);
      var_name = tup3.at0();
      if (var_name->startswith(str223)) {
        var_name = var_name->slice(1);
      }
      cmd = typed_args::OptionalBlock(cmd_val);
      if (!cmd) {
        e_usage(str224, loc::Missing);
      }
      {  // with
        ctx_HayEval ctx{this->hay_state, this->mutable_opts, this->mem};

        unused = this->cmd_ev->EvalCommand(cmd);
      }
      result = this->hay_state->Result();
      val = Alloc<value::Dict>(result);
      this->mem->SetNamed(location::LName(var_name), val, scope_e::LocalOnly);
    }
    else {
      if (str_equals(action, str225)) {
        this->hay_state->Reset();
      }
      else {
        if (str_equals(action, str226)) {
          tree = this->hay_state->root_defs->PrettyTree();
          ast_f = fmt::DetectConsoleOutput(mylib::Stdout());
          fmt::PrintTree(tree, ast_f);
          ast_f->write(str227);
        }
        else {
          e_usage(_HAY_ACTION_ERROR, action_loc);
        }
      }
    }
  }
  return 0;
}

HayNode_::HayNode_(hay_ysh::HayState* hay_state, state::Mem* mem, cmd_eval::CommandEvaluator* cmd_ev) {
  this->hay_state = hay_state;
  this->mem = mem;
  this->cmd_ev = cmd_ev;
  this->arena = cmd_ev->arena;
}

int HayNode_::Run(cmd_value::Argv* cmd_val) {
  args::Reader* arg_r = nullptr;
  BigStr* hay_name = nullptr;
  syntax_asdl::loc_t* arg0_loc = nullptr;
  Dict<BigStr*, value_asdl::value_t*>* result = nullptr;
  BigStr* node_type = nullptr;
  List<BigStr*>* arguments = nullptr;
  syntax_asdl::LiteralBlock* lit_block = nullptr;
  List<value_asdl::value_t*>* items = nullptr;
  syntax_asdl::BraceGroup* brace_group = nullptr;
  syntax_asdl::SourceLine* line = nullptr;
  BigStr* code_str = nullptr;
  Dict<BigStr*, runtime_asdl::Cell*>* block_attrs = nullptr;
  Dict<BigStr*, value_asdl::value_t*>* attrs = nullptr;
  StackRoot _root0(&cmd_val);
  StackRoot _root1(&arg_r);
  StackRoot _root2(&hay_name);
  StackRoot _root3(&arg0_loc);
  StackRoot _root4(&result);
  StackRoot _root5(&node_type);
  StackRoot _root6(&arguments);
  StackRoot _root7(&lit_block);
  StackRoot _root8(&items);
  StackRoot _root9(&brace_group);
  StackRoot _root10(&line);
  StackRoot _root11(&code_str);
  StackRoot _root12(&block_attrs);
  StackRoot _root13(&attrs);

  arg_r = Alloc<args::Reader>(cmd_val->argv, cmd_val->arg_locs);
  Tuple2<BigStr*, syntax_asdl::loc_t*> tup4 = arg_r->Peek2();
  hay_name = tup4.at0();
  arg0_loc = tup4.at1();
  if (maybe_str_equals(hay_name, str228)) {
    arg_r->Next();
    hay_name = nullptr;
  }
  result = Alloc<Dict<BigStr*, value_asdl::value_t*>>();
  Tuple2<BigStr*, syntax_asdl::loc_t*> tup5 = arg_r->Peek2();
  node_type = tup5.at0();
  result->set(str229, Alloc<value::Str>(node_type));
  arg_r->Next();
  arguments = arg_r->Rest();
  lit_block = typed_args::OptionalLiteralBlock(cmd_val);
  if ((len(arguments) == 0 and lit_block == nullptr)) {
    e_usage(str230, arg0_loc);
  }
  items = Alloc<List<value_asdl::value_t*>>();
  for (ListIter<BigStr*> it(arguments); !it.Done(); it.Next()) {
    BigStr* s = it.Value();
    items->append(Alloc<value::Str>(s));
  }
  result->set(str231, Alloc<value::List>(items));
  if (node_type->isupper()) {
    if (lit_block == nullptr) {
      e_usage(str232, loc::Missing);
    }
{
      brace_group = lit_block->brace_group;
      line = brace_group->left->line;
      result->set(str234, Alloc<value::Str>(ui::GetLineSourceString(line)));
      result->set(str235, num::ToBig(line->line_num));
      code_str = alloc::SnipCodeBlock(brace_group->left, brace_group->right, lit_block->lines);
      result->set(str236, Alloc<value::Str>(code_str));
    }
    this->hay_state->AppendResult(result);
  }
  else {
    this->hay_state->AppendResult(result);
    if (lit_block) {
      result->set(str237, Alloc<value::List>(Alloc<List<value_asdl::value_t*>>()));
      {  // with
        state::ctx_Temp ctx{this->mem};

        {  // with
          ctx_HayNode ctx{this->hay_state, hay_name};

          this->cmd_ev->EvalCommand(lit_block->brace_group);
        }
        block_attrs = this->mem->TopNamespace();
      }
      attrs = Alloc<Dict<BigStr*, value_asdl::value_t*>>();
      for (DictIter<BigStr*, runtime_asdl::Cell*> it(block_attrs); !it.Done(); it.Next()) {
        BigStr* name = it.Key();
        runtime_asdl::Cell* cell = it.Value();
        if (name->endswith(str238)) {
          continue;
        }
        attrs->set(name, cell->val);
      }
      result->set(str239, Alloc<value::Dict>(attrs));
    }
  }
  return 0;
}

}  // define namespace hay_ysh

namespace io_osh {  // define

using id_kind_asdl::Id;
using value_asdl::value;
using value_asdl::value_t;
using error::e_die_status;

Echo::Echo(optview::Exec* exec_opts) {
  this->exec_opts = exec_opts;
  this->f = mylib::Stdout();
  this->simple_flag = nullptr;
}

arg_types::echo* Echo::_SimpleFlag() {
  Dict<BigStr*, value_asdl::value_t*>* attrs = nullptr;
  StackRoot _root0(&attrs);

  if (this->simple_flag == nullptr) {
    attrs = Alloc<Dict<BigStr*, value_asdl::value_t*>>();
    attrs->set(str240, Alloc<value::Bool>(false));
    attrs->set(str241, Alloc<value::Bool>(false));
    this->simple_flag = Alloc<arg_types::echo>(attrs);
  }
  return this->simple_flag;
}

int Echo::Run(cmd_value::Argv* cmd_val) {
  List<BigStr*>* argv = nullptr;
  arg_types::echo* arg = nullptr;
  args::_Attributes* attrs = nullptr;
  args::Reader* arg_r = nullptr;
  bool backslash_c;
  List<BigStr*>* new_argv = nullptr;
  List<BigStr*>* parts = nullptr;
  match::SimpleLexer* lex = nullptr;
  int id_;
  BigStr* s = nullptr;
  BigStr* p = nullptr;
  mylib::BufWriter* buf = nullptr;
  int i;
  StackRoot _root0(&cmd_val);
  StackRoot _root1(&argv);
  StackRoot _root2(&arg);
  StackRoot _root3(&attrs);
  StackRoot _root4(&arg_r);
  StackRoot _root5(&new_argv);
  StackRoot _root6(&parts);
  StackRoot _root7(&lex);
  StackRoot _root8(&s);
  StackRoot _root9(&p);
  StackRoot _root10(&buf);

  argv = cmd_val->argv->slice(1);
  if (this->exec_opts->simple_echo()) {
    typed_args::DoesNotAccept(cmd_val->typed_args);
    arg = this->_SimpleFlag();
  }
  else {
    Tuple2<args::_Attributes*, args::Reader*> tup0 = flag_util::ParseLikeEcho(str242, cmd_val);
    attrs = tup0.at0();
    arg_r = tup0.at1();
    arg = Alloc<arg_types::echo>(attrs->attrs);
    argv = arg_r->Rest();
  }
  backslash_c = false;
  if (arg->e) {
    new_argv = Alloc<List<BigStr*>>();
    for (ListIter<BigStr*> it(argv); !it.Done(); it.Next()) {
      BigStr* a = it.Value();
      StackRoot _for(&a    );
      parts = Alloc<List<BigStr*>>();
      lex = match::EchoLexer(a);
      while (!backslash_c) {
        Tuple2<int, BigStr*> tup1 = lex->Next();
        id_ = tup1.at0();
        s = tup1.at1();
        if (id_ == Id::Eol_Tok) {
          break;
        }
        p = word_compile::EvalCStringToken(id_, s);
        if (p == nullptr) {
          backslash_c = true;
          break;
        }
        parts->append(p);
      }
      new_argv->append(str243->join(parts));
      if (backslash_c) {
        break;
      }
    }
    argv = new_argv;
  }
  buf = Alloc<mylib::BufWriter>();
  i = 0;
  for (ListIter<BigStr*> it(argv); !it.Done(); it.Next(), ++i) {
    BigStr* a = it.Value();
    StackRoot _for(&a  );
    if (i != 0) {
      buf->write(str244);
    }
    buf->write(a);
  }
  if ((!arg->n and !backslash_c)) {
    buf->write(str245);
  }
  this->f->write(buf->getvalue());
  return 0;
}

MapFile::MapFile(state::Mem* mem, ui::ErrorFormatter* errfmt, cmd_eval::CommandEvaluator* cmd_ev) {
  this->mem = mem;
  this->errfmt = errfmt;
  this->cmd_ev = cmd_ev;
}

int MapFile::Run(cmd_value::Argv* cmd_val) {
  args::_Attributes* attrs = nullptr;
  args::Reader* arg_r = nullptr;
  arg_types::mapfile* arg = nullptr;
  BigStr* var_name = nullptr;
  List<BigStr*>* lines = nullptr;
  BigStr* line = nullptr;
  StackRoot _root0(&cmd_val);
  StackRoot _root1(&attrs);
  StackRoot _root2(&arg_r);
  StackRoot _root3(&arg);
  StackRoot _root4(&var_name);
  StackRoot _root5(&lines);
  StackRoot _root6(&line);

  Tuple2<args::_Attributes*, args::Reader*> tup2 = flag_util::ParseCmdVal(str246, cmd_val);
  attrs = tup2.at0();
  arg_r = tup2.at1();
  arg = Alloc<arg_types::mapfile>(attrs->attrs);
  Tuple2<BigStr*, syntax_asdl::loc_t*> tup3 = arg_r->Peek2();
  var_name = tup3.at0();
  if (var_name == nullptr) {
    var_name = str247;
  }
  lines = Alloc<List<BigStr*>>();
  while (true) {
    try {
      Tuple2<BigStr*, bool> tup4 = read_osh::ReadLineSlowly(this->cmd_ev, !arg->t);
      line = tup4.at0();
    }
    catch (pyos::ReadError* e) {
      this->errfmt->PrintMessage(StrFormat("mapfile: read() error: %s", posix::strerror(e->err_num)));
      return 1;
    }
    if (len(line) == 0) {
      break;
    }
    lines->append(line);
  }
  state::BuiltinSetArray(this->mem, var_name, lines);
  return 0;
}

Cat::Cat() : ::vm::_Builtin() {
}

int Cat::Run(cmd_value::Argv* cmd_val) {
  List<BigStr*>* chunks = nullptr;
  int n;
  int err_num;
  StackRoot _root0(&cmd_val);
  StackRoot _root1(&chunks);

  chunks = Alloc<List<BigStr*>>();
  while (true) {
    Tuple2<int, int> tup5 = pyos::Read(0, 4096, chunks);
    n = tup5.at0();
    err_num = tup5.at1();
    if (n < 0) {
      if (err_num == EINTR) {
        ;  // pass
      }
      else {
        e_die_status(2, StrFormat("osh I/O error: %s", posix::strerror(err_num)));
      }
    }
    else {
      if (n == 0) {
        break;
      }
      else {
        mylib::Stdout()->write(chunks->at(0));
        chunks->pop();
      }
    }
  }
  return 0;
}

}  // define namespace io_osh

namespace io_ysh {  // define

using runtime_asdl::cmd_value;
using syntax_asdl::command_e;
using syntax_asdl::BraceGroup;
using syntax_asdl::loc;
using value_asdl::value;
namespace fmt = format;
using error::e_usage;

_Builtin::_Builtin(state::Mem* mem, ui::ErrorFormatter* errfmt) {
  this->mem = mem;
  this->errfmt = errfmt;
}

Pp::Pp(state::Mem* mem, ui::ErrorFormatter* errfmt, Dict<BigStr*, value::Proc*>* procs, alloc::Arena* arena) : ::io_ysh::_Builtin(mem, errfmt) {
  this->procs = procs;
  this->arena = arena;
  this->stdout_ = mylib::Stdout();
}

int Pp::Run(cmd_value::Argv* cmd_val) {
  args::_Attributes* arg = nullptr;
  args::Reader* arg_r = nullptr;
  BigStr* action = nullptr;
  syntax_asdl::loc_t* action_loc = nullptr;
  List<BigStr*>* argv = nullptr;
  List<syntax_asdl::CompoundWord*>* locs = nullptr;
  int status;
  int i;
  BigStr* name = nullptr;
  runtime_asdl::Cell* cell = nullptr;
  format::ColorOutput* pretty_f = nullptr;
  typed_args::Reader* rd = nullptr;
  value_asdl::value_t* val = nullptr;
  hnode_asdl::hnode_t* tree = nullptr;
  BigStr* ysh_type = nullptr;
  List<BigStr*>* names = nullptr;
  value::Proc* node = nullptr;
  value::Proc* proc = nullptr;
  syntax_asdl::command_t* body = nullptr;
  BigStr* doc = nullptr;
  BraceGroup* bgroup = nullptr;
  syntax_asdl::Token* token = nullptr;
  mylib::BufWriter* buf = nullptr;
  StackRoot _root0(&cmd_val);
  StackRoot _root1(&arg);
  StackRoot _root2(&arg_r);
  StackRoot _root3(&action);
  StackRoot _root4(&action_loc);
  StackRoot _root5(&argv);
  StackRoot _root6(&locs);
  StackRoot _root7(&name);
  StackRoot _root8(&cell);
  StackRoot _root9(&pretty_f);
  StackRoot _root10(&rd);
  StackRoot _root11(&val);
  StackRoot _root12(&tree);
  StackRoot _root13(&ysh_type);
  StackRoot _root14(&names);
  StackRoot _root15(&node);
  StackRoot _root16(&proc);
  StackRoot _root17(&body);
  StackRoot _root18(&doc);
  StackRoot _root19(&bgroup);
  StackRoot _root20(&token);
  StackRoot _root21(&buf);

  Tuple2<args::_Attributes*, args::Reader*> tup0 = flag_util::ParseCmdVal(str250, cmd_val, true);
  arg = tup0.at0();
  arg_r = tup0.at1();
  Tuple2<BigStr*, syntax_asdl::loc_t*> tup1 = arg_r->ReadRequired2(str251);
  action = tup1.at0();
  action_loc = tup1.at1();
  if (str_equals(action, str252)) {
    Tuple2<List<BigStr*>*, List<syntax_asdl::CompoundWord*>*> tup2 = arg_r->Rest2();
    argv = tup2.at0();
    locs = tup2.at1();
    status = 0;
    i = 0;
    for (ListIter<BigStr*> it(argv); !it.Done(); it.Next(), ++i) {
      BigStr* name = it.Value();
      StackRoot _for(&name    );
      if (name->startswith(str253)) {
        name = name->slice(1);
      }
      if (!match::IsValidVarName(name)) {
        throw Alloc<error::Usage>(StrFormat("got invalid variable name %r", name), locs->at(i));
      }
      cell = this->mem->GetCell(name);
      if (cell == nullptr) {
        this->errfmt->Print_(StrFormat("Couldn't find a variable named %r", name), locs->at(i));
        status = 1;
      }
      else {
        this->stdout_->write(StrFormat("%s = ", name));
        pretty_f = fmt::DetectConsoleOutput(this->stdout_);
        fmt::PrintTree(cell->PrettyTree(), pretty_f);
        this->stdout_->write(str257);
      }
    }
  }
  else {
    if (str_equals(action, str258)) {
      rd = typed_args::ReaderForProc(cmd_val);
      val = rd->PosValue();
      rd->Done();
      tree = val->PrettyTree();
      pretty_f = fmt::DetectConsoleOutput(this->stdout_);
      fmt::PrintTree(tree, pretty_f);
      this->stdout_->write(str259);
      status = 0;
    }
    else {
      if (str_equals(action, str260)) {
        rd = typed_args::ReaderForProc(cmd_val);
        val = rd->PosValue();
        rd->Done();
        ysh_type = ui::ValType(val);
        this->stdout_->write(StrFormat("(%s)   ", ysh_type));
        j8::PrintLine(val, this->stdout_);
        status = 0;
      }
      else {
        if (str_equals(action, str262)) {
          print(str263);
          status = 0;
        }
        else {
          if (str_equals(action, str264)) {
            Tuple2<List<BigStr*>*, List<syntax_asdl::CompoundWord*>*> tup3 = arg_r->Rest2();
            names = tup3.at0();
            locs = tup3.at1();
            if (len(names)) {
              i = 0;
              for (ListIter<BigStr*> it(names); !it.Done(); it.Next(), ++i) {
                BigStr* name = it.Value();
                StackRoot _for(&name              );
                node = this->procs->get(name);
                if (node == nullptr) {
                  this->errfmt->Print_(StrFormat("Invalid proc %r", name), locs->at(i));
                  return 1;
                }
              }
            }
            else {
              names = sorted(this->procs);
            }
            print(str266);
            for (ListIter<BigStr*> it(names); !it.Done(); it.Next()) {
              BigStr* name = it.Value();
              StackRoot _for(&name            );
              proc = this->procs->at(name);
              body = proc->body;
              doc = str267;
              if (body->tag() == command_e::BraceGroup) {
                bgroup = static_cast<BraceGroup*>(body);
                if (bgroup->doc_token) {
                  token = bgroup->doc_token;
                  doc = token->line->content->slice((token->col + 1), (token->col + token->length));
                }
              }
              buf = Alloc<mylib::BufWriter>();
              j8::EncodeString(name, buf, true);
              buf->write(str268);
              j8::EncodeString(doc, buf, true);
              print(buf->getvalue());
            }
            status = 0;
          }
          else {
            e_usage(StrFormat("got invalid action %r", action), action_loc);
          }
        }
      }
    }
  }
  return status;
}

Write::Write(state::Mem* mem, ui::ErrorFormatter* errfmt) : ::io_ysh::_Builtin(mem, errfmt) {
  this->stdout_ = mylib::Stdout();
}

int Write::Run(cmd_value::Argv* cmd_val) {
  args::_Attributes* attrs = nullptr;
  args::Reader* arg_r = nullptr;
  arg_types::write* arg = nullptr;
  int i;
  BigStr* s = nullptr;
  StackRoot _root0(&cmd_val);
  StackRoot _root1(&attrs);
  StackRoot _root2(&arg_r);
  StackRoot _root3(&arg);
  StackRoot _root4(&s);

  Tuple2<args::_Attributes*, args::Reader*> tup4 = flag_util::ParseCmdVal(str270, cmd_val);
  attrs = tup4.at0();
  arg_r = tup4.at1();
  arg = Alloc<arg_types::write>(attrs->attrs);
  i = 0;
  while (!arg_r->AtEnd()) {
    if (i != 0) {
      this->stdout_->write(arg->sep);
    }
    s = arg_r->Peek();
    if (arg->json) {
      s = j8::MaybeEncodeJsonString(s);
    }
    else {
      if (arg->j8) {
        s = j8::MaybeEncodeString(s);
      }
    }
    this->stdout_->write(s);
    arg_r->Next();
    i += 1;
  }
  if (arg->n) {
    ;  // pass
  }
  else {
    if (len(arg->end)) {
      this->stdout_->write(arg->end);
    }
  }
  return 0;
}

Fopen::Fopen(state::Mem* mem, cmd_eval::CommandEvaluator* cmd_ev) {
  this->mem = mem;
  this->cmd_ev = cmd_ev;
}

int Fopen::Run(cmd_value::Argv* cmd_val) {
  args::Reader* arg_r = nullptr;
  syntax_asdl::command_t* cmd = nullptr;
  int unused;
  StackRoot _root0(&cmd_val);
  StackRoot _root1(&arg_r);
  StackRoot _root2(&cmd);

  Tuple2<args::_Attributes*, args::Reader*> tup5 = flag_util::ParseCmdVal(str271, cmd_val, true);
  arg_r = tup5.at1();
  cmd = typed_args::OptionalBlock(cmd_val);
  if (!cmd) {
    throw Alloc<error::Usage>(str272, loc::Missing);
  }
  unused = this->cmd_ev->EvalCommand(cmd);
  return 0;
}

}  // define namespace io_ysh

namespace json_ysh {  // define

using runtime_asdl::cmd_value;
using syntax_asdl::loc;
using syntax_asdl::loc_t;
using value_asdl::value;
using value_asdl::LeftName;
using error::e_usage;
BigStr* _JSON_ACTION_ERROR = str273;

Json::Json(state::Mem* mem, ui::ErrorFormatter* errfmt, bool is_j8) {
  this->mem = mem;
  this->errfmt = errfmt;
  this->is_j8 = is_j8;
  this->name = is_j8 ? str274 : str275;
  this->stdout_ = mylib::Stdout();
}

int Json::Run(cmd_value::Argv* cmd_val) {
  args::Reader* arg_r = nullptr;
  BigStr* action = nullptr;
  syntax_asdl::loc_t* action_loc = nullptr;
  args::_Attributes* attrs = nullptr;
  arg_types::json_write* arg_jw = nullptr;
  typed_args::Reader* rd = nullptr;
  value_asdl::value_t* val = nullptr;
  int space;
  int indent;
  mylib::BufWriter* buf = nullptr;
  value::Place* place = nullptr;
  syntax_asdl::loc_t* blame_loc = nullptr;
  BigStr* var_name = nullptr;
  BigStr* contents = nullptr;
  j8::Parser* p = nullptr;
  StackRoot _root0(&cmd_val);
  StackRoot _root1(&arg_r);
  StackRoot _root2(&action);
  StackRoot _root3(&action_loc);
  StackRoot _root4(&attrs);
  StackRoot _root5(&arg_jw);
  StackRoot _root6(&rd);
  StackRoot _root7(&val);
  StackRoot _root8(&buf);
  StackRoot _root9(&place);
  StackRoot _root10(&blame_loc);
  StackRoot _root11(&var_name);
  StackRoot _root12(&contents);
  StackRoot _root13(&p);

  arg_r = Alloc<args::Reader>(cmd_val->argv, cmd_val->arg_locs);
  arg_r->Next();
  Tuple2<BigStr*, syntax_asdl::loc_t*> tup0 = arg_r->Peek2();
  action = tup0.at0();
  action_loc = tup0.at1();
  if (action == nullptr) {
    throw Alloc<error::Usage>(_JSON_ACTION_ERROR, loc::Missing);
  }
  arg_r->Next();
  if (str_equals(action, str276)) {
    attrs = flag_util::Parse(str277, arg_r);
    arg_jw = Alloc<arg_types::json_write>(attrs->attrs);
    if (!arg_r->AtEnd()) {
      e_usage(str278, arg_r->Location());
    }
    rd = typed_args::ReaderForProc(cmd_val);
    val = rd->PosValue();
    space = mops::BigTruncate(rd->NamedInt(str279, 2));
    rd->Done();
    if (space <= 0) {
      indent = -1;
    }
    else {
      indent = space;
    }
    buf = Alloc<mylib::BufWriter>();
    try {
      if (this->is_j8) {
        j8::PrintMessage(val, buf, indent);
      }
      else {
        j8::PrintJsonMessage(val, buf, indent);
      }
    }
    catch (error::Encode* e) {
      this->errfmt->PrintMessage(StrFormat("%s write: %s", this->name, e->Message()), action_loc);
      return 1;
    }
    this->stdout_->write(buf->getvalue());
    this->stdout_->write(str281);
  }
  else {
    if (str_equals(action, str282)) {
      attrs = flag_util::Parse(str283, arg_r);
      if (cmd_val->typed_args) {
        rd = typed_args::ReaderForProc(cmd_val);
        place = rd->PosPlace();
        rd->Done();
        blame_loc = cmd_val->typed_args->left;
      }
      else {
        var_name = str284;
        blame_loc = cmd_val->arg_locs->at(0);
        place = Alloc<value::Place>(Alloc<LeftName>(var_name, blame_loc), this->mem->TopNamespace());
      }
      if (!arg_r->AtEnd()) {
        e_usage(str285, arg_r->Location());
      }
      try {
        contents = read_osh::ReadAll();
      }
      catch (pyos::ReadError* e) {
        this->errfmt->PrintMessage(StrFormat("read error: %s", posix::strerror(e->err_num)));
        return 1;
      }
      p = Alloc<j8::Parser>(contents, this->is_j8);
      try {
        val = p->ParseValue();
      }
      catch (error::Decode* err) {
        this->errfmt->Print_(StrFormat("%s read: %s", this->name, err->Message()), action_loc);
        return 1;
      }
      this->mem->SetPlace(place, val, blame_loc);
    }
    else {
      throw Alloc<error::Usage>(_JSON_ACTION_ERROR, action_loc);
    }
  }
  return 0;
}

}  // define namespace json_ysh

namespace meta_osh {  // define

using runtime_asdl::cmd_value;
using runtime_asdl::CommandStatus;
using syntax_asdl::source;
using syntax_asdl::loc;
using value_asdl::value;
using error::e_usage;
using mylib::print_stderr;

Eval::Eval(parse_lib::ParseContext* parse_ctx, optview::Exec* exec_opts, cmd_eval::CommandEvaluator* cmd_ev, dev::Tracer* tracer, ui::ErrorFormatter* errfmt) {
  this->parse_ctx = parse_ctx;
  this->arena = parse_ctx->arena;
  this->exec_opts = exec_opts;
  this->cmd_ev = cmd_ev;
  this->tracer = tracer;
  this->errfmt = errfmt;
}

int Eval::Run(cmd_value::Argv* cmd_val) {
  typed_args::Reader* rd = nullptr;
  syntax_asdl::command_t* cmd = nullptr;
  args::Reader* arg_r = nullptr;
  BigStr* code_str = nullptr;
  syntax_asdl::loc_t* eval_loc = nullptr;
  reader::FileLineReader* line_reader = nullptr;
  cmd_parse::CommandParser* c_parser = nullptr;
  source::ArgvWord* src = nullptr;
  StackRoot _root0(&cmd_val);
  StackRoot _root1(&rd);
  StackRoot _root2(&cmd);
  StackRoot _root3(&arg_r);
  StackRoot _root4(&code_str);
  StackRoot _root5(&eval_loc);
  StackRoot _root6(&line_reader);
  StackRoot _root7(&c_parser);
  StackRoot _root8(&src);

  if (cmd_val->typed_args) {
    rd = typed_args::ReaderForProc(cmd_val);
    cmd = rd->PosCommand();
    rd->Done();
    return this->cmd_ev->EvalCommand(cmd);
  }
  Tuple2<args::_Attributes*, args::Reader*> tup0 = flag_util::ParseCmdVal(str288, cmd_val);
  arg_r = tup0.at1();
  if (this->exec_opts->simple_eval_builtin()) {
    Tuple2<BigStr*, syntax_asdl::loc_t*> tup1 = arg_r->ReadRequired2(str289);
    code_str = tup1.at0();
    eval_loc = tup1.at1();
    if (!arg_r->AtEnd()) {
      e_usage(str290, loc::Missing);
    }
  }
  else {
    code_str = str291->join(arg_r->Rest());
    eval_loc = cmd_val->arg_locs->at(0);
  }
  line_reader = reader::StringLineReader(code_str, this->arena);
  c_parser = this->parse_ctx->MakeOshParser(line_reader);
  src = Alloc<source::ArgvWord>(str292, eval_loc);
  {  // with
    dev::ctx_Tracer ctx{this->tracer, str293, nullptr};

    {  // with
      alloc::ctx_SourceCode ctx{this->arena, src};

      return main_loop::Batch(this->cmd_ev, c_parser, this->errfmt, cmd_eval::RaiseControlFlow);
    }
  }
}

Source::Source(parse_lib::ParseContext* parse_ctx, state::SearchPath* search_path, cmd_eval::CommandEvaluator* cmd_ev, process::FdState* fd_state, dev::Tracer* tracer, ui::ErrorFormatter* errfmt, pyutil::_ResourceLoader* loader) {
  this->parse_ctx = parse_ctx;
  this->arena = parse_ctx->arena;
  this->search_path = search_path;
  this->cmd_ev = cmd_ev;
  this->fd_state = fd_state;
  this->tracer = tracer;
  this->errfmt = errfmt;
  this->loader = loader;
  this->mem = cmd_ev->mem;
}

int Source::Run(cmd_value::Argv* cmd_val) {
  args::_Attributes* attrs = nullptr;
  args::Reader* arg_r = nullptr;
  arg_types::source* arg = nullptr;
  BigStr* path_arg = nullptr;
  BigStr* builtin_path = nullptr;
  BigStr* load_path = nullptr;
  BigStr* contents = nullptr;
  reader::FileLineReader* line_reader = nullptr;
  cmd_parse::CommandParser* c_parser = nullptr;
  BigStr* resolved = nullptr;
  mylib::LineReader* f = nullptr;
  StackRoot _root0(&cmd_val);
  StackRoot _root1(&attrs);
  StackRoot _root2(&arg_r);
  StackRoot _root3(&arg);
  StackRoot _root4(&path_arg);
  StackRoot _root5(&builtin_path);
  StackRoot _root6(&load_path);
  StackRoot _root7(&contents);
  StackRoot _root8(&line_reader);
  StackRoot _root9(&c_parser);
  StackRoot _root10(&resolved);
  StackRoot _root11(&f);

  Tuple2<args::_Attributes*, args::Reader*> tup2 = flag_util::ParseCmdVal(str294, cmd_val);
  attrs = tup2.at0();
  arg_r = tup2.at1();
  arg = Alloc<arg_types::source>(attrs->attrs);
  path_arg = arg_r->Peek();
  if (path_arg == nullptr) {
    e_usage(str295, loc::Missing);
  }
  arg_r->Next();
  builtin_path = nullptr;
  if (arg->builtin) {
    builtin_path = path_arg;
  }
  else {
    if (path_arg->startswith(str296)) {
      builtin_path = path_arg->slice(3);
    }
  }
  if (builtin_path != nullptr) {
    try {
      load_path = os_path::join(str297, builtin_path);
      contents = this->loader->Get(load_path);
    }
    catch (IOError_OSError*) {
      this->errfmt->Print_(StrFormat("source failed: No builtin file %r", load_path), cmd_val->arg_locs->at(2));
      return 2;
    }
    line_reader = reader::StringLineReader(contents, this->arena);
    c_parser = this->parse_ctx->MakeOshParser(line_reader);
    return this->_Exec(cmd_val, arg_r, load_path, c_parser);
  }
  else {
    resolved = this->search_path->LookupOne(path_arg, false);
    if (resolved == nullptr) {
      resolved = path_arg;
    }
    try {
      f = this->fd_state->Open(resolved);
    }
    catch (IOError_OSError* e) {
      this->errfmt->Print_(StrFormat("source %r failed: %s", path_arg, pyutil::strerror(e)), cmd_val->arg_locs->at(1));
      return 1;
    }
    line_reader = Alloc<reader::FileLineReader>(f, this->arena);
    c_parser = this->parse_ctx->MakeOshParser(line_reader);
    {  // with
      process::ctx_FileCloser ctx{f};

      return this->_Exec(cmd_val, arg_r, path_arg, c_parser);
    }
  }
}

int Source::_Exec(cmd_value::Argv* cmd_val, args::Reader* arg_r, BigStr* path, cmd_parse::CommandParser* c_parser) {
  syntax_asdl::CompoundWord* call_loc = nullptr;
  List<BigStr*>* source_argv = nullptr;
  source::SourcedFile* src = nullptr;
  int status;
  StackRoot _root0(&cmd_val);
  StackRoot _root1(&arg_r);
  StackRoot _root2(&path);
  StackRoot _root3(&c_parser);
  StackRoot _root4(&call_loc);
  StackRoot _root5(&source_argv);
  StackRoot _root6(&src);

  call_loc = cmd_val->arg_locs->at(0);
  {  // with
    dev::ctx_Tracer ctx{this->tracer, str300, cmd_val->argv};

    source_argv = arg_r->Rest();
    {  // with
      state::ctx_Source ctx{this->mem, path, source_argv};

      {  // with
        state::ctx_ThisDir ctx{this->mem, path};

        src = Alloc<source::SourcedFile>(path, call_loc);
        {  // with
          alloc::ctx_SourceCode ctx{this->arena, src};

          try {
            status = main_loop::Batch(this->cmd_ev, c_parser, this->errfmt, cmd_eval::RaiseControlFlow);
          }
          catch (vm::IntControlFlow* e) {
            if (e->IsReturn()) {
              status = e->StatusCode();
            }
            else {
              throw ;
            }
          }
        }
      }
    }
  }
  return status;
}

void _PrintFreeForm(Tuple3<BigStr*, BigStr*, BigStr*>* row) {
  BigStr* name = nullptr;
  BigStr* kind = nullptr;
  BigStr* resolved = nullptr;
  BigStr* what = nullptr;
  StackRoot _root0(&row);
  StackRoot _root1(&name);
  StackRoot _root2(&kind);
  StackRoot _root3(&resolved);
  StackRoot _root4(&what);

  Tuple3<BigStr*, BigStr*, BigStr*>* tup3 = row;
  name = tup3->at0();
  kind = tup3->at1();
  resolved = tup3->at2();
  if (str_equals(kind, str301)) {
    what = resolved;
  }
  else {
    if (str_equals(kind, str302)) {
      what = StrFormat("an alias for %s", j8_lite::EncodeString(resolved, true));
    }
    else {
      what = StrFormat("a shell %s", kind);
    }
  }
  print(StrFormat("%s is %s", name, what));
}

void _PrintEntry(arg_types::type* arg, Tuple3<BigStr*, BigStr*, BigStr*>* row) {
  BigStr* kind = nullptr;
  BigStr* resolved = nullptr;
  StackRoot _root0(&arg);
  StackRoot _root1(&row);
  StackRoot _root2(&kind);
  StackRoot _root3(&resolved);

  Tuple3<BigStr*, BigStr*, BigStr*>* tup4 = row;
  kind = tup4->at1();
  resolved = tup4->at2();
  if (arg->t) {
    print(kind);
  }
  else {
    if (arg->p) {
      if (str_equals(kind, str306)) {
        print(resolved);
      }
    }
    else {
      _PrintFreeForm(row);
    }
  }
}

Command::Command(vm::_Executor* shell_ex, Dict<BigStr*, value::Proc*>* funcs, Dict<BigStr*, BigStr*>* aliases, state::SearchPath* search_path) {
  this->shell_ex = shell_ex;
  this->funcs = funcs;
  this->aliases = aliases;
  this->search_path = search_path;
}

int Command::Run(cmd_value::Argv* cmd_val) {
  args::_Attributes* attrs = nullptr;
  args::Reader* arg_r = nullptr;
  arg_types::command* arg = nullptr;
  List<BigStr*>* argv = nullptr;
  List<syntax_asdl::CompoundWord*>* locs = nullptr;
  int status;
  List<Tuple3<BigStr*, BigStr*, BigStr*>*>* r = nullptr;
  Tuple3<BigStr*, BigStr*, BigStr*>* row = nullptr;
  BigStr* name = nullptr;
  cmd_value::Argv* cmd_val2 = nullptr;
  runtime_asdl::CommandStatus* cmd_st = nullptr;
  int run_flags;
  StackRoot _root0(&cmd_val);
  StackRoot _root1(&attrs);
  StackRoot _root2(&arg_r);
  StackRoot _root3(&arg);
  StackRoot _root4(&argv);
  StackRoot _root5(&locs);
  StackRoot _root6(&r);
  StackRoot _root7(&row);
  StackRoot _root8(&name);
  StackRoot _root9(&cmd_val2);
  StackRoot _root10(&cmd_st);

  Tuple2<args::_Attributes*, args::Reader*> tup5 = flag_util::ParseCmdVal(str307, cmd_val, true);
  attrs = tup5.at0();
  arg_r = tup5.at1();
  arg = Alloc<arg_types::command>(attrs->attrs);
  Tuple2<List<BigStr*>*, List<syntax_asdl::CompoundWord*>*> tup6 = arg_r->Rest2();
  argv = tup6.at0();
  locs = tup6.at1();
  if ((arg->v or arg->V)) {
    status = 0;
    for (ListIter<BigStr*> it(argv); !it.Done(); it.Next()) {
      BigStr* argument = it.Value();
      StackRoot _for(&argument    );
      r = _ResolveName(argument, this->funcs, this->aliases, this->search_path, false);
      if (len(r)) {
        row = r->at(0);
        Tuple3<BigStr*, BigStr*, BigStr*>* tup7 = row;
        name = tup7->at0();
        if (arg->v) {
          print(name);
        }
        else {
          _PrintFreeForm(row);
        }
      }
      else {
        print_stderr(StrFormat("%s: not found", argument));
        status = 1;
      }
    }
    return status;
  }
  cmd_val2 = Alloc<cmd_value::Argv>(argv, locs, cmd_val->typed_args, cmd_val->pos_args, cmd_val->named_args, cmd_val->block_arg);
  cmd_st = CommandStatus::CreateNull(true);
  run_flags = (executor::DO_FORK | executor::NO_CALL_PROCS);
  if (arg->p) {
    run_flags |= executor::USE_DEFAULT_PATH;
  }
  return this->shell_ex->RunSimpleCommand(cmd_val2, cmd_st, run_flags);
}

cmd_value::Argv* _ShiftArgv(cmd_value::Argv* cmd_val) {
  StackRoot _root0(&cmd_val);

  return Alloc<cmd_value::Argv>(cmd_val->argv->slice(1), cmd_val->arg_locs->slice(1), cmd_val->typed_args, cmd_val->pos_args, cmd_val->named_args, cmd_val->block_arg);
}

Builtin::Builtin(vm::_Executor* shell_ex, ui::ErrorFormatter* errfmt) {
  this->shell_ex = shell_ex;
  this->errfmt = errfmt;
}

int Builtin::Run(cmd_value::Argv* cmd_val) {
  BigStr* name = nullptr;
  int to_run;
  syntax_asdl::CompoundWord* location = nullptr;
  cmd_value::Argv* cmd_val2 = nullptr;
  StackRoot _root0(&cmd_val);
  StackRoot _root1(&name);
  StackRoot _root2(&location);
  StackRoot _root3(&cmd_val2);

  if (len(cmd_val->argv) == 1) {
    return 0;
  }
  name = cmd_val->argv->at(1);
  to_run = consts::LookupNormalBuiltin(name);
  if (to_run == consts::NO_INDEX) {
    to_run = consts::LookupSpecialBuiltin(name);
  }
  if (to_run == consts::NO_INDEX) {
    location = cmd_val->arg_locs->at(1);
    if (consts::LookupAssignBuiltin(name) != consts::NO_INDEX) {
      this->errfmt->Print_(str309, location);
    }
    else {
      this->errfmt->Print_(StrFormat("%r isn't a shell builtin", name), location);
    }
    return 1;
  }
  cmd_val2 = _ShiftArgv(cmd_val);
  return this->shell_ex->RunBuiltin(to_run, cmd_val2);
}

RunProc::RunProc(vm::_Executor* shell_ex, Dict<BigStr*, value::Proc*>* procs, ui::ErrorFormatter* errfmt) {
  this->shell_ex = shell_ex;
  this->procs = procs;
  this->errfmt = errfmt;
}

int RunProc::Run(cmd_value::Argv* cmd_val) {
  args::Reader* arg_r = nullptr;
  List<BigStr*>* argv = nullptr;
  List<syntax_asdl::CompoundWord*>* locs = nullptr;
  BigStr* name = nullptr;
  cmd_value::Argv* cmd_val2 = nullptr;
  runtime_asdl::CommandStatus* cmd_st = nullptr;
  StackRoot _root0(&cmd_val);
  StackRoot _root1(&arg_r);
  StackRoot _root2(&argv);
  StackRoot _root3(&locs);
  StackRoot _root4(&name);
  StackRoot _root5(&cmd_val2);
  StackRoot _root6(&cmd_st);

  Tuple2<args::_Attributes*, args::Reader*> tup8 = flag_util::ParseCmdVal(str311, cmd_val, true);
  arg_r = tup8.at1();
  Tuple2<List<BigStr*>*, List<syntax_asdl::CompoundWord*>*> tup9 = arg_r->Rest2();
  argv = tup9.at0();
  locs = tup9.at1();
  if (len(argv) == 0) {
    throw Alloc<error::Usage>(str312, loc::Missing);
  }
  name = argv->at(0);
  if (!dict_contains(this->procs, name)) {
    this->errfmt->PrintMessage(StrFormat("runproc: no proc named %r", name));
    return 1;
  }
  cmd_val2 = Alloc<cmd_value::Argv>(argv, locs, cmd_val->typed_args, cmd_val->pos_args, cmd_val->named_args, cmd_val->block_arg);
  cmd_st = CommandStatus::CreateNull(true);
  return this->shell_ex->RunSimpleCommand(cmd_val2, cmd_st, executor::DO_FORK);
}

List<Tuple3<BigStr*, BigStr*, BigStr*>*>* _ResolveName(BigStr* name, Dict<BigStr*, value::Proc*>* funcs, Dict<BigStr*, BigStr*>* aliases, state::SearchPath* search_path, bool do_all) {
  BigStr* no_str = nullptr;
  List<Tuple3<BigStr*, BigStr*, BigStr*>*>* results = nullptr;
  StackRoot _root0(&name);
  StackRoot _root1(&funcs);
  StackRoot _root2(&aliases);
  StackRoot _root3(&search_path);
  StackRoot _root4(&no_str);
  StackRoot _root5(&results);

  no_str = nullptr;
  results = Alloc<List<Tuple3<BigStr*, BigStr*, BigStr*>*>>();
  if (dict_contains(funcs, name)) {
    results->append((Alloc<Tuple3<BigStr*, BigStr*, BigStr*>>(name, str314, no_str)));
  }
  if (dict_contains(aliases, name)) {
    results->append((Alloc<Tuple3<BigStr*, BigStr*, BigStr*>>(name, str315, aliases->at(name))));
  }
  if (consts::LookupNormalBuiltin(name) != 0) {
    results->append((Alloc<Tuple3<BigStr*, BigStr*, BigStr*>>(name, str316, no_str)));
  }
  else {
    if (consts::LookupSpecialBuiltin(name) != 0) {
      results->append((Alloc<Tuple3<BigStr*, BigStr*, BigStr*>>(name, str317, no_str)));
    }
    else {
      if (consts::LookupAssignBuiltin(name) != 0) {
        results->append((Alloc<Tuple3<BigStr*, BigStr*, BigStr*>>(name, str318, no_str)));
      }
    }
  }
  if (consts::IsControlFlow(name)) {
    results->append((Alloc<Tuple3<BigStr*, BigStr*, BigStr*>>(name, str319, no_str)));
  }
  else {
    if (consts::IsKeyword(name)) {
      results->append((Alloc<Tuple3<BigStr*, BigStr*, BigStr*>>(name, str320, no_str)));
    }
  }
  for (ListIter<BigStr*> it(search_path->LookupReflect(name, do_all)); !it.Done(); it.Next()) {
    BigStr* path = it.Value();
    StackRoot _for(&path  );
    if (posix::access(path, X_OK)) {
      results->append((Alloc<Tuple3<BigStr*, BigStr*, BigStr*>>(name, str321, path)));
    }
  }
  return results;
}

Type::Type(Dict<BigStr*, value::Proc*>* funcs, Dict<BigStr*, BigStr*>* aliases, state::SearchPath* search_path, ui::ErrorFormatter* errfmt) {
  this->funcs = funcs;
  this->aliases = aliases;
  this->search_path = search_path;
  this->errfmt = errfmt;
}

int Type::Run(cmd_value::Argv* cmd_val) {
  args::_Attributes* attrs = nullptr;
  args::Reader* arg_r = nullptr;
  arg_types::type* arg = nullptr;
  Dict<BigStr*, value::Proc*>* funcs = nullptr;
  int status;
  List<BigStr*>* names = nullptr;
  List<BigStr*>* paths = nullptr;
  List<Tuple3<BigStr*, BigStr*, BigStr*>*>* r = nullptr;
  StackRoot _root0(&cmd_val);
  StackRoot _root1(&attrs);
  StackRoot _root2(&arg_r);
  StackRoot _root3(&arg);
  StackRoot _root4(&funcs);
  StackRoot _root5(&names);
  StackRoot _root6(&paths);
  StackRoot _root7(&r);

  Tuple2<args::_Attributes*, args::Reader*> tup10 = flag_util::ParseCmdVal(str322, cmd_val);
  attrs = tup10.at0();
  arg_r = tup10.at1();
  arg = Alloc<arg_types::type>(attrs->attrs);
  if (arg->f) {
    funcs = Alloc<Dict<BigStr*, value::Proc*>>();
  }
  else {
    funcs = this->funcs;
  }
  status = 0;
  names = arg_r->Rest();
  if (arg->P) {
    for (ListIter<BigStr*> it(names); !it.Done(); it.Next()) {
      BigStr* name = it.Value();
      StackRoot _for(&name    );
      paths = this->search_path->LookupReflect(name, arg->a);
      if (len(paths)) {
        for (ListIter<BigStr*> it(paths); !it.Done(); it.Next()) {
          BigStr* path = it.Value();
          StackRoot _for(&path        );
          print(path);
        }
      }
      else {
        status = 1;
      }
    }
    return status;
  }
  for (ListIter<BigStr*> it(names); !it.Done(); it.Next()) {
    BigStr* argument = it.Value();
    StackRoot _for(&argument  );
    r = _ResolveName(argument, funcs, this->aliases, this->search_path, arg->a);
    if (arg->a) {
      for (ListIter<Tuple3<BigStr*, BigStr*, BigStr*>*> it(r); !it.Done(); it.Next()) {
        Tuple3<BigStr*, BigStr*, BigStr*>* row = it.Value();
        _PrintEntry(arg, row);
      }
    }
    else {
      if (len(r)) {
        _PrintEntry(arg, r->at(0));
      }
    }
    if (len(r) == 0) {
      if (!arg->t) {
        print_stderr(StrFormat("%s: not found", argument));
      }
      status = 1;
    }
  }
  return status;
}

}  // define namespace meta_osh

namespace method_dict {  // define

using value_asdl::value;
using value_asdl::value_t;

Keys::Keys() {
  ;  // pass
}

value_asdl::value_t* Keys::Call(typed_args::Reader* rd) {
  Dict<BigStr*, value_asdl::value_t*>* dictionary = nullptr;
  List<value_asdl::value_t*>* keys = nullptr;
  StackRoot _root0(&rd);
  StackRoot _root1(&dictionary);
  StackRoot _root2(&keys);

  dictionary = rd->PosDict();
  rd->Done();
  keys = Alloc<List<value_asdl::value_t*>>();
  for (ListIter<BigStr*> it(dictionary->keys()); !it.Done(); it.Next()) {
    BigStr* k = it.Value();
    keys->append(Alloc<value::Str>(k));
  }
  return Alloc<value::List>(keys);
}

Values::Values() {
  ;  // pass
}

value_asdl::value_t* Values::Call(typed_args::Reader* rd) {
  Dict<BigStr*, value_asdl::value_t*>* dictionary = nullptr;
  List<value_asdl::value_t*>* values = nullptr;
  StackRoot _root0(&rd);
  StackRoot _root1(&dictionary);
  StackRoot _root2(&values);

  dictionary = rd->PosDict();
  rd->Done();
  values = dictionary->values();
  return Alloc<value::List>(values);
}

}  // define namespace method_dict

namespace method_io {  // define

using value_asdl::value;
using value_asdl::value_t;

Eval::Eval() {
  ;  // pass
}

value_asdl::value_t* Eval::Call(typed_args::Reader* rd) {
  StackRoot _root0(&rd);

  return value::Null;
}

CaptureStdout::CaptureStdout() {
  ;  // pass
}

value_asdl::value_t* CaptureStdout::Call(typed_args::Reader* rd) {
  StackRoot _root0(&rd);

  return value::Null;
}

PromptVal::PromptVal() {
  ;  // pass
}

value_asdl::value_t* PromptVal::Call(typed_args::Reader* rd) {
  value::IO* io = nullptr;
  BigStr* what = nullptr;
  prompt::Evaluator* prompt_ev = nullptr;
  StackRoot _root0(&rd);
  StackRoot _root1(&io);
  StackRoot _root2(&what);
  StackRoot _root3(&prompt_ev);

  io = rd->PosIO();
  what = rd->PosStr();
  rd->Done();
  if (len(what) != 1) {
    throw Alloc<error::Expr>(StrFormat("promptVal() expected a single char, got %r", what), rd->LeftParenToken());
  }
  prompt_ev = static_cast<prompt::Evaluator*>(io->prompt_ev);
  return Alloc<value::Str>(prompt_ev->PromptVal(what));
}

Time::Time() {
  ;  // pass
}

value_asdl::value_t* Time::Call(typed_args::Reader* rd) {
  StackRoot _root0(&rd);

  return value::Null;
}

Strftime::Strftime() {
  ;  // pass
}

value_asdl::value_t* Strftime::Call(typed_args::Reader* rd) {
  StackRoot _root0(&rd);

  return value::Null;
}

}  // define namespace method_io

namespace method_list {  // define

using value_asdl::value;
using value_asdl::value_t;

Append::Append() {
  ;  // pass
}

value_asdl::value_t* Append::Call(typed_args::Reader* rd) {
  List<value_asdl::value_t*>* items = nullptr;
  value_asdl::value_t* to_append = nullptr;
  StackRoot _root0(&rd);
  StackRoot _root1(&items);
  StackRoot _root2(&to_append);

  items = rd->PosList();
  to_append = rd->PosValue();
  rd->Done();
  items->append(to_append);
  return value::Null;
}

Extend::Extend() {
  ;  // pass
}

value_asdl::value_t* Extend::Call(typed_args::Reader* rd) {
  List<value_asdl::value_t*>* a = nullptr;
  List<value_asdl::value_t*>* b = nullptr;
  StackRoot _root0(&rd);
  StackRoot _root1(&a);
  StackRoot _root2(&b);

  a = rd->PosList();
  b = rd->PosList();
  rd->Done();
  a->extend(b);
  return value::Null;
}

Pop::Pop() {
  ;  // pass
}

value_asdl::value_t* Pop::Call(typed_args::Reader* rd) {
  List<value_asdl::value_t*>* items = nullptr;
  StackRoot _root0(&rd);
  StackRoot _root1(&items);

  items = rd->PosList();
  rd->Done();
  return items->pop();
}

Reverse::Reverse() {
  ;  // pass
}

value_asdl::value_t* Reverse::Call(typed_args::Reader* rd) {
  List<value_asdl::value_t*>* li = nullptr;
  StackRoot _root0(&rd);
  StackRoot _root1(&li);

  li = rd->PosList();
  rd->Done();
  li->reverse();
  return value::Null;
}

IndexOf::IndexOf() {
  ;  // pass
}

value_asdl::value_t* IndexOf::Call(typed_args::Reader* rd) {
  List<value_asdl::value_t*>* li = nullptr;
  value_asdl::value_t* needle = nullptr;
  int i;
  StackRoot _root0(&rd);
  StackRoot _root1(&li);
  StackRoot _root2(&needle);

  li = rd->PosList();
  needle = rd->PosValue();
  rd->Done();
  i = 0;
  while (i < len(li)) {
    if (val_ops::ExactlyEqual(li->at(i), needle, rd->LeftParenToken())) {
      return num::ToBig(i);
    }
    i += 1;
  }
  return Alloc<value::Int>(mops::MINUS_ONE);
}

}  // define namespace method_list

namespace method_other {  // define

using value_asdl::value;
using value_asdl::value_t;

SetValue::SetValue(state::Mem* mem) {
  this->mem = mem;
}

value_asdl::value_t* SetValue::Call(typed_args::Reader* rd) {
  value::Place* place = nullptr;
  value_asdl::value_t* val = nullptr;
  StackRoot _root0(&rd);
  StackRoot _root1(&place);
  StackRoot _root2(&val);

  place = rd->PosPlace();
  val = rd->PosValue();
  rd->Done();
  this->mem->SetPlace(place, val, rd->LeftParenToken());
  return value::Null;
}

}  // define namespace method_other

namespace method_str {  // define

using syntax_asdl::loc_t;
using syntax_asdl::loc;
using runtime_asdl::scope_e;
using value_asdl::value;
using value_asdl::value_e;
using value_asdl::value_t;
using value_asdl::eggex_ops;
using value_asdl::eggex_ops_t;
using value_asdl::RegexMatch;
using value_asdl::LeftName;

Tuple3<bool, int, int> _StrMatchStart(BigStr* s, BigStr* p) {
  StackRoot _root0(&s);
  StackRoot _root1(&p);

  if (s->startswith(p)) {
    return Tuple3<bool, int, int>(true, 0, len(p));
  }
  else {
    return Tuple3<bool, int, int>(false, 0, 0);
  }
}

Tuple3<bool, int, int> _StrMatchEnd(BigStr* s, BigStr* p) {
  int len_s;
  StackRoot _root0(&s);
  StackRoot _root1(&p);

  len_s = len(s);
  if (s->endswith(p)) {
    return Tuple3<bool, int, int>(true, (len_s - len(p)), len_s);
  }
  else {
    return Tuple3<bool, int, int>(false, len_s, len_s);
  }
}

Tuple3<bool, int, int> _EggexMatchCommon(BigStr* s, value::Eggex* p, BigStr* ere, int empty_p) {
  int cflags;
  int eflags;
  List<int>* indices = nullptr;
  int start;
  int end;
  StackRoot _root0(&s);
  StackRoot _root1(&p);
  StackRoot _root2(&ere);
  StackRoot _root3(&indices);

  cflags = regex_translate::LibcFlags(p->canonical_flags);
  eflags = 0;
  indices = libc::regex_search(ere, cflags, s, eflags);
  if (indices == nullptr) {
    return Tuple3<bool, int, int>(false, empty_p, empty_p);
  }
  start = indices->at(0);
  end = indices->at(1);
  return Tuple3<bool, int, int>(true, start, end);
}

Tuple3<bool, int, int> _EggexMatchStart(BigStr* s, value::Eggex* p) {
  BigStr* ere = nullptr;
  StackRoot _root0(&s);
  StackRoot _root1(&p);
  StackRoot _root2(&ere);

  ere = regex_translate::AsPosixEre(p);
  if (!ere->startswith(str325)) {
    ere = str_concat(str326, ere);
  }
  return _EggexMatchCommon(s, p, ere, 0);
}

Tuple3<bool, int, int> _EggexMatchEnd(BigStr* s, value::Eggex* p) {
  BigStr* ere = nullptr;
  StackRoot _root0(&s);
  StackRoot _root1(&p);
  StackRoot _root2(&ere);

  ere = regex_translate::AsPosixEre(p);
  if (!ere->endswith(str327)) {
    ere = str_concat(ere, str328);
  }
  return _EggexMatchCommon(s, p, ere, len(s));
}
int START = 1;
int END = 2;

HasAffix::HasAffix(int anchor) {
  this->anchor = anchor;
}

value_asdl::value_t* HasAffix::Call(typed_args::Reader* rd) {
  BigStr* string = nullptr;
  value_asdl::value_t* pattern_val = nullptr;
  BigStr* pattern_str = nullptr;
  value::Eggex* pattern_eggex = nullptr;
  bool matched;
  StackRoot _root0(&rd);
  StackRoot _root1(&string);
  StackRoot _root2(&pattern_val);
  StackRoot _root3(&pattern_str);
  StackRoot _root4(&pattern_eggex);

  string = rd->PosStr();
  pattern_val = rd->PosValue();
  pattern_str = nullptr;
  pattern_eggex = nullptr;
  switch (pattern_val->tag()) {
    case value_e::Eggex: {
      pattern_eggex = static_cast<value::Eggex*>(pattern_val);
    }
      break;
    case value_e::Str: {
      pattern_str = static_cast<value::Str*>(pattern_val)->s;
    }
      break;
    default: {
      throw Alloc<error::TypeErr>(pattern_val, str329, rd->LeftParenToken());
    }
  }
  rd->Done();
  matched = false;
  try {
    if (pattern_str != nullptr) {
      if ((this->anchor & START)) {
        Tuple3<bool, int, int> tup0 = _StrMatchStart(string, pattern_str);
        matched = tup0.at0();
      }
      else {
        Tuple3<bool, int, int> tup1 = _StrMatchEnd(string, pattern_str);
        matched = tup1.at0();
      }
    }
    else {
      if ((this->anchor & START)) {
        Tuple3<bool, int, int> tup2 = _EggexMatchStart(string, pattern_eggex);
        matched = tup2.at0();
      }
      else {
        Tuple3<bool, int, int> tup3 = _EggexMatchEnd(string, pattern_eggex);
        matched = tup3.at0();
      }
    }
  }
  catch (error::Strict* e) {
    throw Alloc<error::Expr>(e->msg, e->location);
  }
  return Alloc<value::Bool>(matched);
}

Trim::Trim(int anchor) {
  this->anchor = anchor;
}

value_asdl::value_t* Trim::Call(typed_args::Reader* rd) {
  BigStr* string = nullptr;
  value_asdl::value_t* pattern_val = nullptr;
  BigStr* pattern_str = nullptr;
  value::Eggex* pattern_eggex = nullptr;
  int start;
  int end;
  BigStr* res = nullptr;
  StackRoot _root0(&rd);
  StackRoot _root1(&string);
  StackRoot _root2(&pattern_val);
  StackRoot _root3(&pattern_str);
  StackRoot _root4(&pattern_eggex);
  StackRoot _root5(&res);

  string = rd->PosStr();
  pattern_val = rd->OptionalValue();
  pattern_str = nullptr;
  pattern_eggex = nullptr;
  if (pattern_val) {
    switch (pattern_val->tag()) {
      case value_e::Eggex: {
        pattern_eggex = static_cast<value::Eggex*>(pattern_val);
      }
        break;
      case value_e::Str: {
        pattern_str = static_cast<value::Str*>(pattern_val)->s;
      }
        break;
      default: {
        throw Alloc<error::TypeErr>(pattern_val, str330, rd->LeftParenToken());
      }
    }
  }
  rd->Done();
  start = 0;
  end = len(string);
  try {
    if (pattern_str != nullptr) {
      if ((this->anchor & START)) {
        Tuple3<bool, int, int> tup4 = _StrMatchStart(string, pattern_str);
        start = tup4.at2();
      }
      if ((this->anchor & END)) {
        Tuple3<bool, int, int> tup5 = _StrMatchEnd(string, pattern_str);
        end = tup5.at1();
      }
    }
    else {
      if (pattern_eggex != nullptr) {
        if ((this->anchor & START)) {
          Tuple3<bool, int, int> tup6 = _EggexMatchStart(string, pattern_eggex);
          start = tup6.at2();
        }
        if ((this->anchor & END)) {
          Tuple3<bool, int, int> tup7 = _EggexMatchEnd(string, pattern_eggex);
          end = tup7.at1();
        }
      }
      else {
        if ((this->anchor & START)) {
          Tuple2<int, int> tup8 = string_ops::StartsWithWhitespaceByteRange(string);
          start = tup8.at1();
        }
        if ((this->anchor & END)) {
          Tuple2<int, int> tup9 = string_ops::EndsWithWhitespaceByteRange(string);
          end = tup9.at0();
        }
      }
    }
  }
  catch (error::Strict* e) {
    throw Alloc<error::Expr>(e->msg, e->location);
  }
  res = string->slice(start, end);
  return Alloc<value::Str>(res);
}

Upper::Upper() {
  ;  // pass
}

value_asdl::value_t* Upper::Call(typed_args::Reader* rd) {
  BigStr* s = nullptr;
  StackRoot _root0(&rd);
  StackRoot _root1(&s);

  s = rd->PosStr();
  rd->Done();
  return Alloc<value::Str>(s->upper());
}

Lower::Lower() {
  ;  // pass
}

value_asdl::value_t* Lower::Call(typed_args::Reader* rd) {
  BigStr* s = nullptr;
  StackRoot _root0(&rd);
  StackRoot _root1(&s);

  s = rd->PosStr();
  rd->Done();
  return Alloc<value::Str>(s->lower());
}
int SEARCH = 0;
int LEFT_MATCH = 1;

SearchMatch::SearchMatch(int which_method) {
  this->which_method = which_method;
}

value_asdl::value_t* SearchMatch::Call(typed_args::Reader* rd) {
  BigStr* string = nullptr;
  value_asdl::value_t* pattern = nullptr;
  value::Eggex* eggex_val = nullptr;
  BigStr* ere = nullptr;
  int cflags;
  value_asdl::eggex_ops_t* capture = nullptr;
  int pos;
  int eflags;
  List<int>* indices = nullptr;
  StackRoot _root0(&rd);
  StackRoot _root1(&string);
  StackRoot _root2(&pattern);
  StackRoot _root3(&eggex_val);
  StackRoot _root4(&ere);
  StackRoot _root5(&capture);
  StackRoot _root6(&indices);

  string = rd->PosStr();
  pattern = rd->PosValue();
  switch (pattern->tag()) {
    case value_e::Eggex: {
      eggex_val = static_cast<value::Eggex*>(pattern);
      ere = regex_translate::AsPosixEre(eggex_val);
      cflags = regex_translate::LibcFlags(eggex_val->canonical_flags);
      capture = Alloc<eggex_ops::Yes>(eggex_val->convert_funcs, eggex_val->convert_toks, eggex_val->capture_names);
    }
      break;
    case value_e::Str: {
      ere = static_cast<value::Str*>(pattern)->s;
      cflags = 0;
      capture = eggex_ops::No;
    }
      break;
    default: {
      throw Alloc<error::TypeErr>(pattern, str331, rd->LeftParenToken());
    }
  }
  pos = mops::BigTruncate(rd->NamedInt(str332, 0));
  rd->Done();
  if ((this->which_method == LEFT_MATCH and !ere->startswith(str333))) {
    ere = str_concat(str334, ere);
  }
  if (this->which_method == LEFT_MATCH) {
    eflags = 0;
  }
  else {
    eflags = pos == 0 ? 0 : REG_NOTBOL;
  }
  indices = libc::regex_search(ere, cflags, string, eflags, pos);
  if (indices == nullptr) {
    return value::Null;
  }
  return Alloc<RegexMatch>(string, indices, capture);
}

ctx_EvalReplace::ctx_EvalReplace(state::Mem* mem, BigStr* arg0, List<BigStr*>* argv) {
  gHeap.PushRoot(reinterpret_cast<RawObject**>(&(this->lval)));
  gHeap.PushRoot(reinterpret_cast<RawObject**>(&(this->mem)));
  if (argv == nullptr) {
    this->pushed_argv = false;
  }
  else {
    mem->argv_stack->append(Alloc<state::_ArgFrame>(argv));
    this->pushed_argv = true;
  }
  this->lval = Alloc<LeftName>(str335, loc::Missing);
  mem->SetLocalName(this->lval, Alloc<value::Str>(arg0));
  this->mem = mem;
}

ctx_EvalReplace::~ctx_EvalReplace() {
  this->mem->SetLocalName(this->lval, value::Undef);
  if (this->pushed_argv) {
    this->mem->argv_stack->pop();
  }
  gHeap.PopRoot();
  gHeap.PopRoot();
}

Replace::Replace(state::Mem* mem, expr_eval::ExprEvaluator* expr_ev) {
  this->mem = mem;
  this->expr_ev = expr_ev;
}

BigStr* Replace::EvalSubstExpr(value::Expr* expr, syntax_asdl::loc_t* blame_loc) {
  value_asdl::value_t* res = nullptr;
  StackRoot _root0(&expr);
  StackRoot _root1(&blame_loc);
  StackRoot _root2(&res);

  res = this->expr_ev->EvalExpr(expr->e, blame_loc);
  if (res->tag() == value_e::Str) {
    return static_cast<value::Str*>(res)->s;
  }
  throw Alloc<error::TypeErr>(res, str336, blame_loc);
}

value_asdl::value_t* Replace::Call(typed_args::Reader* rd) {
  BigStr* string = nullptr;
  value::Str* string_val = nullptr;
  value::Eggex* eggex_val = nullptr;
  value::Str* subst_str = nullptr;
  value::Expr* subst_expr = nullptr;
  value_asdl::value_t* pattern = nullptr;
  value::Eggex* eggex_val_ = nullptr;
  value::Str* string_val_ = nullptr;
  value_asdl::value_t* subst = nullptr;
  value::Str* subst_str_ = nullptr;
  value::Expr* subst_expr_ = nullptr;
  int count;
  BigStr* s = nullptr;
  BigStr* result = nullptr;
  BigStr* ere = nullptr;
  int cflags;
  int pos;
  List<BigStr*>* parts = nullptr;
  int replace_count;
  List<int>* indices = nullptr;
  BigStr* arg0 = nullptr;
  List<BigStr*>* argv = nullptr;
  List<Tuple2<BigStr*, value_asdl::value_t*>*>* named_vars = nullptr;
  int num_groups;
  int start;
  int end;
  BigStr* captured = nullptr;
  value_asdl::value_t* val = nullptr;
  value_asdl::value_t* convert_func = nullptr;
  syntax_asdl::Token* convert_tok = nullptr;
  BigStr* val_str = nullptr;
  BigStr* name = nullptr;
  StackRoot _root0(&rd);
  StackRoot _root1(&string);
  StackRoot _root2(&string_val);
  StackRoot _root3(&eggex_val);
  StackRoot _root4(&subst_str);
  StackRoot _root5(&subst_expr);
  StackRoot _root6(&pattern);
  StackRoot _root7(&eggex_val_);
  StackRoot _root8(&string_val_);
  StackRoot _root9(&subst);
  StackRoot _root10(&subst_str_);
  StackRoot _root11(&subst_expr_);
  StackRoot _root12(&s);
  StackRoot _root13(&result);
  StackRoot _root14(&ere);
  StackRoot _root15(&parts);
  StackRoot _root16(&indices);
  StackRoot _root17(&arg0);
  StackRoot _root18(&argv);
  StackRoot _root19(&named_vars);
  StackRoot _root20(&captured);
  StackRoot _root21(&val);
  StackRoot _root22(&convert_func);
  StackRoot _root23(&convert_tok);
  StackRoot _root24(&val_str);
  StackRoot _root25(&name);

  string = rd->PosStr();
  string_val = nullptr;
  eggex_val = nullptr;
  subst_str = nullptr;
  subst_expr = nullptr;
  pattern = rd->PosValue();
  switch (pattern->tag()) {
    case value_e::Eggex: {
      eggex_val_ = static_cast<value::Eggex*>(pattern);
      eggex_val = eggex_val_;
    }
      break;
    case value_e::Str: {
      string_val_ = static_cast<value::Str*>(pattern);
      string_val = string_val_;
    }
      break;
    default: {
      throw Alloc<error::TypeErr>(pattern, str337, rd->LeftParenToken());
    }
  }
  subst = rd->PosValue();
  switch (subst->tag()) {
    case value_e::Str: {
      subst_str_ = static_cast<value::Str*>(subst);
      subst_str = subst_str_;
    }
      break;
    case value_e::Expr: {
      subst_expr_ = static_cast<value::Expr*>(subst);
      subst_expr = subst_expr_;
    }
      break;
    default: {
      throw Alloc<error::TypeErr>(subst, str338, rd->LeftParenToken());
    }
  }
  count = mops::BigTruncate(rd->NamedInt(str339, -1));
  rd->Done();
  if (count == 0) {
    return Alloc<value::Str>(string);
  }
  if (string_val) {
    if (subst_str) {
      s = subst_str->s;
    }
    if (subst_expr) {
      {  // with
        ctx_EvalReplace ctx{this->mem, string_val->s, nullptr};

        s = this->EvalSubstExpr(subst_expr, rd->LeftParenToken());
      }
    }
    result = string->replace(string_val->s, s, count);
    return Alloc<value::Str>(result);
  }
  if (eggex_val) {
    ere = regex_translate::AsPosixEre(eggex_val);
    cflags = regex_translate::LibcFlags(eggex_val->canonical_flags);
    pos = 0;
    parts = Alloc<List<BigStr*>>();
    replace_count = 0;
    while (pos < len(string)) {
      indices = libc::regex_search(ere, cflags, string, 0, pos);
      if (indices == nullptr) {
        break;
      }
      arg0 = nullptr;
      argv = Alloc<List<BigStr*>>();
      named_vars = Alloc<List<Tuple2<BigStr*, value_asdl::value_t*>*>>();
      num_groups = (len(indices) / 2);
      for (int group = 0; group < num_groups; ++group) {
        start = indices->at((2 * group));
        end = indices->at(((2 * group) + 1));
        captured = string->slice(start, end);
        val = Alloc<value::Str>(captured);
        if ((len(eggex_val->convert_funcs) and group != 0)) {
          convert_func = eggex_val->convert_funcs->at((group - 1));
          convert_tok = eggex_val->convert_toks->at((group - 1));
          if (convert_func) {
            val = this->expr_ev->CallConvertFunc(convert_func, val, convert_tok, rd->LeftParenToken());
          }
        }
        val_str = val_ops::Stringify(val, rd->LeftParenToken());
        if (group == 0) {
          arg0 = val_str;
        }
        else {
          argv->append(val_str);
        }
        if (group != 0) {
          name = eggex_val->capture_names->at((group - 2));
          if (name != nullptr) {
            named_vars->append((Alloc<Tuple2<BigStr*, value_asdl::value_t*>>(name, val)));
          }
        }
      }
      if (subst_str) {
        s = subst_str->s;
      }
      if (subst_expr) {
        {  // with
          ctx_EvalReplace ctx{this->mem, arg0, argv};

          {  // with
            pure_ysh::ctx_Shvar ctx{this->mem, named_vars};

            s = this->EvalSubstExpr(subst_expr, rd->LeftParenToken());
          }
        }
      }
      start = indices->at(0);
      end = indices->at(1);
      parts->append(string->slice(pos, start));
      parts->append(s);
      pos = end;
      replace_count += 1;
      if ((count != -1 and replace_count == count)) {
        break;
      }
    }
    parts->append(string->slice(pos));
    return Alloc<value::Str>(str340->join(parts));
  }
  assert(0);  // AssertionError
}

}  // define namespace method_str

namespace misc_osh {  // define

using runtime_asdl::cmd_value;
using syntax_asdl::loc_t;

Times::Times() : ::vm::_Builtin() {
}

int Times::Run(cmd_value::Argv* cmd_val) {
  StackRoot _root0(&cmd_val);

  pyos::PrintTimes();
  return 0;
}

Help::Help(BigStr* lang, pyutil::_ResourceLoader* loader, Dict<BigStr*, BigStr*>* help_data, ui::ErrorFormatter* errfmt) {
  this->lang = lang;
  this->loader = loader;
  this->help_data = help_data;
  this->errfmt = errfmt;
  this->version_str = pyutil::GetVersion(this->loader);
  this->f = mylib::Stdout();
}

int Help::_ShowTopic(BigStr* topic_id, syntax_asdl::loc_t* blame_loc) {
  BigStr* prefix = nullptr;
  BigStr* chapter_name = nullptr;
  bool found;
  StackRoot _root0(&topic_id);
  StackRoot _root1(&blame_loc);
  StackRoot _root2(&prefix);
  StackRoot _root3(&chapter_name);

  prefix = str341;
  chapter_name = this->help_data->get(topic_id);
  if (chapter_name != nullptr) {
    util::PrintTopicHeader(topic_id, this->f);
    print(StrFormat("    %s/%s/doc/ref/chap-%s.html#%s", prefix, this->version_str, chapter_name, topic_id));
    return 0;
  }
  found = util::PrintEmbeddedHelp(this->loader, topic_id, this->f);
  if (!found) {
    this->errfmt->Print_(StrFormat("no help topics match %r", topic_id), blame_loc);
    return 1;
  }
  return 0;
}

int Help::Run(cmd_value::Argv* cmd_val) {
  args::_Attributes* attrs = nullptr;
  args::Reader* arg_r = nullptr;
  BigStr* topic_id = nullptr;
  syntax_asdl::loc_t* blame_loc = nullptr;
  bool found;
  StackRoot _root0(&cmd_val);
  StackRoot _root1(&attrs);
  StackRoot _root2(&arg_r);
  StackRoot _root3(&topic_id);
  StackRoot _root4(&blame_loc);

  Tuple2<args::_Attributes*, args::Reader*> tup0 = flag_util::ParseCmdVal(str344, cmd_val);
  attrs = tup0.at0();
  arg_r = tup0.at1();
  Tuple2<BigStr*, syntax_asdl::loc_t*> tup1 = arg_r->Peek2();
  topic_id = tup1.at0();
  blame_loc = tup1.at1();
  if (topic_id == nullptr) {
    found = this->_ShowTopic(str345, blame_loc) == 0;
    found = this->_ShowTopic(StrFormat("%s-chapters", this->lang), blame_loc) == 0;
    print(StrFormat("All docs: https://www.oilshell.org/release/%s/doc/", this->version_str));
    print(str348);
    return 0;
  }
  else {
    arg_r->Next();
  }
  return this->_ShowTopic(topic_id, blame_loc);
}

}  // define namespace misc_osh

namespace module_ysh {  // define

using runtime_asdl::scope_e;
using syntax_asdl::loc;
using value_asdl::value;
using value_asdl::value_e;

IsMain::IsMain(state::Mem* mem) {
  this->mem = mem;
}

int IsMain::Run(cmd_value::Argv* cmd_val) {
  StackRoot _root0(&cmd_val);

  return this->mem->is_main ? 0 : 1;
}

SourceGuard::SourceGuard(Dict<BigStr*, bool>* guards, optview::Exec* exec_opts, ui::ErrorFormatter* errfmt) {
  this->guards = guards;
  this->exec_opts = exec_opts;
  this->errfmt = errfmt;
}

int SourceGuard::Run(cmd_value::Argv* cmd_val) {
  args::Reader* arg_r = nullptr;
  BigStr* name = nullptr;
  StackRoot _root0(&cmd_val);
  StackRoot _root1(&arg_r);
  StackRoot _root2(&name);

  Tuple2<args::_Attributes*, args::Reader*> tup0 = flag_util::ParseCmdVal(str349, cmd_val);
  arg_r = tup0.at1();
  Tuple2<BigStr*, syntax_asdl::loc_t*> tup1 = arg_r->ReadRequired2(str350);
  name = tup1.at0();
  if (dict_contains(this->guards, name)) {
    if (this->exec_opts->redefine_module()) {
      this->errfmt->PrintMessage(StrFormat("(interactive) Reloading source file %r", name));
      return 0;
    }
    else {
      return 1;
    }
  }
  this->guards->set(name, true);
  return 0;
}

Use::Use(state::Mem* mem, ui::ErrorFormatter* errfmt) {
  this->mem = mem;
  this->errfmt = errfmt;
}

int Use::Run(cmd_value::Argv* cmd_val) {
  args::Reader* arg_r = nullptr;
  BigStr* arg = nullptr;
  syntax_asdl::loc_t* arg_loc = nullptr;
  BigStr* expected = nullptr;
  syntax_asdl::loc_t* e_loc = nullptr;
  value_asdl::value_t* UP_actual = nullptr;
  BigStr* actual = nullptr;
  List<BigStr*>* rest = nullptr;
  StackRoot _root0(&cmd_val);
  StackRoot _root1(&arg_r);
  StackRoot _root2(&arg);
  StackRoot _root3(&arg_loc);
  StackRoot _root4(&expected);
  StackRoot _root5(&e_loc);
  StackRoot _root6(&UP_actual);
  StackRoot _root7(&actual);
  StackRoot _root8(&rest);

  arg_r = Alloc<args::Reader>(cmd_val->argv, cmd_val->arg_locs);
  arg_r->Next();
  Tuple2<BigStr*, syntax_asdl::loc_t*> tup2 = arg_r->Peek2();
  arg = tup2.at0();
  arg_loc = tup2.at1();
  if (arg == nullptr) {
    throw Alloc<error::Usage>(str352, loc::Missing);
  }
  arg_r->Next();
  if (str_equals(arg, str353)) {
    Tuple2<BigStr*, syntax_asdl::loc_t*> tup3 = arg_r->Peek2();
    expected = tup3.at0();
    e_loc = tup3.at1();
    if (expected == nullptr) {
      throw Alloc<error::Usage>(str354, loc::Missing);
    }
    UP_actual = this->mem->GetValue(str355, scope_e::Dynamic);
    if (UP_actual->tag() == value_e::Str) {
      actual = static_cast<value::Str*>(UP_actual)->s;
      if (str_equals(actual, expected)) {
        return 0;
      }
      else {
        this->errfmt->Print_(StrFormat("Expected dialect %r, got %r", expected, actual), e_loc);
        return 1;
      }
    }
    else {
      this->errfmt->Print_(StrFormat("Expected dialect %r", expected), e_loc);
      return 1;
    }
  }
  if (str_equals(arg, str358)) {
    rest = arg_r->Rest();
    for (ListIter<BigStr*> it(rest); !it.Done(); it.Next()) {
      BigStr* name = it.Value();
      StackRoot _for(&name    );
      mylib::print_stderr(StrFormat("bin %s", name));
    }
    return 0;
  }
  throw Alloc<error::Usage>(str360, arg_loc);
}

}  // define namespace module_ysh

namespace printf_osh {  // define

using id_kind_asdl::Id;
using id_kind_asdl::Id_t;
using id_kind_asdl::Id_str;
using id_kind_asdl::Kind;
using id_kind_asdl::Kind_t;
using runtime_asdl::cmd_value;
using syntax_asdl::loc;
using syntax_asdl::loc_e;
using syntax_asdl::loc_t;
using syntax_asdl::source;
using syntax_asdl::Token;
using syntax_asdl::CompoundWord;
using syntax_asdl::printf_part;
using syntax_asdl::printf_part_e;
using syntax_asdl::printf_part_t;
using types_asdl::lex_mode_e;
using types_asdl::lex_mode_t;
using value_asdl::value;
using value_asdl::value_e;
using error::e_die;
using error::p_die;

_FormatStringParser::_FormatStringParser(lexer::Lexer* lexer) {
  this->lexer = lexer;
  this->cur_token = nullptr;
  this->token_type = Id::Undefined_Tok;
  this->token_kind = Kind::Undefined;
}

void _FormatStringParser::_Next(types_asdl::lex_mode_t lex_mode) {
  this->cur_token = this->lexer->Read(lex_mode);
  this->token_type = this->cur_token->id;
  this->token_kind = consts::GetKind(this->token_type);
}

syntax_asdl::printf_part_t* _FormatStringParser::_ParseFormatStr() {
  printf_part::Percent* part = nullptr;
  BigStr* flag = nullptr;
  BigStr* type_val = nullptr;
  StackRoot _root0(&part);
  StackRoot _root1(&flag);
  StackRoot _root2(&type_val);

  this->_Next(lex_mode_e::PrintfPercent);
  part = printf_part::Percent::CreateNull(true);
  while ((this->token_type == Id::Format_Flag || this->token_type == Id::Format_Zero)) {
    flag = lexer::TokenVal(this->cur_token);
    if (str_contains(str361, flag)) {
      p_die(StrFormat("osh printf doesn't support the %r flag", flag), this->cur_token);
    }
    part->flags->append(this->cur_token);
    this->_Next(lex_mode_e::PrintfPercent);
  }
  if ((this->token_type == Id::Format_Num || this->token_type == Id::Format_Star)) {
    part->width = this->cur_token;
    this->_Next(lex_mode_e::PrintfPercent);
  }
  if (this->token_type == Id::Format_Dot) {
    part->precision = this->cur_token;
    this->_Next(lex_mode_e::PrintfPercent);
    if ((this->token_type == Id::Format_Num || this->token_type == Id::Format_Star || this->token_type == Id::Format_Zero)) {
      part->precision = this->cur_token;
      this->_Next(lex_mode_e::PrintfPercent);
    }
  }
  if ((this->token_type == Id::Format_Type || this->token_type == Id::Format_Time)) {
    part->type = this->cur_token;
    type_val = lexer::TokenVal(part->type);
    if (str_contains(str363, type_val)) {
      p_die(str364, part->type);
    }
    if (str_equals(type_val, str365)) {
      p_die(str366, part->type);
    }
  }
  else {
    if (this->token_type == Id::Unknown_Tok) {
      p_die(str367, this->cur_token);
    }
    else {
      p_die(str368, this->cur_token);
    }
  }
  return part;
}

List<syntax_asdl::printf_part_t*>* _FormatStringParser::Parse() {
  List<syntax_asdl::printf_part_t*>* parts = nullptr;
  StackRoot _root0(&parts);

  this->_Next(lex_mode_e::PrintfOuter);
  parts = Alloc<List<syntax_asdl::printf_part_t*>>();
  while (true) {
    if (((this->token_kind == Kind::Lit || this->token_kind == Kind::Char) or (this->token_type == Id::Format_EscapedPercent || this->token_type == Id::Unknown_Backslash))) {
      parts->append(this->cur_token);
    }
    else {
      if (this->token_type == Id::Format_Percent) {
        parts->append(this->_ParseFormatStr());
      }
      else {
        if ((this->token_type == Id::Eof_Real || this->token_type == Id::Eol_Tok)) {
          break;
        }
        else {
          assert(0);  // AssertionError
        }
      }
    }
    this->_Next(lex_mode_e::PrintfOuter);
  }
  return parts;
}

_PrintfState::_PrintfState() {
  this->arg_index = 0;
  this->backslash_c = false;
  this->status = 0;
}

Printf::Printf(state::Mem* mem, parse_lib::ParseContext* parse_ctx, sh_expr_eval::UnsafeArith* unsafe_arith, ui::ErrorFormatter* errfmt) {
  this->mem = mem;
  this->parse_ctx = parse_ctx;
  this->unsafe_arith = unsafe_arith;
  this->errfmt = errfmt;
  this->parse_cache = Alloc<Dict<BigStr*, List<syntax_asdl::printf_part_t*>*>>();
  this->shell_start_time = time_::time();
}

BigStr* Printf::_Percent(printf_osh::_PrintfState* pr, printf_part::Percent* part, List<BigStr*>* varargs, List<syntax_asdl::CompoundWord*>* locs) {
  int num_args;
  List<BigStr*>* flags = nullptr;
  int width;
  BigStr* width_str = nullptr;
  syntax_asdl::loc_t* width_loc = nullptr;
  int precision;
  BigStr* precision_str = nullptr;
  syntax_asdl::loc_t* precision_loc = nullptr;
  BigStr* s = nullptr;
  syntax_asdl::loc_t* word_loc = nullptr;
  bool has_arg;
  BigStr* typ = nullptr;
  List<BigStr*>* c_parts = nullptr;
  match::SimpleLexer* lex = nullptr;
  int id_;
  BigStr* tok_val = nullptr;
  BigStr* p = nullptr;
  mops::BigInt d;
  int num_bytes;
  int small_i;
  syntax_asdl::loc_t* blame_loc = nullptr;
  runtime_asdl::Cell* tzcell = nullptr;
  value::Str* tzval = nullptr;
  double ts;
  int zero_pad;
  bool negative;
  BigStr* digits = nullptr;
  BigStr* sign = nullptr;
  int n;
  StackRoot _root0(&pr);
  StackRoot _root1(&part);
  StackRoot _root2(&varargs);
  StackRoot _root3(&locs);
  StackRoot _root4(&flags);
  StackRoot _root5(&width_str);
  StackRoot _root6(&width_loc);
  StackRoot _root7(&precision_str);
  StackRoot _root8(&precision_loc);
  StackRoot _root9(&s);
  StackRoot _root10(&word_loc);
  StackRoot _root11(&typ);
  StackRoot _root12(&c_parts);
  StackRoot _root13(&lex);
  StackRoot _root14(&tok_val);
  StackRoot _root15(&p);
  StackRoot _root16(&blame_loc);
  StackRoot _root17(&tzcell);
  StackRoot _root18(&tzval);
  StackRoot _root19(&digits);
  StackRoot _root20(&sign);

  num_args = len(varargs);
  flags = Alloc<List<BigStr*>>();
  if (len(part->flags) > 0) {
    for (ListIter<syntax_asdl::Token*> it(part->flags); !it.Done(); it.Next()) {
      syntax_asdl::Token* flag_token = it.Value();
      StackRoot _for(&flag_token    );
      flags->append(lexer::TokenVal(flag_token));
    }
  }
  width = -1;
  if (part->width) {
    if ((part->width->id == Id::Format_Num || part->width->id == Id::Format_Zero)) {
      width_str = lexer::TokenVal(part->width);
      width_loc = part->width;
    }
    else {
      if (part->width->id == Id::Format_Star) {
        if (pr->arg_index < num_args) {
          width_str = varargs->at(pr->arg_index);
          width_loc = locs->at(pr->arg_index);
          pr->arg_index += 1;
        }
        else {
          width_str = str369;
          width_loc = loc::Missing;
        }
      }
      else {
        assert(0);  // AssertionError
      }
    }
    try {
      width = to_int(width_str);
    }
    catch (ValueError*) {
      if (width_loc->tag() == loc_e::Missing) {
        width_loc = part->width;
      }
      this->errfmt->Print_(StrFormat("printf got invalid width %r", width_str), width_loc);
      pr->status = 1;
      return nullptr;
    }
  }
  precision = -1;
  if (part->precision) {
    if (part->precision->id == Id::Format_Dot) {
      precision_str = str371;
      precision_loc = part->precision;
    }
    else {
      if ((part->precision->id == Id::Format_Num || part->precision->id == Id::Format_Zero)) {
        precision_str = lexer::TokenVal(part->precision);
        precision_loc = part->precision;
      }
      else {
        if (part->precision->id == Id::Format_Star) {
          if (pr->arg_index < num_args) {
            precision_str = varargs->at(pr->arg_index);
            precision_loc = locs->at(pr->arg_index);
            pr->arg_index += 1;
          }
          else {
            precision_str = str372;
            precision_loc = loc::Missing;
          }
        }
        else {
          assert(0);  // AssertionError
        }
      }
    }
    try {
      precision = to_int(precision_str);
    }
    catch (ValueError*) {
      if (precision_loc->tag() == loc_e::Missing) {
        precision_loc = part->precision;
      }
      this->errfmt->Print_(StrFormat("printf got invalid precision %r", precision_str), precision_loc);
      pr->status = 1;
      return nullptr;
    }
  }
  if (pr->arg_index < num_args) {
    s = varargs->at(pr->arg_index);
    word_loc = locs->at(pr->arg_index);
    pr->arg_index += 1;
    has_arg = true;
  }
  else {
    s = str374;
    word_loc = loc::Missing;
    has_arg = false;
  }
  typ = lexer::TokenVal(part->type);
  if (str_equals(typ, str375)) {
    if (precision >= 0) {
      s = s->slice(0, precision);
    }
  }
  else {
    if (str_equals(typ, str376)) {
      s = j8_lite::MaybeShellEncode(s);
    }
    else {
      if (str_equals(typ, str377)) {
        c_parts = Alloc<List<BigStr*>>();
        lex = match::EchoLexer(s);
        while (true) {
          Tuple2<int, BigStr*> tup0 = lex->Next();
          id_ = tup0.at0();
          tok_val = tup0.at1();
          if (id_ == Id::Eol_Tok) {
            break;
          }
          p = word_compile::EvalCStringToken(id_, tok_val);
          if (p == nullptr) {
            pr->backslash_c = true;
            break;
          }
          c_parts->append(p);
        }
        s = str378->join(c_parts);
      }
      else {
        if ((part->type->id == Id::Format_Time or str_contains(str379, typ))) {
          if (match::LooksLikeInteger(s)) {
            d = mops::FromStr(s);
          }
          else {
            num_bytes = len(s);
            if ((num_bytes > 0 and str_contains(str380, s->at(0)))) {
              if (num_bytes == 1) {
                d = mops::ZERO;
              }
              else {
                if (num_bytes == 2) {
                  d = mops::IntWiden(ord(s->at(1)));
                }
                else {
                  try {
                    small_i = string_ops::DecodeUtf8Char(s, 1);
                  }
                  catch (error::Expr* e) {
                    this->errfmt->Print_(StrFormat("Warning: %s", e->UserErrorString()), word_loc);
                    small_i = ord(s->at(1));
                  }
                  d = mops::IntWiden(small_i);
                }
              }
            }
            else {
              if ((!has_arg and part->type->id == Id::Format_Time)) {
                d = mops::MINUS_ONE;
              }
              else {
                if (has_arg) {
                  blame_loc = word_loc;
                }
                else {
                  blame_loc = part->type;
                }
                this->errfmt->Print_(StrFormat("printf expected an integer, got %r", s), blame_loc);
                pr->status = 1;
                return nullptr;
              }
            }
          }
          if (part->type->id == Id::Format_Time) {
            tzcell = this->mem->GetCell(str383);
            if ((tzcell and (tzcell->exported and tzcell->val->tag() == value_e::Str))) {
              tzval = static_cast<value::Str*>(tzcell->val);
              posix::putenv(str384, tzval->s);
            }
            time_::tzset();
            if (mops::Equal(d, mops::MINUS_ONE)) {
              ts = time_::time();
            }
            else {
              if (mops::Equal(d, mops::MINUS_TWO)) {
                ts = this->shell_start_time;
              }
              else {
                ts = mops::BigTruncate(d);
              }
            }
            s = time_::strftime(typ->slice(1, -2), time_::localtime(ts));
            if (precision >= 0) {
              s = s->slice(0, precision);
            }
          }
          else {
            if ((mops::Greater(mops::ZERO, d) and str_contains(str385, typ))) {
              e_die(StrFormat("Can't format negative number with %%%s: %d", typ, mops::BigTruncate(d)), part->type);
            }
            if (str_equals(typ, str387)) {
              s = mops::ToOctal(d);
            }
            else {
              if (str_equals(typ, str388)) {
                s = mops::ToHexLower(d);
              }
              else {
                if (str_equals(typ, str389)) {
                  s = mops::ToHexUpper(d);
                }
                else {
                  s = mops::ToStr(d);
                }
              }
            }
            zero_pad = 0;
            if ((width >= 0 and list_contains(flags, str390))) {
              zero_pad = 1;
            }
            else {
              if ((precision > 0 and len(s) < precision)) {
                zero_pad = 2;
              }
            }
            if (zero_pad) {
              negative = str_equals(s->at(0), str391);
              if (negative) {
                digits = s->slice(1);
                sign = str392;
                if (zero_pad == 1) {
                  n = (width - 1);
                }
                else {
                  n = precision;
                }
              }
              else {
                digits = s;
                sign = str393;
                if (zero_pad == 1) {
                  n = width;
                }
                else {
                  n = precision;
                }
              }
              s = str_concat(sign, digits->rjust(n, str394));
            }
          }
        }
        else {
          assert(0);  // AssertionError
        }
      }
    }
  }
  if (width >= 0) {
    if (list_contains(flags, str395)) {
      s = s->ljust(width, str396);
    }
    else {
      s = s->rjust(width, str397);
    }
  }
  return s;
}

int Printf::_Format(List<syntax_asdl::printf_part_t*>* parts, List<BigStr*>* varargs, List<syntax_asdl::CompoundWord*>* locs, List<BigStr*>* out) {
  printf_osh::_PrintfState* pr = nullptr;
  int num_args;
  syntax_asdl::printf_part_t* UP_part = nullptr;
  BigStr* s = nullptr;
  StackRoot _root0(&parts);
  StackRoot _root1(&varargs);
  StackRoot _root2(&locs);
  StackRoot _root3(&out);
  StackRoot _root4(&pr);
  StackRoot _root5(&UP_part);
  StackRoot _root6(&s);

  pr = Alloc<_PrintfState>();
  num_args = len(varargs);
  while (true) {
    for (ListIter<syntax_asdl::printf_part_t*> it(parts); !it.Done(); it.Next()) {
      syntax_asdl::printf_part_t* part = it.Value();
      StackRoot _for(&part    );
      UP_part = part;
      if (part->tag() == printf_part_e::Literal) {
        Token* part = static_cast<Token*>(UP_part);
        if (part->id == Id::Format_EscapedPercent) {
          s = str398;
        }
        else {
          s = word_compile::EvalCStringToken(part->id, lexer::LazyStr(part));
        }
      }
      else {
        if (part->tag() == printf_part_e::Percent) {
          printf_part::Percent* part = static_cast<printf_part::Percent*>(UP_part);
          s = this->_Percent(pr, part, varargs, locs);
          if (pr->status != 0) {
            return pr->status;
          }
        }
        else {
          assert(0);  // AssertionError
        }
      }
      out->append(s);
      if (pr->backslash_c) {
        break;
      }
    }
    if (pr->arg_index == 0) {
      break;
    }
    if (pr->arg_index >= num_args) {
      break;
    }
  }
  return 0;
}

int Printf::Run(cmd_value::Argv* cmd_val) {
  args::_Attributes* attrs = nullptr;
  args::Reader* arg_r = nullptr;
  arg_types::printf* arg = nullptr;
  BigStr* fmt = nullptr;
  syntax_asdl::loc_t* fmt_loc = nullptr;
  List<BigStr*>* varargs = nullptr;
  List<syntax_asdl::CompoundWord*>* locs = nullptr;
  alloc::Arena* arena = nullptr;
  List<syntax_asdl::printf_part_t*>* parts = nullptr;
  reader::FileLineReader* line_reader = nullptr;
  lexer::Lexer* lexer = nullptr;
  printf_osh::_FormatStringParser* parser = nullptr;
  List<BigStr*>* out = nullptr;
  int status;
  BigStr* result = nullptr;
  syntax_asdl::loc__Missing* v_loc = nullptr;
  value_asdl::sh_lvalue_t* lval = nullptr;
  StackRoot _root0(&cmd_val);
  StackRoot _root1(&attrs);
  StackRoot _root2(&arg_r);
  StackRoot _root3(&arg);
  StackRoot _root4(&fmt);
  StackRoot _root5(&fmt_loc);
  StackRoot _root6(&varargs);
  StackRoot _root7(&locs);
  StackRoot _root8(&arena);
  StackRoot _root9(&parts);
  StackRoot _root10(&line_reader);
  StackRoot _root11(&lexer);
  StackRoot _root12(&parser);
  StackRoot _root13(&out);
  StackRoot _root14(&result);
  StackRoot _root15(&v_loc);
  StackRoot _root16(&lval);

  Tuple2<args::_Attributes*, args::Reader*> tup1 = flag_util::ParseCmdVal(str399, cmd_val);
  attrs = tup1.at0();
  arg_r = tup1.at1();
  arg = Alloc<arg_types::printf>(attrs->attrs);
  Tuple2<BigStr*, syntax_asdl::loc_t*> tup2 = arg_r->ReadRequired2(str400);
  fmt = tup2.at0();
  fmt_loc = tup2.at1();
  Tuple2<List<BigStr*>*, List<syntax_asdl::CompoundWord*>*> tup3 = arg_r->Rest2();
  varargs = tup3.at0();
  locs = tup3.at1();
  arena = this->parse_ctx->arena;
  if (dict_contains(this->parse_cache, fmt)) {
    parts = this->parse_cache->at(fmt);
  }
  else {
    line_reader = reader::StringLineReader(fmt, arena);
    lexer = this->parse_ctx->MakeLexer(line_reader);
    parser = Alloc<_FormatStringParser>(lexer);
    {  // with
      alloc::ctx_SourceCode ctx{arena, Alloc<source::ArgvWord>(str401, fmt_loc)};

      try {
        parts = parser->Parse();
      }
      catch (error::Parse* e) {
        this->errfmt->PrettyPrintError(e);
        return 2;
      }
    }
    this->parse_cache->set(fmt, parts);
  }
  out = Alloc<List<BigStr*>>();
  status = this->_Format(parts, varargs, locs, out);
  if (status != 0) {
    return status;
  }
  result = str402->join(out);
  if (arg->v != nullptr) {
    v_loc = loc::Missing;
    lval = this->unsafe_arith->ParseLValue(arg->v, v_loc);
    state::BuiltinSetValue(this->mem, lval, Alloc<value::Str>(result));
  }
  else {
    mylib::Stdout()->write(result);
  }
  return 0;
}

}  // define namespace printf_osh

namespace process_osh {  // define

using syntax_asdl::loc;
using runtime_asdl::cmd_value;
using runtime_asdl::job_state_e;
using runtime_asdl::wait_status;
using runtime_asdl::wait_status_e;
using error::e_usage;
using error::e_die_status;
using mylib::print_stderr;

Jobs::Jobs(process::JobList* job_list) {
  this->job_list = job_list;
}

int Jobs::Run(cmd_value::Argv* cmd_val) {
  args::_Attributes* attrs = nullptr;
  args::Reader* arg_r = nullptr;
  arg_types::jobs* arg = nullptr;
  int style;
  StackRoot _root0(&cmd_val);
  StackRoot _root1(&attrs);
  StackRoot _root2(&arg_r);
  StackRoot _root3(&arg);

  Tuple2<args::_Attributes*, args::Reader*> tup0 = flag_util::ParseCmdVal(str403, cmd_val);
  attrs = tup0.at0();
  arg_r = tup0.at1();
  arg = Alloc<arg_types::jobs>(attrs->attrs);
  if (arg->l) {
    style = process::STYLE_LONG;
  }
  else {
    if (arg->p) {
      style = process::STYLE_PID_ONLY;
    }
    else {
      style = process::STYLE_DEFAULT;
    }
  }
  this->job_list->DisplayJobs(style);
  if (arg->debug) {
    this->job_list->DebugPrint();
  }
  return 0;
}

Fg::Fg(process::JobControl* job_control, process::JobList* job_list, process::Waiter* waiter) {
  this->job_control = job_control;
  this->job_list = job_list;
  this->waiter = waiter;
}

int Fg::Run(cmd_value::Argv* cmd_val) {
  BigStr* job_spec = nullptr;
  process::Job* job = nullptr;
  int pgid;
  int status;
  runtime_asdl::wait_status_t* wait_st = nullptr;
  runtime_asdl::wait_status_t* UP_wait_st = nullptr;
  StackRoot _root0(&cmd_val);
  StackRoot _root1(&job_spec);
  StackRoot _root2(&job);
  StackRoot _root3(&wait_st);
  StackRoot _root4(&UP_wait_st);

  job_spec = str404;
  if (len(cmd_val->argv) > 1) {
    job_spec = cmd_val->argv->at(1);
  }
  job = this->job_list->GetJobWithSpec(job_spec);
  if (job == nullptr) {
    mylib::print_stderr(str405);
    return 1;
  }
  pgid = job->ProcessGroupId();
  mylib::print_stderr(StrFormat("Continue PID %d", pgid));
  this->job_control->MaybeGiveTerminal(pgid);
  job->SetForeground();
  job->state = job_state_e::Running;
  posix::killpg(pgid, SIGCONT);
  status = -1;
  wait_st = job->JobWait(this->waiter);
  UP_wait_st = wait_st;
  switch (wait_st->tag()) {
    case wait_status_e::Proc: {
      wait_status::Proc* wait_st = static_cast<wait_status::Proc*>(UP_wait_st);
      status = wait_st->code;
    }
      break;
    case wait_status_e::Pipeline: {
      wait_status::Pipeline* wait_st = static_cast<wait_status::Pipeline*>(UP_wait_st);
      status = wait_st->codes->at(-1);
    }
      break;
    case wait_status_e::Cancelled: {
      wait_status::Cancelled* wait_st = static_cast<wait_status::Cancelled*>(UP_wait_st);
      status = (128 + wait_st->sig_num);
    }
      break;
    default: {
      assert(0);  // AssertionError
    }
  }
  return status;
}

Bg::Bg(process::JobList* job_list) {
  this->job_list = job_list;
}

int Bg::Run(cmd_value::Argv* cmd_val) {
  StackRoot _root0(&cmd_val);

  throw Alloc<error::Usage>(str407, loc::Missing);
}

Fork::Fork(vm::_Executor* shell_ex) {
  this->shell_ex = shell_ex;
}

int Fork::Run(cmd_value::Argv* cmd_val) {
  args::Reader* arg_r = nullptr;
  BigStr* arg = nullptr;
  syntax_asdl::loc_t* location = nullptr;
  syntax_asdl::command_t* cmd = nullptr;
  StackRoot _root0(&cmd_val);
  StackRoot _root1(&arg_r);
  StackRoot _root2(&arg);
  StackRoot _root3(&location);
  StackRoot _root4(&cmd);

  Tuple2<args::_Attributes*, args::Reader*> tup1 = flag_util::ParseCmdVal(str408, cmd_val, true);
  arg_r = tup1.at1();
  Tuple2<BigStr*, syntax_asdl::loc_t*> tup2 = arg_r->Peek2();
  arg = tup2.at0();
  location = tup2.at1();
  if (arg != nullptr) {
    e_usage(StrFormat("got unexpected argument %r", arg), location);
  }
  cmd = typed_args::OptionalBlock(cmd_val);
  if (cmd == nullptr) {
    e_usage(str410, loc::Missing);
  }
  return this->shell_ex->RunBackgroundJob(cmd);
}

ForkWait::ForkWait(vm::_Executor* shell_ex) {
  this->shell_ex = shell_ex;
}

int ForkWait::Run(cmd_value::Argv* cmd_val) {
  args::Reader* arg_r = nullptr;
  BigStr* arg = nullptr;
  syntax_asdl::loc_t* location = nullptr;
  syntax_asdl::command_t* cmd = nullptr;
  StackRoot _root0(&cmd_val);
  StackRoot _root1(&arg_r);
  StackRoot _root2(&arg);
  StackRoot _root3(&location);
  StackRoot _root4(&cmd);

  Tuple2<args::_Attributes*, args::Reader*> tup3 = flag_util::ParseCmdVal(str411, cmd_val, true);
  arg_r = tup3.at1();
  Tuple2<BigStr*, syntax_asdl::loc_t*> tup4 = arg_r->Peek2();
  arg = tup4.at0();
  location = tup4.at1();
  if (arg != nullptr) {
    e_usage(StrFormat("got unexpected argument %r", arg), location);
  }
  cmd = typed_args::OptionalBlock(cmd_val);
  if (cmd == nullptr) {
    e_usage(str413, loc::Missing);
  }
  return this->shell_ex->RunSubshell(cmd);
}

Exec::Exec(state::Mem* mem, process::ExternalProgram* ext_prog, process::FdState* fd_state, state::SearchPath* search_path, ui::ErrorFormatter* errfmt) {
  this->mem = mem;
  this->ext_prog = ext_prog;
  this->fd_state = fd_state;
  this->search_path = search_path;
  this->errfmt = errfmt;
}

int Exec::Run(cmd_value::Argv* cmd_val) {
  args::Reader* arg_r = nullptr;
  Dict<BigStr*, BigStr*>* environ = nullptr;
  int i;
  BigStr* cmd = nullptr;
  BigStr* argv0_path = nullptr;
  cmd_value::Argv* c2 = nullptr;
  StackRoot _root0(&cmd_val);
  StackRoot _root1(&arg_r);
  StackRoot _root2(&environ);
  StackRoot _root3(&cmd);
  StackRoot _root4(&argv0_path);
  StackRoot _root5(&c2);

  Tuple2<args::_Attributes*, args::Reader*> tup5 = flag_util::ParseCmdVal(str414, cmd_val);
  arg_r = tup5.at1();
  if (arg_r->AtEnd()) {
    this->fd_state->MakePermanent();
    return 0;
  }
  environ = this->mem->GetExported();
  i = arg_r->i;
  cmd = cmd_val->argv->at(i);
  argv0_path = this->search_path->CachedLookup(cmd);
  if (argv0_path == nullptr) {
    e_die_status(127, StrFormat("exec: %r not found", cmd), cmd_val->arg_locs->at(1));
  }
  c2 = Alloc<cmd_value::Argv>(cmd_val->argv->slice(i), cmd_val->arg_locs->slice(i), nullptr, nullptr, nullptr, nullptr);
  this->ext_prog->Exec(argv0_path, c2, environ);
  assert(0);  // AssertionError
}

Wait::Wait(process::Waiter* waiter, process::JobList* job_list, state::Mem* mem, dev::Tracer* tracer, ui::ErrorFormatter* errfmt) {
  this->waiter = waiter;
  this->job_list = job_list;
  this->mem = mem;
  this->tracer = tracer;
  this->errfmt = errfmt;
}

int Wait::Run(cmd_value::Argv* cmd_val) {
  StackRoot _root0(&cmd_val);

  {  // with
    dev::ctx_Tracer ctx{this->tracer, str417, cmd_val->argv};

    return this->_Run(cmd_val);
  }
}

int Wait::_Run(cmd_value::Argv* cmd_val) {
  args::_Attributes* attrs = nullptr;
  args::Reader* arg_r = nullptr;
  arg_types::wait* arg = nullptr;
  List<BigStr*>* job_ids = nullptr;
  List<syntax_asdl::CompoundWord*>* arg_locs = nullptr;
  int n;
  int status;
  int target;
  int result;
  List<process::Job*>* jobs = nullptr;
  int i;
  syntax_asdl::CompoundWord* location = nullptr;
  process::Job* job = nullptr;
  int pid;
  runtime_asdl::wait_status_t* wait_st = nullptr;
  runtime_asdl::wait_status_t* UP_wait_st = nullptr;
  StackRoot _root0(&cmd_val);
  StackRoot _root1(&attrs);
  StackRoot _root2(&arg_r);
  StackRoot _root3(&arg);
  StackRoot _root4(&job_ids);
  StackRoot _root5(&arg_locs);
  StackRoot _root6(&jobs);
  StackRoot _root7(&location);
  StackRoot _root8(&job);
  StackRoot _root9(&wait_st);
  StackRoot _root10(&UP_wait_st);

  Tuple2<args::_Attributes*, args::Reader*> tup6 = flag_util::ParseCmdVal(str418, cmd_val);
  attrs = tup6.at0();
  arg_r = tup6.at1();
  arg = Alloc<arg_types::wait>(attrs->attrs);
  Tuple2<List<BigStr*>*, List<syntax_asdl::CompoundWord*>*> tup7 = arg_r->Rest2();
  job_ids = tup7.at0();
  arg_locs = tup7.at1();
  if (arg->n) {
    n = this->job_list->NumRunning();
    if (n == 0) {
      status = 127;
    }
    else {
      target = (n - 1);
      status = 0;
      while (this->job_list->NumRunning() > target) {
        result = this->waiter->WaitForOne();
        if (result == process::W1_OK) {
          status = this->waiter->last_status;
        }
        else {
          if (result == process::W1_ECHILD) {
            status = 127;
            break;
          }
          else {
            if (result >= 0) {
              status = (128 + result);
              break;
            }
          }
        }
      }
    }
    return status;
  }
  if (len(job_ids) == 0) {
    status = 0;
    while (this->job_list->NumRunning() != 0) {
      result = this->waiter->WaitForOne();
      if (result == process::W1_ECHILD) {
        break;
      }
      else {
        if (result >= 0) {
          status = (128 + result);
          break;
        }
      }
    }
    return status;
  }
  jobs = Alloc<List<process::Job*>>();
  i = 0;
  for (ListIter<BigStr*> it(job_ids); !it.Done(); it.Next(), ++i) {
    BigStr* job_id = it.Value();
    StackRoot _for(&job_id  );
    location = arg_locs->at(i);
    job = nullptr;
    if ((str_equals(job_id, str419) or job_id->startswith(str420))) {
      job = this->job_list->GetJobWithSpec(job_id);
    }
    if (job == nullptr) {
      try {
        pid = to_int(job_id);
      }
      catch (ValueError*) {
        throw Alloc<error::Usage>(StrFormat("expected PID or jobspec, got %r", job_id), location);
      }
      job = this->job_list->ProcessFromPid(pid);
    }
    if (job == nullptr) {
      this->errfmt->Print_(StrFormat("%s isn't a child of this shell", job_id), location);
      return 127;
    }
    jobs->append(job);
  }
  status = 1;
  for (ListIter<process::Job*> it(jobs); !it.Done(); it.Next()) {
    process::Job* job = it.Value();
    StackRoot _for(&job  );
    wait_st = job->JobWait(this->waiter);
    UP_wait_st = wait_st;
    switch (wait_st->tag()) {
      case wait_status_e::Proc: {
        wait_status::Proc* wait_st = static_cast<wait_status::Proc*>(UP_wait_st);
        status = wait_st->code;
      }
        break;
      case wait_status_e::Pipeline: {
        wait_status::Pipeline* wait_st = static_cast<wait_status::Pipeline*>(UP_wait_st);
        status = wait_st->codes->at(-1);
      }
        break;
      case wait_status_e::Cancelled: {
        wait_status::Cancelled* wait_st = static_cast<wait_status::Cancelled*>(UP_wait_st);
        status = (128 + wait_st->sig_num);
      }
        break;
      default: {
        assert(0);  // AssertionError
      }
    }
  }
  return status;
}

Umask::Umask() {
  ;  // pass
}

int Umask::Run(cmd_value::Argv* cmd_val) {
  List<BigStr*>* argv = nullptr;
  int mask;
  BigStr* a = nullptr;
  int new_mask;
  StackRoot _root0(&cmd_val);
  StackRoot _root1(&argv);
  StackRoot _root2(&a);

  argv = cmd_val->argv->slice(1);
  if (len(argv) == 0) {
    mask = posix::umask(0);
    posix::umask(mask);
    print(StrFormat("0%03o", mask));
    return 0;
  }
  if (len(argv) == 1) {
    a = argv->at(0);
    try {
      new_mask = to_int(a, 8);
    }
    catch (ValueError*) {
      print_stderr(str424);
      return 1;
    }
    posix::umask(new_mask);
    return 0;
  }
  e_usage(str425, loc::Missing);
}

BigStr* _LimitString(mops::BigInt lim, int factor) {
  mops::BigInt i;
  if (mops::Equal(lim, mops::FromC(RLIM_INFINITY))) {
    return str426;
  }
  else {
    i = mops::Div(lim, mops::IntWiden(factor));
    return mops::ToStr(i);
  }
}

Ulimit::Ulimit() {
  this->_table = nullptr;
}

List<Tuple4<BigStr*, int, int, BigStr*>*>* Ulimit::_Table() {
  if (this->_table == nullptr) {
    this->_table = NewList<Tuple4<BigStr*, int, int, BigStr*>*>(std::initializer_list<Tuple4<BigStr*, int, int, BigStr*>*>{(Alloc<Tuple4<BigStr*, int, int, BigStr*>>(str427, RLIMIT_CORE, 512, str428)), (Alloc<Tuple4<BigStr*, int, int, BigStr*>>(str429, RLIMIT_DATA, 1024, str430)), (Alloc<Tuple4<BigStr*, int, int, BigStr*>>(str431, RLIMIT_FSIZE, 512, str432)), (Alloc<Tuple4<BigStr*, int, int, BigStr*>>(str433, RLIMIT_NOFILE, 1, str434)), (Alloc<Tuple4<BigStr*, int, int, BigStr*>>(str435, RLIMIT_STACK, 1024, str436)), (Alloc<Tuple4<BigStr*, int, int, BigStr*>>(str437, RLIMIT_CPU, 1, str438)), (Alloc<Tuple4<BigStr*, int, int, BigStr*>>(str439, RLIMIT_AS, 1024, str440))});
  }
  return this->_table;
}

int Ulimit::_FindFactor(int what) {
  int w;
  int factor;
  for (ListIter<Tuple4<BigStr*, int, int, BigStr*>*> it(this->_Table()); !it.Done(); it.Next()) {
    Tuple4<BigStr*, int, int, BigStr*>* tup8 = it.Value();
    w = tup8->at1();
    factor = tup8->at2();
    if (w == what) {
      return factor;
    }
  }
  assert(0);  // AssertionError
}

int Ulimit::Run(cmd_value::Argv* cmd_val) {
  args::_Attributes* attrs = nullptr;
  args::Reader* arg_r = nullptr;
  arg_types::ulimit* arg = nullptr;
  int what;
  int num_what_flags;
  bool show_all;
  BigStr* extra = nullptr;
  syntax_asdl::loc_t* extra_loc = nullptr;
  BigStr* fmt = nullptr;
  BigStr* flag = nullptr;
  int factor;
  BigStr* desc = nullptr;
  mops::BigInt soft;
  mops::BigInt hard;
  BigStr* soft2 = nullptr;
  BigStr* hard2 = nullptr;
  BigStr* s = nullptr;
  syntax_asdl::loc_t* s_loc = nullptr;
  mops::BigInt limit;
  mops::BigInt big_int;
  mops::BigInt fac;
  BigStr* extra2 = nullptr;
  syntax_asdl::loc_t* extra_loc2 = nullptr;
  mops::BigInt old_soft;
  mops::BigInt old_hard;
  StackRoot _root0(&cmd_val);
  StackRoot _root1(&attrs);
  StackRoot _root2(&arg_r);
  StackRoot _root3(&arg);
  StackRoot _root4(&extra);
  StackRoot _root5(&extra_loc);
  StackRoot _root6(&fmt);
  StackRoot _root7(&flag);
  StackRoot _root8(&desc);
  StackRoot _root9(&soft2);
  StackRoot _root10(&hard2);
  StackRoot _root11(&s);
  StackRoot _root12(&s_loc);
  StackRoot _root13(&extra2);
  StackRoot _root14(&extra_loc2);

  Tuple2<args::_Attributes*, args::Reader*> tup9 = flag_util::ParseCmdVal(str441, cmd_val);
  attrs = tup9.at0();
  arg_r = tup9.at1();
  arg = Alloc<arg_types::ulimit>(attrs->attrs);
  what = 0;
  num_what_flags = 0;
  if (arg->c) {
    what = RLIMIT_CORE;
    num_what_flags += 1;
  }
  if (arg->d) {
    what = RLIMIT_DATA;
    num_what_flags += 1;
  }
  if (arg->f) {
    what = RLIMIT_FSIZE;
    num_what_flags += 1;
  }
  if (arg->n) {
    what = RLIMIT_NOFILE;
    num_what_flags += 1;
  }
  if (arg->s) {
    what = RLIMIT_STACK;
    num_what_flags += 1;
  }
  if (arg->t) {
    what = RLIMIT_CPU;
    num_what_flags += 1;
  }
  if (arg->v) {
    what = RLIMIT_AS;
    num_what_flags += 1;
  }
  if (num_what_flags > 1) {
    throw Alloc<error::Usage>(str442, cmd_val->arg_locs->at(0));
  }
  show_all = (arg->a or arg->all);
  if (show_all) {
    if (num_what_flags > 0) {
      throw Alloc<error::Usage>(str443, cmd_val->arg_locs->at(0));
    }
    Tuple2<BigStr*, syntax_asdl::loc_t*> tup10 = arg_r->Peek2();
    extra = tup10.at0();
    extra_loc = tup10.at1();
    if (extra != nullptr) {
      throw Alloc<error::Usage>(str444, extra_loc);
    }
    fmt = str445;
    print(StrFormat(fmt, str446, str447, str448, str449, str450));
    for (ListIter<Tuple4<BigStr*, int, int, BigStr*>*> it(this->_Table()); !it.Done(); it.Next()) {
      Tuple4<BigStr*, int, int, BigStr*>* tup11 = it.Value();
      flag = tup11->at0();
      what = tup11->at1();
      factor = tup11->at2();
      desc = tup11->at3();
      Tuple2<mops::BigInt, mops::BigInt> tup12 = pyos::GetRLimit(what);
      soft = tup12.at0();
      hard = tup12.at1();
      soft2 = _LimitString(soft, factor);
      hard2 = _LimitString(hard, factor);
      print(StrFormat(fmt, flag, soft2, hard2, str(factor), desc));
    }
    return 0;
  }
  if (num_what_flags == 0) {
    what = RLIMIT_FSIZE;
  }
  Tuple2<BigStr*, syntax_asdl::loc_t*> tup13 = arg_r->Peek2();
  s = tup13.at0();
  s_loc = tup13.at1();
  if (s == nullptr) {
    factor = this->_FindFactor(what);
    Tuple2<mops::BigInt, mops::BigInt> tup14 = pyos::GetRLimit(what);
    soft = tup14.at0();
    hard = tup14.at1();
    if (arg->H) {
      print(_LimitString(hard, factor));
    }
    else {
      print(_LimitString(soft, factor));
    }
    return 0;
  }
  if (str_equals(s, str451)) {
    limit = mops::FromC(RLIM_INFINITY);
  }
  else {
    try {
      big_int = mops::FromStr(s);
    }
    catch (ValueError* e) {
      throw Alloc<error::Usage>(StrFormat("expected a number or 'unlimited', got %r", s), s_loc);
    }
    if (mops::Greater(mops::IntWiden(0), big_int)) {
      throw Alloc<error::Usage>(StrFormat("doesn't accept negative numbers, got %r", s), s_loc);
    }
    factor = this->_FindFactor(what);
    fac = mops::IntWiden(factor);
    limit = mops::Mul(big_int, fac);
    if (!mops::Equal(mops::Div(limit, fac), big_int)) {
      throw Alloc<error::Usage>(StrFormat("detected integer overflow: %s", mops::ToStr(big_int)), s_loc);
    }
  }
  arg_r->Next();
  Tuple2<BigStr*, syntax_asdl::loc_t*> tup15 = arg_r->Peek2();
  extra2 = tup15.at0();
  extra_loc2 = tup15.at1();
  if (extra2 != nullptr) {
    throw Alloc<error::Usage>(str455, extra_loc2);
  }
  Tuple2<mops::BigInt, mops::BigInt> tup16 = pyos::GetRLimit(what);
  soft = tup16.at0();
  hard = tup16.at1();
  old_soft = soft;
  old_hard = hard;
  if ((!arg->S and !arg->H)) {
    soft = limit;
    hard = limit;
  }
  if (arg->S) {
    soft = limit;
  }
  if (arg->H) {
    hard = limit;
  }
  // if not PYTHON
  {
    try {
      pyos::SetRLimit(what, soft, hard);
    }
    catch (IOError_OSError* e) {
      print_stderr(StrFormat("ulimit error: %s", pyutil::strerror(e)));
      return 1;
    }
  }
  // endif MYCPP
  return 0;
}

}  // define namespace process_osh

namespace pure_osh {  // define

using syntax_asdl::loc;
using types_asdl::opt_group_i;
using error::e_usage;
using mylib::print_stderr;

Boolean::Boolean(int status) {
  this->status = status;
}

int Boolean::Run(cmd_value::Argv* cmd_val) {
  StackRoot _root0(&cmd_val);

  typed_args::DoesNotAccept(cmd_val->typed_args);
  return this->status;
}

Alias::Alias(Dict<BigStr*, BigStr*>* aliases, ui::ErrorFormatter* errfmt) {
  this->aliases = aliases;
  this->errfmt = errfmt;
}

int Alias::Run(cmd_value::Argv* cmd_val) {
  args::Reader* arg_r = nullptr;
  List<BigStr*>* argv = nullptr;
  BigStr* alias_exp = nullptr;
  int status;
  int i;
  BigStr* name = nullptr;
  StackRoot _root0(&cmd_val);
  StackRoot _root1(&arg_r);
  StackRoot _root2(&argv);
  StackRoot _root3(&alias_exp);
  StackRoot _root4(&name);

  Tuple2<args::_Attributes*, args::Reader*> tup0 = flag_util::ParseCmdVal(str457, cmd_val);
  arg_r = tup0.at1();
  argv = arg_r->Rest();
  if (len(argv) == 0) {
    for (ListIter<BigStr*> it(sorted(this->aliases)); !it.Done(); it.Next()) {
      BigStr* name = it.Value();
      StackRoot _for(&name    );
      alias_exp = this->aliases->at(name);
      print(StrFormat("alias %s=%r", name, alias_exp));
    }
    return 0;
  }
  status = 0;
  i = 0;
  for (ListIter<BigStr*> it(argv); !it.Done(); it.Next(), ++i) {
    BigStr* arg = it.Value();
    StackRoot _for(&arg  );
    Tuple2<BigStr*, BigStr*> tup1 = mylib::split_once(arg, str459);
    name = tup1.at0();
    alias_exp = tup1.at1();
    if (alias_exp == nullptr) {
      alias_exp = this->aliases->get(name);
      if (alias_exp == nullptr) {
        this->errfmt->Print_(StrFormat("No alias named %r", name), cmd_val->arg_locs->at(i));
        status = 1;
      }
      else {
        print(StrFormat("alias %s=%r", name, alias_exp));
      }
    }
    else {
      this->aliases->set(name, alias_exp);
    }
  }
  return status;
}

UnAlias::UnAlias(Dict<BigStr*, BigStr*>* aliases, ui::ErrorFormatter* errfmt) {
  this->aliases = aliases;
  this->errfmt = errfmt;
}

int UnAlias::Run(cmd_value::Argv* cmd_val) {
  args::_Attributes* attrs = nullptr;
  args::Reader* arg_r = nullptr;
  arg_types::unalias* arg = nullptr;
  List<BigStr*>* argv = nullptr;
  int status;
  int i;
  StackRoot _root0(&cmd_val);
  StackRoot _root1(&attrs);
  StackRoot _root2(&arg_r);
  StackRoot _root3(&arg);
  StackRoot _root4(&argv);

  Tuple2<args::_Attributes*, args::Reader*> tup2 = flag_util::ParseCmdVal(str462, cmd_val);
  attrs = tup2.at0();
  arg_r = tup2.at1();
  arg = Alloc<arg_types::unalias>(attrs->attrs);
  if (arg->a) {
    this->aliases->clear();
    return 0;
  }
  argv = arg_r->Rest();
  if (len(argv) == 0) {
    e_usage(str463, loc::Missing);
  }
  status = 0;
  i = 0;
  for (ListIter<BigStr*> it(argv); !it.Done(); it.Next(), ++i) {
    BigStr* name = it.Value();
    StackRoot _for(&name  );
    if (dict_contains(this->aliases, name)) {
      mylib::dict_erase(this->aliases, name);
    }
    else {
      this->errfmt->Print_(StrFormat("No alias named %r", name), cmd_val->arg_locs->at(i));
      status = 1;
    }
  }
  return status;
}

void SetOptionsFromFlags(state::MutableOpts* exec_opts, List<Tuple2<BigStr*, bool>*>* opt_changes, List<Tuple2<BigStr*, bool>*>* shopt_changes) {
  BigStr* opt_name = nullptr;
  bool b;
  StackRoot _root0(&exec_opts);
  StackRoot _root1(&opt_changes);
  StackRoot _root2(&shopt_changes);
  StackRoot _root3(&opt_name);

  for (ListIter<Tuple2<BigStr*, bool>*> it(opt_changes); !it.Done(); it.Next()) {
    Tuple2<BigStr*, bool>* tup3 = it.Value();
    opt_name = tup3->at0();
    b = tup3->at1();
    exec_opts->SetAnyOption(opt_name, b);
  }
  for (ListIter<Tuple2<BigStr*, bool>*> it(shopt_changes); !it.Done(); it.Next()) {
    Tuple2<BigStr*, bool>* tup4 = it.Value();
    opt_name = tup4->at0();
    b = tup4->at1();
    exec_opts->SetAnyOption(opt_name, b);
  }
}

Set::Set(state::MutableOpts* exec_opts, state::Mem* mem) {
  this->exec_opts = exec_opts;
  this->mem = mem;
}

int Set::Run(cmd_value::Argv* cmd_val) {
  Dict<BigStr*, BigStr*>* mapping = nullptr;
  BigStr* str_val = nullptr;
  BigStr* code_str = nullptr;
  args::Reader* arg_r = nullptr;
  args::_Attributes* arg = nullptr;
  BigStr* opt_name = nullptr;
  bool b;
  StackRoot _root0(&cmd_val);
  StackRoot _root1(&mapping);
  StackRoot _root2(&str_val);
  StackRoot _root3(&code_str);
  StackRoot _root4(&arg_r);
  StackRoot _root5(&arg);
  StackRoot _root6(&opt_name);

  if (len(cmd_val->argv) == 1) {
    mapping = this->mem->GetAllVars();
    for (ListIter<BigStr*> it(sorted(mapping)); !it.Done(); it.Next()) {
      BigStr* name = it.Value();
      StackRoot _for(&name    );
      str_val = mapping->at(name);
      code_str = StrFormat("%s=%s", name, j8_lite::MaybeShellEncode(str_val));
      print(code_str);
    }
    return 0;
  }
  arg_r = Alloc<args::Reader>(cmd_val->argv, cmd_val->arg_locs);
  arg_r->Next();
  arg = flag_util::ParseMore(str466, arg_r);
  if (arg->show_options) {
    this->exec_opts->ShowOptions(Alloc<List<BigStr*>>());
    return 0;
  }
  for (ListIter<Tuple2<BigStr*, bool>*> it(arg->opt_changes); !it.Done(); it.Next()) {
    Tuple2<BigStr*, bool>* tup5 = it.Value();
    opt_name = tup5->at0();
    b = tup5->at1();
    this->exec_opts->SetOldOption(opt_name, b);
  }
  for (ListIter<Tuple2<BigStr*, bool>*> it(arg->shopt_changes); !it.Done(); it.Next()) {
    Tuple2<BigStr*, bool>* tup6 = it.Value();
    opt_name = tup6->at0();
    b = tup6->at1();
    this->exec_opts->SetAnyOption(opt_name, b);
  }
  if ((arg->saw_double_dash or !arg_r->AtEnd())) {
    this->mem->SetArgv(arg_r->Rest());
  }
  return 0;
}

Shopt::Shopt(state::MutableOpts* mutable_opts, cmd_eval::CommandEvaluator* cmd_ev) {
  this->mutable_opts = mutable_opts;
  this->cmd_ev = cmd_ev;
}

void Shopt::_PrintOptions(bool use_set_opts, List<BigStr*>* opt_names) {
  StackRoot _root0(&opt_names);

  if (use_set_opts) {
    this->mutable_opts->ShowOptions(opt_names);
  }
  else {
    this->mutable_opts->ShowShoptOptions(opt_names);
  }
}

int Shopt::Run(cmd_value::Argv* cmd_val) {
  args::_Attributes* attrs = nullptr;
  args::Reader* arg_r = nullptr;
  arg_types::shopt* arg = nullptr;
  List<BigStr*>* opt_names = nullptr;
  int index;
  bool b;
  syntax_asdl::command_t* cmd = nullptr;
  List<int>* opt_nums = nullptr;
  int opt_group;
  int unused;
  StackRoot _root0(&cmd_val);
  StackRoot _root1(&attrs);
  StackRoot _root2(&arg_r);
  StackRoot _root3(&arg);
  StackRoot _root4(&opt_names);
  StackRoot _root5(&cmd);
  StackRoot _root6(&opt_nums);

  Tuple2<args::_Attributes*, args::Reader*> tup7 = flag_util::ParseCmdVal(str467, cmd_val, true);
  attrs = tup7.at0();
  arg_r = tup7.at1();
  arg = Alloc<arg_types::shopt>(attrs->attrs);
  opt_names = arg_r->Rest();
  if (arg->q) {
    for (ListIter<BigStr*> it(opt_names); !it.Done(); it.Next()) {
      BigStr* name = it.Value();
      StackRoot _for(&name    );
      index = consts::OptionNum(name);
      if (index == 0) {
        return 2;
      }
      if (!this->mutable_opts->opt0_array->at(index)) {
        return 1;
      }
    }
    return 0;
  }
  if (arg->s) {
    b = true;
  }
  else {
    if (arg->u) {
      b = false;
    }
    else {
      if (arg->p) {
        this->_PrintOptions(arg->o, opt_names);
        return 0;
      }
      else {
        this->_PrintOptions(arg->o, opt_names);
        return 0;
      }
    }
  }
  cmd = typed_args::OptionalBlock(cmd_val);
  if (cmd) {
    opt_nums = Alloc<List<int>>();
    for (ListIter<BigStr*> it(opt_names); !it.Done(); it.Next()) {
      BigStr* opt_name = it.Value();
      StackRoot _for(&opt_name    );
      opt_group = consts::OptionGroupNum(opt_name);
      if (opt_group == opt_group_i::YshUpgrade) {
        opt_nums->extend(consts::YSH_UPGRADE);
        continue;
      }
      if (opt_group == opt_group_i::YshAll) {
        opt_nums->extend(consts::YSH_ALL);
        continue;
      }
      if (opt_group == opt_group_i::StrictAll) {
        opt_nums->extend(consts::STRICT_ALL);
        continue;
      }
      index = consts::OptionNum(opt_name);
      if (index == 0) {
        e_usage(StrFormat("got invalid option %r", opt_name), loc::Missing);
      }
      opt_nums->append(index);
    }
    {  // with
      state::ctx_Option ctx{this->mutable_opts, opt_nums, b};

      unused = this->cmd_ev->EvalCommand(cmd);
    }
    return 0;
  }
  for (ListIter<BigStr*> it(opt_names); !it.Done(); it.Next()) {
    BigStr* opt_name = it.Value();
    StackRoot _for(&opt_name  );
    this->mutable_opts->SetAnyOption(opt_name, b);
  }
  return 0;
}

Hash::Hash(state::SearchPath* search_path) {
  this->search_path = search_path;
}

int Hash::Run(cmd_value::Argv* cmd_val) {
  args::_Attributes* attrs = nullptr;
  args::Reader* arg_r = nullptr;
  arg_types::hash* arg = nullptr;
  List<BigStr*>* rest = nullptr;
  int status;
  BigStr* full_path = nullptr;
  List<BigStr*>* commands = nullptr;
  StackRoot _root0(&cmd_val);
  StackRoot _root1(&attrs);
  StackRoot _root2(&arg_r);
  StackRoot _root3(&arg);
  StackRoot _root4(&rest);
  StackRoot _root5(&full_path);
  StackRoot _root6(&commands);

  Tuple2<args::_Attributes*, args::Reader*> tup8 = flag_util::ParseCmdVal(str469, cmd_val);
  attrs = tup8.at0();
  arg_r = tup8.at1();
  arg = Alloc<arg_types::hash>(attrs->attrs);
  rest = arg_r->Rest();
  if (arg->r) {
    if (len(rest)) {
      e_usage(str470, loc::Missing);
    }
    this->search_path->ClearCache();
    return 0;
  }
  status = 0;
  if (len(rest)) {
    for (ListIter<BigStr*> it(rest); !it.Done(); it.Next()) {
      BigStr* cmd = it.Value();
      StackRoot _for(&cmd    );
      full_path = this->search_path->CachedLookup(cmd);
      if (full_path == nullptr) {
        print_stderr(StrFormat("hash: %r not found", cmd));
        status = 1;
      }
    }
  }
  else {
    commands = this->search_path->CachedCommands();
    commands->sort();
    for (ListIter<BigStr*> it(commands); !it.Done(); it.Next()) {
      BigStr* cmd = it.Value();
      StackRoot _for(&cmd    );
      print(cmd);
    }
  }
  return status;
}

Dict<BigStr*, bool>* _ParseOptSpec(BigStr* spec_str) {
  Dict<BigStr*, bool>* spec = nullptr;
  int i;
  int n;
  BigStr* ch = nullptr;
  StackRoot _root0(&spec_str);
  StackRoot _root1(&spec);
  StackRoot _root2(&ch);

  spec = Alloc<Dict<BigStr*, bool>>();
  i = 0;
  n = len(spec_str);
  while (true) {
    if (i >= n) {
      break;
    }
    ch = spec_str->at(i);
    spec->set(ch, false);
    i += 1;
    if (i >= n) {
      break;
    }
    if (str_equals(spec_str->at(i), str472)) {
      spec->set(ch, true);
      i += 1;
    }
  }
  return spec;
}

GetOptsState::GetOptsState(state::Mem* mem, ui::ErrorFormatter* errfmt) {
  this->mem = mem;
  this->errfmt = errfmt;
  this->_optind = -1;
  this->flag_pos = 1;
}

int GetOptsState::_OptInd() {
  int result;
  try {
    result = state::GetInteger(this->mem, str473);
  }
  catch (error::Runtime* e) {
    this->errfmt->Print_(e->UserErrorString());
    result = -1;
  }
  return result;
}

BigStr* GetOptsState::GetArg(List<BigStr*>* argv) {
  int optind;
  int i;
  StackRoot _root0(&argv);

  optind = this->_OptInd();
  if (optind == -1) {
    return nullptr;
  }
  this->_optind = optind;
  i = (optind - 1);
  if ((0 <= i and i < len(argv))) {
    return argv->at(i);
  }
  else {
    return nullptr;
  }
}

void GetOptsState::IncIndex() {
  state::BuiltinSetString(this->mem, str474, str((this->_optind + 1)));
  this->flag_pos = 1;
}

void GetOptsState::SetArg(BigStr* optarg) {
  StackRoot _root0(&optarg);

  state::BuiltinSetString(this->mem, str475, optarg);
}

void GetOptsState::Fail() {
  state::BuiltinSetString(this->mem, str476, str477);
}

Tuple2<int, BigStr*> _GetOpts(Dict<BigStr*, bool>* spec, List<BigStr*>* argv, pure_osh::GetOptsState* my_state, ui::ErrorFormatter* errfmt) {
  BigStr* current = nullptr;
  BigStr* flag_char = nullptr;
  bool more_chars;
  BigStr* optarg = nullptr;
  List<BigStr*>* tmp = nullptr;
  StackRoot _root0(&spec);
  StackRoot _root1(&argv);
  StackRoot _root2(&my_state);
  StackRoot _root3(&errfmt);
  StackRoot _root4(&current);
  StackRoot _root5(&flag_char);
  StackRoot _root6(&optarg);
  StackRoot _root7(&tmp);

  current = my_state->GetArg(argv);
  if (current == nullptr) {
    my_state->Fail();
    return Tuple2<int, BigStr*>(1, str478);
  }
  if ((!current->startswith(str479) or str_equals(current, str480))) {
    my_state->Fail();
    return Tuple2<int, BigStr*>(1, str481);
  }
  flag_char = current->at(my_state->flag_pos);
  if (my_state->flag_pos < (len(current) - 1)) {
    my_state->flag_pos += 1;
    more_chars = true;
  }
  else {
    my_state->IncIndex();
    my_state->flag_pos = 1;
    more_chars = false;
  }
  if (!dict_contains(spec, flag_char)) {
    return Tuple2<int, BigStr*>(0, str482);
  }
  if (spec->at(flag_char)) {
    if (more_chars) {
      optarg = current->slice(my_state->flag_pos);
    }
    else {
      optarg = my_state->GetArg(argv);
      if (optarg == nullptr) {
        my_state->Fail();
        errfmt->Print_(StrFormat("getopts: option %r requires an argument.", current));
        tmp = Alloc<List<BigStr*>>();
        for (ListIter<BigStr*> it(argv); !it.Done(); it.Next()) {
          BigStr* a = it.Value();
          tmp->append(j8_lite::MaybeShellEncode(a));
        }
        print_stderr(StrFormat("(getopts argv: %s)", str485->join(tmp)));
        return Tuple2<int, BigStr*>(0, str486);
      }
    }
    my_state->IncIndex();
    my_state->SetArg(optarg);
  }
  else {
    my_state->SetArg(str487);
  }
  return Tuple2<int, BigStr*>(0, flag_char);
}

GetOpts::GetOpts(state::Mem* mem, ui::ErrorFormatter* errfmt) {
  this->mem = mem;
  this->errfmt = errfmt;
  this->my_state = Alloc<GetOptsState>(mem, errfmt);
  this->spec_cache = Alloc<Dict<BigStr*, Dict<BigStr*, bool>*>>();
}

int GetOpts::Run(cmd_value::Argv* cmd_val) {
  args::Reader* arg_r = nullptr;
  BigStr* spec_str = nullptr;
  BigStr* var_name = nullptr;
  syntax_asdl::loc_t* var_loc = nullptr;
  Dict<BigStr*, bool>* spec = nullptr;
  List<BigStr*>* user_argv = nullptr;
  int status;
  BigStr* flag_char = nullptr;
  StackRoot _root0(&cmd_val);
  StackRoot _root1(&arg_r);
  StackRoot _root2(&spec_str);
  StackRoot _root3(&var_name);
  StackRoot _root4(&var_loc);
  StackRoot _root5(&spec);
  StackRoot _root6(&user_argv);
  StackRoot _root7(&flag_char);

  arg_r = Alloc<args::Reader>(cmd_val->argv, cmd_val->arg_locs);
  arg_r->Next();
  spec_str = arg_r->ReadRequired(str488);
  Tuple2<BigStr*, syntax_asdl::loc_t*> tup9 = arg_r->ReadRequired2(str489);
  var_name = tup9.at0();
  var_loc = tup9.at1();
  spec = this->spec_cache->get(spec_str);
  if (spec == nullptr) {
    spec = _ParseOptSpec(spec_str);
    this->spec_cache->set(spec_str, spec);
  }
  user_argv = arg_r->AtEnd() ? this->mem->GetArgv() : arg_r->Rest();
  Tuple2<int, BigStr*> tup10 = _GetOpts(spec, user_argv, this->my_state, this->errfmt);
  status = tup10.at0();
  flag_char = tup10.at1();
  if (match::IsValidVarName(var_name)) {
    state::BuiltinSetString(this->mem, var_name, flag_char);
  }
  else {
    throw Alloc<error::Usage>(StrFormat("got invalid variable name %r", var_name), var_loc);
  }
  return status;
}

}  // define namespace pure_osh

namespace pure_ysh {  // define

using runtime_asdl::cmd_value;
using runtime_asdl::scope_e;
using syntax_asdl::command_t;
using syntax_asdl::loc;
using syntax_asdl::loc_t;
using value_asdl::value;
using value_asdl::value_e;
using value_asdl::value_t;
using value_asdl::LeftName;

ctx_Shvar::ctx_Shvar(state::Mem* mem, List<Tuple2<BigStr*, value_asdl::value_t*>*>* pairs) {
  gHeap.PushRoot(reinterpret_cast<RawObject**>(&(this->mem)));
  gHeap.PushRoot(reinterpret_cast<RawObject**>(&(this->restore)));
  this->mem = mem;
  this->restore = Alloc<List<Tuple2<value_asdl::LeftName*, value_asdl::value_t*>*>>();
  this->_Push(pairs);
}

ctx_Shvar::~ctx_Shvar() {
  this->_Pop();
  gHeap.PopRoot();
  gHeap.PopRoot();
}

void ctx_Shvar::_Push(List<Tuple2<BigStr*, value_asdl::value_t*>*>* pairs) {
  BigStr* name = nullptr;
  value_asdl::value_t* v = nullptr;
  value_asdl::LeftName* lval = nullptr;
  value_asdl::value_t* old_val = nullptr;
  StackRoot _root0(&pairs);
  StackRoot _root1(&name);
  StackRoot _root2(&v);
  StackRoot _root3(&lval);
  StackRoot _root4(&old_val);

  for (ListIter<Tuple2<BigStr*, value_asdl::value_t*>*> it(pairs); !it.Done(); it.Next()) {
    Tuple2<BigStr*, value_asdl::value_t*>* tup0 = it.Value();
    name = tup0->at0();
    v = tup0->at1();
    lval = location::LName(name);
    old_val = this->mem->GetValue(name, scope_e::LocalOnly);
    this->restore->append((Alloc<Tuple2<value_asdl::LeftName*, value_asdl::value_t*>>(lval, old_val)));
    this->mem->SetNamed(lval, v, scope_e::LocalOnly);
  }
}

void ctx_Shvar::_Pop() {
  value_asdl::LeftName* lval = nullptr;
  value_asdl::value_t* old_val = nullptr;
  StackRoot _root0(&lval);
  StackRoot _root1(&old_val);

  for (ListIter<Tuple2<value_asdl::LeftName*, value_asdl::value_t*>*> it(this->restore); !it.Done(); it.Next()) {
    Tuple2<value_asdl::LeftName*, value_asdl::value_t*>* tup1 = it.Value();
    lval = tup1->at0();
    old_val = tup1->at1();
    if (old_val->tag() == value_e::Undef) {
      this->mem->Unset(lval, scope_e::LocalOnly);
    }
    else {
      this->mem->SetNamed(lval, old_val, scope_e::LocalOnly);
    }
  }
}

Shvar::Shvar(state::Mem* mem, state::SearchPath* search_path, cmd_eval::CommandEvaluator* cmd_ev) {
  this->mem = mem;
  this->search_path = search_path;
  this->cmd_ev = cmd_ev;
}

int Shvar::Run(cmd_value::Argv* cmd_val) {
  args::Reader* arg_r = nullptr;
  syntax_asdl::command_t* cmd = nullptr;
  List<Tuple2<BigStr*, value_asdl::value_t*>*>* pairs = nullptr;
  List<BigStr*>* args = nullptr;
  List<syntax_asdl::CompoundWord*>* arg_locs = nullptr;
  int i;
  BigStr* name = nullptr;
  BigStr* s = nullptr;
  value_asdl::value_t* v = nullptr;
  int unused;
  StackRoot _root0(&cmd_val);
  StackRoot _root1(&arg_r);
  StackRoot _root2(&cmd);
  StackRoot _root3(&pairs);
  StackRoot _root4(&args);
  StackRoot _root5(&arg_locs);
  StackRoot _root6(&name);
  StackRoot _root7(&s);
  StackRoot _root8(&v);

  Tuple2<args::_Attributes*, args::Reader*> tup2 = flag_util::ParseCmdVal(str491, cmd_val, true);
  arg_r = tup2.at1();
  cmd = typed_args::OptionalBlock(cmd_val);
  if (!cmd) {
    throw Alloc<error::Usage>(str492, loc::Missing);
  }
  pairs = Alloc<List<Tuple2<BigStr*, value_asdl::value_t*>*>>();
  Tuple2<List<BigStr*>*, List<syntax_asdl::CompoundWord*>*> tup3 = arg_r->Rest2();
  args = tup3.at0();
  arg_locs = tup3.at1();
  if (len(args) == 0) {
    throw Alloc<error::Usage>(str493, loc::Missing);
  }
  i = 0;
  for (ListIter<BigStr*> it(args); !it.Done(); it.Next(), ++i) {
    BigStr* arg = it.Value();
    StackRoot _for(&arg  );
    Tuple2<BigStr*, BigStr*> tup4 = mylib::split_once(arg, str494);
    name = tup4.at0();
    s = tup4.at1();
    if (s == nullptr) {
      throw Alloc<error::Usage>(str495, arg_locs->at(i));
    }
    v = Alloc<value::Str>(s);
    pairs->append((Alloc<Tuple2<BigStr*, value_asdl::value_t*>>(name, v)));
    if (str_equals(name, str496)) {
      this->search_path->ClearCache();
    }
  }
  {  // with
    ctx_Shvar ctx{this->mem, pairs};

    unused = this->cmd_ev->EvalCommand(cmd);
  }
  return 0;
}

ctx_Context::ctx_Context(state::Mem* mem, Dict<BigStr*, value_asdl::value_t*>* context) {
  gHeap.PushRoot(reinterpret_cast<RawObject**>(&(this->mem)));
  this->mem = mem;
  this->mem->PushContextStack(context);
}

ctx_Context::~ctx_Context() {
  this->mem->PopContextStack();
  gHeap.PopRoot();
}

Ctx::Ctx(state::Mem* mem, cmd_eval::CommandEvaluator* cmd_ev) {
  this->mem = mem;
  this->cmd_ev = cmd_ev;
}

Dict<BigStr*, value_asdl::value_t*>* Ctx::_GetContext() {
  Dict<BigStr*, value_asdl::value_t*>* ctx = nullptr;
  StackRoot _root0(&ctx);

  ctx = this->mem->GetContext();
  if (ctx == nullptr) {
    throw Alloc<error::Expr>(str497, loc::Missing);
  }
  return ctx;
}

int Ctx::_Push(Dict<BigStr*, value_asdl::value_t*>* context, syntax_asdl::command_t* block) {
  StackRoot _root0(&context);
  StackRoot _root1(&block);

  {  // with
    ctx_Context ctx{this->mem, context};

    return this->cmd_ev->EvalCommand(block);
  }
}

int Ctx::_Set(Dict<BigStr*, value_asdl::value_t*>* updates) {
  Dict<BigStr*, value_asdl::value_t*>* ctx = nullptr;
  StackRoot _root0(&updates);
  StackRoot _root1(&ctx);

  ctx = this->_GetContext();
  ctx->update(updates);
  return 0;
}

int Ctx::_Emit(BigStr* field, value_asdl::value_t* item, syntax_asdl::loc_t* blame) {
  Dict<BigStr*, value_asdl::value_t*>* ctx = nullptr;
  value_asdl::value_t* UP_arr = nullptr;
  StackRoot _root0(&field);
  StackRoot _root1(&item);
  StackRoot _root2(&blame);
  StackRoot _root3(&ctx);
  StackRoot _root4(&UP_arr);

  ctx = this->_GetContext();
  if (!dict_contains(ctx, field)) {
    ctx->set(field, Alloc<value::List>(Alloc<List<value_asdl::value_t*>>()));
  }
  UP_arr = ctx->at(field);
  if (UP_arr->tag() != value_e::List) {
    throw Alloc<error::TypeErr>(UP_arr, StrFormat("Expected the context item '%s' to be a List", field), blame);
  }
  value::List* arr = static_cast<value::List*>(UP_arr);
  arr->items->append(item);
  return 0;
}

int Ctx::Run(cmd_value::Argv* cmd_val) {
  typed_args::Reader* rd = nullptr;
  args::Reader* arg_r = nullptr;
  BigStr* verb = nullptr;
  syntax_asdl::loc_t* verb_loc = nullptr;
  Dict<BigStr*, value_asdl::value_t*>* context = nullptr;
  syntax_asdl::command_t* block = nullptr;
  Dict<BigStr*, value_asdl::value_t*>* updates = nullptr;
  BigStr* field = nullptr;
  syntax_asdl::loc_t* field_loc = nullptr;
  value_asdl::value_t* item = nullptr;
  StackRoot _root0(&cmd_val);
  StackRoot _root1(&rd);
  StackRoot _root2(&arg_r);
  StackRoot _root3(&verb);
  StackRoot _root4(&verb_loc);
  StackRoot _root5(&context);
  StackRoot _root6(&block);
  StackRoot _root7(&updates);
  StackRoot _root8(&field);
  StackRoot _root9(&field_loc);
  StackRoot _root10(&item);

  rd = typed_args::ReaderForProc(cmd_val);
  Tuple2<args::_Attributes*, args::Reader*> tup5 = flag_util::ParseCmdVal(str499, cmd_val, true);
  arg_r = tup5.at1();
  Tuple2<BigStr*, syntax_asdl::loc_t*> tup6 = arg_r->ReadRequired2(str500);
  verb = tup6.at0();
  verb_loc = tup6.at1();
  if (str_equals(verb, str501)) {
    context = rd->PosDict();
    block = rd->RequiredBlock();
    rd->Done();
    arg_r->AtEnd();
    return this->_Push(context, block);
  }
  else {
    if (str_equals(verb, str502)) {
      updates = rd->RestNamed();
      rd->Done();
      arg_r->AtEnd();
      return this->_Set(updates);
    }
    else {
      if (str_equals(verb, str503)) {
        Tuple2<BigStr*, syntax_asdl::loc_t*> tup7 = arg_r->ReadRequired2(str504);
        field = tup7.at0();
        field_loc = tup7.at1();
        item = rd->PosValue();
        rd->Done();
        arg_r->AtEnd();
        return this->_Emit(field, item, field_loc);
      }
      else {
        throw Alloc<error::Usage>(StrFormat("Unknown verb '%s'", verb), verb_loc);
      }
    }
  }
}

PushRegisters::PushRegisters(state::Mem* mem, cmd_eval::CommandEvaluator* cmd_ev) {
  this->mem = mem;
  this->cmd_ev = cmd_ev;
}

int PushRegisters::Run(cmd_value::Argv* cmd_val) {
  args::Reader* arg_r = nullptr;
  syntax_asdl::command_t* cmd = nullptr;
  int unused;
  StackRoot _root0(&cmd_val);
  StackRoot _root1(&arg_r);
  StackRoot _root2(&cmd);

  Tuple2<args::_Attributes*, args::Reader*> tup8 = flag_util::ParseCmdVal(str506, cmd_val, true);
  arg_r = tup8.at1();
  cmd = typed_args::OptionalBlock(cmd_val);
  if (!cmd) {
    throw Alloc<error::Usage>(str507, loc::Missing);
  }
  {  // with
    state::ctx_Registers ctx{this->mem};

    unused = this->cmd_ev->EvalCommand(cmd);
  }
  return this->mem->last_status->at(-1);
}

Append::Append(state::Mem* mem, ui::ErrorFormatter* errfmt) {
  this->mem = mem;
  this->errfmt = errfmt;
}

int Append::Run(cmd_value::Argv* cmd_val) {
  args::_Attributes* arg = nullptr;
  args::Reader* arg_r = nullptr;
  typed_args::Reader* rd = nullptr;
  value_asdl::value_t* val = nullptr;
  value_asdl::value_t* UP_val = nullptr;
  List<value_asdl::value_t*>* typed = nullptr;
  StackRoot _root0(&cmd_val);
  StackRoot _root1(&arg);
  StackRoot _root2(&arg_r);
  StackRoot _root3(&rd);
  StackRoot _root4(&val);
  StackRoot _root5(&UP_val);
  StackRoot _root6(&typed);

  Tuple2<args::_Attributes*, args::Reader*> tup9 = flag_util::ParseCmdVal(str508, cmd_val, true);
  arg = tup9.at0();
  arg_r = tup9.at1();
  rd = typed_args::ReaderForProc(cmd_val);
  val = rd->PosValue();
  rd->Done();
  UP_val = val;
  switch (val->tag()) {
    case value_e::BashArray: {
      value::BashArray* val = static_cast<value::BashArray*>(UP_val);
      val->strs->extend(arg_r->Rest());
    }
      break;
    case value_e::List: {
      value::List* val = static_cast<value::List*>(UP_val);
      typed = Alloc<List<value_asdl::value_t*>>();
      for (ListIter<BigStr*> it(arg_r->Rest()); !it.Done(); it.Next()) {
        BigStr* s = it.Value();
        typed->append(Alloc<value::Str>(s));
      }
      val->items->extend(typed);
    }
      break;
    default: {
      throw Alloc<error::TypeErr>(val, str509, loc::Missing);
    }
  }
  return 0;
}

}  // define namespace pure_ysh

namespace read_osh {  // define

using runtime_asdl::span_e;
using runtime_asdl::cmd_value;
using syntax_asdl::source;
using syntax_asdl::loc_t;
using value_asdl::value;
using value_asdl::LeftName;
using error::e_die;

Tuple2<bool, bool> _AppendParts(BigStr* s, List<Tuple2<runtime_asdl::span_t, int>*>* spans, int max_results, bool join_next, List<mylib::BufWriter*>* parts) {
  int start_index;
  bool last_span_was_black;
  runtime_asdl::span_t span_type;
  int end_index;
  mylib::BufWriter* buf = nullptr;
  bool done;
  runtime_asdl::span_t last_span_type;
  StackRoot _root0(&s);
  StackRoot _root1(&spans);
  StackRoot _root2(&parts);
  StackRoot _root3(&buf);

  start_index = 0;
  last_span_was_black = false;
  for (ListIter<Tuple2<runtime_asdl::span_t, int>*> it(spans); !it.Done(); it.Next()) {
    Tuple2<runtime_asdl::span_t, int>* tup0 = it.Value();
    span_type = tup0->at0();
    end_index = tup0->at1();
    if (span_type == span_e::Black) {
      if ((join_next and len(parts))) {
        parts->at(-1)->write(s->slice(start_index, end_index));
        join_next = false;
      }
      else {
        buf = Alloc<mylib::BufWriter>();
        buf->write(s->slice(start_index, end_index));
        parts->append(buf);
      }
      last_span_was_black = true;
    }
    else {
      if (span_type == span_e::Delim) {
        if (join_next) {
          parts->at(-1)->write(s->slice(start_index, end_index));
          join_next = false;
        }
        last_span_was_black = false;
      }
      else {
        if (span_type == span_e::Backslash) {
          if (last_span_was_black) {
            join_next = true;
          }
          last_span_was_black = false;
        }
      }
    }
    if ((max_results and len(parts) >= max_results)) {
      join_next = true;
    }
    start_index = end_index;
  }
  done = true;
  if (len(spans)) {
    Tuple2<runtime_asdl::span_t, int>* tup1 = spans->at(-1);
    last_span_type = tup1->at0();
    if (last_span_type == span_e::Backslash) {
      done = false;
    }
  }
  return Tuple2<bool, bool>(done, join_next);
}

BigStr* _ReadN(int num_bytes, cmd_eval::CommandEvaluator* cmd_ev) {
  List<BigStr*>* chunks = nullptr;
  int bytes_left;
  int n;
  int err_num;
  StackRoot _root0(&cmd_ev);
  StackRoot _root1(&chunks);

  chunks = Alloc<List<BigStr*>>();
  bytes_left = num_bytes;
  while (bytes_left > 0) {
    Tuple2<int, int> tup2 = pyos::Read(STDIN_FILENO, bytes_left, chunks);
    n = tup2.at0();
    err_num = tup2.at1();
    if (n < 0) {
      if (err_num == EINTR) {
        cmd_ev->RunPendingTraps();
      }
      else {
        throw Alloc<pyos::ReadError>(err_num);
      }
    }
    else {
      if (n == 0) {
        break;
      }
      else {
        bytes_left -= n;
      }
    }
  }
  return str510->join(chunks);
}

Tuple2<BigStr*, bool> _ReadPortion(int delim_byte, int max_chars, cmd_eval::CommandEvaluator* cmd_ev) {
  bool eof;
  List<int>* ch_array = nullptr;
  int bytes_read;
  int ch;
  int err_num;
  StackRoot _root0(&cmd_ev);
  StackRoot _root1(&ch_array);

  eof = false;
  ch_array = Alloc<List<int>>();
  bytes_read = 0;
  while (true) {
    if ((max_chars >= 0 and bytes_read >= max_chars)) {
      break;
    }
    Tuple2<int, int> tup3 = pyos::ReadByte(0);
    ch = tup3.at0();
    err_num = tup3.at1();
    if (ch < 0) {
      if (err_num == EINTR) {
        cmd_ev->RunPendingTraps();
      }
      else {
        throw Alloc<pyos::ReadError>(err_num);
      }
    }
    else {
      if (ch == pyos::EOF_SENTINEL) {
        eof = true;
        break;
      }
      else {
        if (ch == delim_byte) {
          break;
        }
        else {
          ch_array->append(ch);
        }
      }
    }
    bytes_read += 1;
  }
  return Tuple2<BigStr*, bool>(pyutil::ChArrayToString(ch_array), eof);
}

Tuple2<BigStr*, bool> ReadLineSlowly(cmd_eval::CommandEvaluator* cmd_ev, bool with_eol) {
  bool eof;
  List<int>* ch_array = nullptr;
  int ch;
  int err_num;
  StackRoot _root0(&cmd_ev);
  StackRoot _root1(&ch_array);

  eof = false;
  ch_array = Alloc<List<int>>();
  while (true) {
    Tuple2<int, int> tup4 = pyos::ReadByte(0);
    ch = tup4.at0();
    err_num = tup4.at1();
    if (ch < 0) {
      if (err_num == EINTR) {
        cmd_ev->RunPendingTraps();
      }
      else {
        throw Alloc<pyos::ReadError>(err_num);
      }
    }
    else {
      if (ch == pyos::EOF_SENTINEL) {
        eof = true;
        break;
      }
      else {
        ch_array->append(ch);
      }
    }
    if (ch == pyos::NEWLINE_CH) {
      if (!with_eol) {
        ch_array->pop();
      }
      break;
    }
  }
  return Tuple2<BigStr*, bool>(pyutil::ChArrayToString(ch_array), eof);
}

BigStr* ReadAll() {
  List<BigStr*>* chunks = nullptr;
  int n;
  int err_num;
  int orig_local_modes;
  void* term_attrs = nullptr;
  StackRoot _root0(&chunks);
  StackRoot _root1(&term_attrs);

  chunks = Alloc<List<BigStr*>>();
  while (true) {
    Tuple2<int, int> tup5 = pyos::Read(0, 4096, chunks);
    n = tup5.at0();
    err_num = tup5.at1();
    if (n < 0) {
      if (err_num == EINTR) {
        ;  // pass
      }
      else {
        throw Alloc<pyos::ReadError>(err_num);
      }
    }
    else {
      if (n == 0) {
        break;
      }
    }
  }
  return str511->join(chunks);
}

ctx_TermAttrs::ctx_TermAttrs(int fd, int local_modes) {
  gHeap.PushRoot(reinterpret_cast<RawObject**>(&(this->term_attrs)));
  this->fd = fd;
  Tuple2<int, void*> tup6 = pyos::PushTermAttrs(fd, local_modes);
  orig_local_modes = tup6.at0();
  term_attrs = tup6.at1();
  this->orig_local_modes = orig_local_modes;
  this->term_attrs = term_attrs;
}

ctx_TermAttrs::~ctx_TermAttrs() {
  pyos::PopTermAttrs(this->fd, this->orig_local_modes, this->term_attrs);
  gHeap.PopRoot();
}

Read::Read(split::SplitContext* splitter, state::Mem* mem, parse_lib::ParseContext* parse_ctx, cmd_eval::CommandEvaluator* cmd_ev, ui::ErrorFormatter* errfmt) {
  this->splitter = splitter;
  this->mem = mem;
  this->parse_ctx = parse_ctx;
  this->cmd_ev = cmd_ev;
  this->errfmt = errfmt;
  this->stdin_ = mylib::Stdin();
}

int Read::Run(cmd_value::Argv* cmd_val) {
  int status;
  StackRoot _root0(&cmd_val);

  try {
    status = this->_Run(cmd_val);
  }
  catch (pyos::ReadError* e) {
    this->errfmt->PrintMessage(StrFormat("Oils read error: %s", posix::strerror(e->err_num)));
    status = 1;
  }
  catch (IOError_OSError* e) {
    this->errfmt->PrintMessage(StrFormat("Oils read I/O error: %s", pyutil::strerror(e)));
    status = 1;
  }
  return status;
}

int Read::_ReadYsh(arg_types::read* arg, args::Reader* arg_r, cmd_value::Argv* cmd_val) {
  value::Place* place = nullptr;
  typed_args::Reader* rd = nullptr;
  syntax_asdl::loc_t* blame_loc = nullptr;
  BigStr* var_name = nullptr;
  BigStr* next_arg = nullptr;
  syntax_asdl::loc_t* next_loc = nullptr;
  int num_bytes;
  BigStr* contents = nullptr;
  int status;
  bool eof;
  StackRoot _root0(&arg);
  StackRoot _root1(&arg_r);
  StackRoot _root2(&cmd_val);
  StackRoot _root3(&place);
  StackRoot _root4(&rd);
  StackRoot _root5(&blame_loc);
  StackRoot _root6(&var_name);
  StackRoot _root7(&next_arg);
  StackRoot _root8(&next_loc);
  StackRoot _root9(&contents);

  place = nullptr;
  if (cmd_val->typed_args) {
    rd = typed_args::ReaderForProc(cmd_val);
    place = rd->PosPlace();
    rd->Done();
    blame_loc = cmd_val->typed_args->left;
  }
  else {
    var_name = str517;
    blame_loc = cmd_val->arg_locs->at(0);
    place = Alloc<value::Place>(Alloc<LeftName>(var_name, blame_loc), this->mem->TopNamespace());
  }
  Tuple2<BigStr*, syntax_asdl::loc_t*> tup7 = arg_r->Peek2();
  next_arg = tup7.at0();
  next_loc = tup7.at1();
  if (next_arg != nullptr) {
    throw Alloc<error::Usage>(str518, next_loc);
  }
  num_bytes = mops::BigTruncate(arg->num_bytes);
  if (num_bytes != -1) {
    contents = _ReadN(num_bytes, this->cmd_ev);
    status = 0;
  }
  else {
    if (arg->raw_line) {
      Tuple2<BigStr*, bool> tup8 = ReadLineSlowly(this->cmd_ev, arg->with_eol);
      contents = tup8.at0();
      eof = tup8.at1();
      status = eof ? 1 : 0;
    }
    else {
      if (arg->all) {
        contents = ReadAll();
        status = 0;
      }
      else {
        assert(0);  // AssertionError
      }
    }
  }
  this->mem->SetPlace(place, Alloc<value::Str>(contents), blame_loc);
  return status;
}

int Read::_Run(cmd_value::Argv* cmd_val) {
  args::_Attributes* attrs = nullptr;
  args::Reader* arg_r = nullptr;
  arg_types::read* arg = nullptr;
  List<BigStr*>* names = nullptr;
  int bits;
  int status;
  StackRoot _root0(&cmd_val);
  StackRoot _root1(&attrs);
  StackRoot _root2(&arg_r);
  StackRoot _root3(&arg);
  StackRoot _root4(&names);

  Tuple2<args::_Attributes*, args::Reader*> tup9 = flag_util::ParseCmdVal(str519, cmd_val, true);
  attrs = tup9.at0();
  arg_r = tup9.at1();
  arg = Alloc<arg_types::read>(attrs->attrs);
  names = arg_r->Rest();
  if ((arg->raw_line or (arg->all or mops::BigTruncate(arg->num_bytes) != -1))) {
    return this->_ReadYsh(arg, arg_r, cmd_val);
  }
  if (cmd_val->typed_args) {
    throw Alloc<error::Usage>(str520, cmd_val->typed_args->left);
  }
  if (arg->t >= 0.0) {
    if (arg->t != 0.0) {
      e_die(str521);
    }
    else {
      return pyos::InputAvailable(STDIN_FILENO) ? 0 : 1;
    }
  }
  bits = 0;
  if (this->stdin_->isatty()) {
    if ((arg->d != nullptr or mops::BigTruncate(arg->n) >= 0)) {
      bits |= pyos::TERM_ICANON;
    }
    if (arg->s) {
      bits |= pyos::TERM_ECHO;
    }
    if (arg->p != nullptr) {
      mylib::Stderr()->write(arg->p);
    }
  }
  if (bits == 0) {
    status = this->_Read(arg, names);
  }
  else {
    {  // with
      ctx_TermAttrs ctx{STDIN_FILENO, ~bits};

      status = this->_Read(arg, names);
    }
  }
  return status;
}

int Read::_Read(arg_types::read* arg, List<BigStr*>* names) {
  int arg_N;
  BigStr* s = nullptr;
  BigStr* name = nullptr;
  bool do_split;
  int max_results;
  bool raw;
  int delim_byte;
  List<mylib::BufWriter*>* parts = nullptr;
  bool join_next;
  int status;
  BigStr* chunk = nullptr;
  bool eof;
  List<Tuple2<runtime_asdl::span_t, int>*>* spans = nullptr;
  bool done;
  List<BigStr*>* entries = nullptr;
  int num_parts;
  BigStr* var_name = nullptr;
  StackRoot _root0(&arg);
  StackRoot _root1(&names);
  StackRoot _root2(&s);
  StackRoot _root3(&name);
  StackRoot _root4(&parts);
  StackRoot _root5(&chunk);
  StackRoot _root6(&spans);
  StackRoot _root7(&entries);
  StackRoot _root8(&var_name);

  arg_N = mops::BigTruncate(arg->N);
  if (arg_N >= 0) {
    s = _ReadN(arg_N, this->cmd_ev);
    if (len(names)) {
      name = names->at(0);
      for (int i = 1; i < len(names); ++i) {
        state::BuiltinSetString(this->mem, names->at(i), str522);
      }
    }
    else {
      name = str523;
    }
    state::BuiltinSetString(this->mem, name, s);
    return len(s) == arg_N ? 0 : 1;
  }
  do_split = false;
  if (len(names)) {
    do_split = true;
  }
  else {
    names->append(str524);
  }
  if (arg->a != nullptr) {
    max_results = 0;
    do_split = true;
  }
  else {
    max_results = len(names);
  }
  if (arg->Z) {
    do_split = false;
    raw = true;
    delim_byte = 0;
  }
  else {
    raw = arg->r;
    if (arg->d != nullptr) {
      if (len(arg->d)) {
        delim_byte = ord(arg->d->at(0));
      }
      else {
        delim_byte = 0;
      }
    }
    else {
      delim_byte = pyos::NEWLINE_CH;
    }
  }
  parts = Alloc<List<mylib::BufWriter*>>();
  join_next = false;
  status = 0;
  while (true) {
    Tuple2<BigStr*, bool> tup10 = _ReadPortion(delim_byte, mops::BigTruncate(arg->n), this->cmd_ev);
    chunk = tup10.at0();
    eof = tup10.at1();
    if (eof) {
      status = 1;
    }
    if (len(chunk) == 0) {
      break;
    }
    spans = this->splitter->SplitForRead(chunk, !raw, do_split);
    Tuple2<bool, bool> tup11 = _AppendParts(chunk, spans, max_results, join_next, parts);
    done = tup11.at0();
    join_next = tup11.at1();
    if (done) {
      break;
    }
  }
  entries = Alloc<List<BigStr*>>();
  for (ListIter<mylib::BufWriter*> it(parts); !it.Done(); it.Next()) {
    mylib::BufWriter* buf = it.Value();
    entries->append(buf->getvalue());
  }
  num_parts = len(entries);
  if (arg->a != nullptr) {
    state::BuiltinSetArray(this->mem, arg->a, entries);
  }
  else {
    for (int i = 0; i < max_results; ++i) {
      if (i < num_parts) {
        s = entries->at(i);
      }
      else {
        s = str525;
      }
      var_name = names->at(i);
      state::BuiltinSetString(this->mem, var_name, s);
    }
  }
  return status;
}

}  // define namespace read_osh

namespace readline_osh {  // define

using syntax_asdl::loc;
using error::e_usage;

Bind::Bind(py_readline::Readline* readline, ui::ErrorFormatter* errfmt) {
  this->readline = readline;
  this->errfmt = errfmt;
}

int Bind::Run(cmd_value::Argv* cmd_val) {
  StackRoot _root0(&cmd_val);

  this->errfmt->Print_(str526, cmd_val->arg_locs->at(0));
  return 1;
}

History::History(py_readline::Readline* readline, shell::ShellFiles* sh_files, ui::ErrorFormatter* errfmt, mylib::Writer* f) {
  this->readline = readline;
  this->sh_files = sh_files;
  this->errfmt = errfmt;
  this->f = f;
}

int History::Run(cmd_value::Argv* cmd_val) {
  py_readline::Readline* readline = nullptr;
  args::_Attributes* attrs = nullptr;
  args::Reader* arg_r = nullptr;
  arg_types::history* arg = nullptr;
  BigStr* hist_file = nullptr;
  int arg_d;
  int cmd_index;
  int num_items;
  BigStr* num_arg = nullptr;
  syntax_asdl::loc_t* num_arg_loc = nullptr;
  int start_index;
  int num_to_show;
  BigStr* item = nullptr;
  StackRoot _root0(&cmd_val);
  StackRoot _root1(&readline);
  StackRoot _root2(&attrs);
  StackRoot _root3(&arg_r);
  StackRoot _root4(&arg);
  StackRoot _root5(&hist_file);
  StackRoot _root6(&num_arg);
  StackRoot _root7(&num_arg_loc);
  StackRoot _root8(&item);

  readline = this->readline;
  if (!readline) {
    e_usage(str527, loc::Missing);
  }
  Tuple2<args::_Attributes*, args::Reader*> tup0 = flag_util::ParseCmdVal(str528, cmd_val);
  attrs = tup0.at0();
  arg_r = tup0.at1();
  arg = Alloc<arg_types::history>(attrs->attrs);
  if (arg->c) {
    readline->clear_history();
    return 0;
  }
  if (arg->a) {
    hist_file = this->sh_files->HistoryFile();
    if (hist_file == nullptr) {
      return 1;
    }
    try {
      readline->write_history_file(hist_file);
    }
    catch (IOError_OSError* e) {
      this->errfmt->Print_(StrFormat("Error writing HISTFILE %r: %s", hist_file, pyutil::strerror(e)), loc::Missing);
      return 1;
    }
    return 0;
  }
  if (arg->r) {
    hist_file = this->sh_files->HistoryFile();
    if (hist_file == nullptr) {
      return 1;
    }
    try {
      readline->read_history_file(hist_file);
    }
    catch (IOError_OSError* e) {
      this->errfmt->Print_(StrFormat("Error reading HISTFILE %r: %s", hist_file, pyutil::strerror(e)), loc::Missing);
      return 1;
    }
    return 0;
  }
  arg_d = mops::BigTruncate(arg->d);
  if (arg_d >= 0) {
    cmd_index = (arg_d - 1);
    try {
      readline->remove_history_item(cmd_index);
    }
    catch (ValueError*) {
      e_usage(StrFormat("couldn't find item %d", arg_d), loc::Missing);
    }
    return 0;
  }
  num_items = readline->get_current_history_length();
  Tuple2<BigStr*, syntax_asdl::loc_t*> tup1 = arg_r->Peek2();
  num_arg = tup1.at0();
  num_arg_loc = tup1.at1();
  if (num_arg == nullptr) {
    start_index = 1;
  }
  else {
    try {
      num_to_show = to_int(num_arg);
    }
    catch (ValueError*) {
      e_usage(StrFormat("got invalid argument %r", num_arg), num_arg_loc);
    }
    start_index = max(1, ((num_items + 1) - num_to_show));
  }
  arg_r->Next();
  if (!arg_r->AtEnd()) {
    e_usage(str533, loc::Missing);
  }
  for (int i = start_index; i < (num_items + 1); ++i) {
    item = readline->get_history_item(i);
    this->f->write(StrFormat("%5d  %s\n", i, item));
  }
  return 0;
}

}  // define namespace readline_osh

namespace trap_osh {  // define

using runtime_asdl::cmd_value;
using syntax_asdl::loc;
using syntax_asdl::source;
using mylib::print_stderr;

TrapState::TrapState(pyos::SignalSafe* signal_safe) {
  this->signal_safe = signal_safe;
  this->hooks = Alloc<Dict<BigStr*, syntax_asdl::command_t*>>();
  this->traps = Alloc<Dict<int, syntax_asdl::command_t*>>();
}

void TrapState::ClearForSubProgram() {
  this->hooks->clear();
  this->traps->clear();
}

syntax_asdl::command_t* TrapState::GetHook(BigStr* hook_name) {
  StackRoot _root0(&hook_name);

  return this->hooks->get(hook_name, nullptr);
}

void TrapState::AddUserHook(BigStr* hook_name, syntax_asdl::command_t* handler) {
  StackRoot _root0(&hook_name);
  StackRoot _root1(&handler);

  this->hooks->set(hook_name, handler);
}

void TrapState::RemoveUserHook(BigStr* hook_name) {
  StackRoot _root0(&hook_name);

  mylib::dict_erase(this->hooks, hook_name);
}

void TrapState::AddUserTrap(int sig_num, syntax_asdl::command_t* handler) {
  StackRoot _root0(&handler);

  this->traps->set(sig_num, handler);
  if (sig_num == SIGWINCH) {
    this->signal_safe->SetSigWinchCode(SIGWINCH);
  }
  else {
    pyos::RegisterSignalInterest(sig_num);
  }
}

void TrapState::RemoveUserTrap(int sig_num) {
  mylib::dict_erase(this->traps, sig_num);
  if (sig_num == SIGINT) {
    ;  // pass
  }
  else {
    if (sig_num == SIGWINCH) {
      this->signal_safe->SetSigWinchCode(pyos::UNTRAPPED_SIGWINCH);
    }
    else {
      pyos::Sigaction(sig_num, SIG_DFL);
    }
  }
}

List<syntax_asdl::command_t*>* TrapState::GetPendingTraps() {
  List<int>* signals = nullptr;
  List<syntax_asdl::command_t*>* run_list = nullptr;
  syntax_asdl::command_t* node = nullptr;
  StackRoot _root0(&signals);
  StackRoot _root1(&run_list);
  StackRoot _root2(&node);

  signals = this->signal_safe->TakePendingSignals();
  if (len(signals) == 0) {
    this->signal_safe->ReuseEmptyList(signals);
    return nullptr;
  }
  run_list = Alloc<List<syntax_asdl::command_t*>>();
  for (ListIter<int> it(signals); !it.Done(); it.Next()) {
    int sig_num = it.Value();
    node = this->traps->get(sig_num, nullptr);
    if (node != nullptr) {
      run_list->append(node);
    }
  }
  signals->clear();
  this->signal_safe->ReuseEmptyList(signals);
  return run_list;
}

int _GetSignalNumber(BigStr* sig_spec) {
  StackRoot _root0(&sig_spec);

  if ((str_equals(sig_spec->strip(), str535) || str_equals(sig_spec->strip(), str536) || str_equals(sig_spec->strip(), str537) || str_equals(sig_spec->strip(), str538) || str_equals(sig_spec->strip(), str539) || str_equals(sig_spec->strip(), str540) || str_equals(sig_spec->strip(), str541) || str_equals(sig_spec->strip(), str542))) {
    return to_int(sig_spec);
  }
  if (sig_spec->startswith(str543)) {
    sig_spec = sig_spec->slice(3);
  }
  return signal_def::GetNumber(sig_spec);
}
GLOBAL_LIST(_HOOK_NAMES, BigStr*, 4, {str544 COMMA str545 COMMA str546 COMMA str547});

Trap::Trap(trap_osh::TrapState* trap_state, parse_lib::ParseContext* parse_ctx, dev::Tracer* tracer, ui::ErrorFormatter* errfmt) {
  this->trap_state = trap_state;
  this->parse_ctx = parse_ctx;
  this->arena = parse_ctx->arena;
  this->tracer = tracer;
  this->errfmt = errfmt;
}

syntax_asdl::command_t* Trap::_ParseTrapCode(BigStr* code_str) {
  reader::FileLineReader* line_reader = nullptr;
  cmd_parse::CommandParser* c_parser = nullptr;
  source::ArgvWord* src = nullptr;
  syntax_asdl::command_t* node = nullptr;
  StackRoot _root0(&code_str);
  StackRoot _root1(&line_reader);
  StackRoot _root2(&c_parser);
  StackRoot _root3(&src);
  StackRoot _root4(&node);

  line_reader = reader::StringLineReader(code_str, this->arena);
  c_parser = this->parse_ctx->MakeOshParser(line_reader);
  src = Alloc<source::ArgvWord>(str548, loc::Missing);
  {  // with
    alloc::ctx_SourceCode ctx{this->arena, src};

    try {
      node = main_loop::ParseWholeFile(c_parser);
    }
    catch (error::Parse* e) {
      this->errfmt->PrettyPrintError(e);
      return nullptr;
    }
  }
  return node;
}

int Trap::Run(cmd_value::Argv* cmd_val) {
  args::_Attributes* attrs = nullptr;
  args::Reader* arg_r = nullptr;
  arg_types::trap* arg = nullptr;
  BigStr* code_str = nullptr;
  BigStr* sig_spec = nullptr;
  syntax_asdl::loc_t* sig_loc = nullptr;
  BigStr* sig_key = nullptr;
  int sig_num;
  syntax_asdl::command_t* node = nullptr;
  StackRoot _root0(&cmd_val);
  StackRoot _root1(&attrs);
  StackRoot _root2(&arg_r);
  StackRoot _root3(&arg);
  StackRoot _root4(&code_str);
  StackRoot _root5(&sig_spec);
  StackRoot _root6(&sig_loc);
  StackRoot _root7(&sig_key);
  StackRoot _root8(&node);

  Tuple2<args::_Attributes*, args::Reader*> tup0 = flag_util::ParseCmdVal(str549, cmd_val);
  attrs = tup0.at0();
  arg_r = tup0.at1();
  arg = Alloc<arg_types::trap>(attrs->attrs);
  if (arg->p) {
    for (DictIter<BigStr*, syntax_asdl::command_t*> it(this->trap_state->hooks); !it.Done(); it.Next()) {
      BigStr* name = it.Key();
      syntax_asdl::command_t* _ = it.Value();
      print(StrFormat("%s TrapState", name));
    }
    for (DictIter<int, syntax_asdl::command_t*> it(this->trap_state->traps); !it.Done(); it.Next()) {
      int sig_num = it.Key();
      syntax_asdl::command_t* _ = it.Value();
      print(StrFormat("%d TrapState", sig_num));
    }
    return 0;
  }
  if (arg->l) {
    for (ListIter<BigStr*> it(_HOOK_NAMES); !it.Done(); it.Next()) {
      BigStr* hook_name = it.Value();
      StackRoot _for(&hook_name    );
      print(StrFormat("   %s", hook_name));
    }
    signal_def::PrintSignals();
    return 0;
  }
  code_str = arg_r->ReadRequired(str553);
  Tuple2<BigStr*, syntax_asdl::loc_t*> tup1 = arg_r->ReadRequired2(str554);
  sig_spec = tup1.at0();
  sig_loc = tup1.at1();
  sig_key = nullptr;
  sig_num = signal_def::NO_SIGNAL;
  if (list_contains(_HOOK_NAMES, sig_spec)) {
    sig_key = sig_spec;
  }
  else {
    if (str_equals(sig_spec, str555)) {
      sig_key = str556;
    }
    else {
      sig_num = _GetSignalNumber(sig_spec);
      if (sig_num != signal_def::NO_SIGNAL) {
        sig_key = str(sig_num);
      }
    }
  }
  if (sig_key == nullptr) {
    this->errfmt->Print_(StrFormat("Invalid signal or hook %r", sig_spec), cmd_val->arg_locs->at(2));
    return 1;
  }
  if (str_equals(code_str, str558)) {
    if (list_contains(_HOOK_NAMES, sig_key)) {
      this->trap_state->RemoveUserHook(sig_key);
      return 0;
    }
    if (sig_num != signal_def::NO_SIGNAL) {
      this->trap_state->RemoveUserTrap(sig_num);
      return 0;
    }
    assert(0);  // AssertionError
  }
  node = this->_ParseTrapCode(code_str);
  if (node == nullptr) {
    return 1;
  }
  if (list_contains(_HOOK_NAMES, sig_key)) {
    if (str_equals(sig_key, str560)) {
      print_stderr(StrFormat("osh warning: The %r hook isn't implemented", sig_spec));
    }
    this->trap_state->AddUserHook(sig_key, node);
    return 0;
  }
  if (sig_num != signal_def::NO_SIGNAL) {
    if ((sig_num == SIGKILL || sig_num == SIGSTOP)) {
      this->errfmt->Print_(StrFormat("Signal %r can't be handled", sig_spec), sig_loc);
      return 1;
    }
    this->trap_state->AddUserTrap(sig_num, node);
    return 0;
  }
  assert(0);  // AssertionError
}

}  // define namespace trap_osh

namespace alloc {  // define

using syntax_asdl::source_t;
using syntax_asdl::Token;
using syntax_asdl::SourceLine;
using syntax_asdl::loc;

BigStr* SnipCodeBlock(syntax_asdl::Token* left, syntax_asdl::Token* right, List<syntax_asdl::SourceLine*>* lines) {
  List<BigStr*>* pieces = nullptr;
  BigStr* piece = nullptr;
  bool saving;
  bool found_left;
  bool found_right;
  StackRoot _root0(&left);
  StackRoot _root1(&right);
  StackRoot _root2(&lines);
  StackRoot _root3(&pieces);
  StackRoot _root4(&piece);

  pieces = Alloc<List<BigStr*>>();
  pieces->append(str_repeat(str564, (left->col + 1)));
  if (left->line == right->line) {
    for (ListIter<syntax_asdl::SourceLine*> it(lines); !it.Done(); it.Next()) {
      syntax_asdl::SourceLine* li = it.Value();
      StackRoot _for(&li    );
      if (li == left->line) {
        piece = li->content->slice((left->col + left->length), right->col);
        pieces->append(piece);
      }
    }
    return str565->join(pieces);
  }
  saving = false;
  found_left = false;
  found_right = false;
  for (ListIter<syntax_asdl::SourceLine*> it(lines); !it.Done(); it.Next()) {
    syntax_asdl::SourceLine* li = it.Value();
    StackRoot _for(&li  );
    if (li == left->line) {
      found_left = true;
      saving = true;
      piece = li->content->slice((left->col + left->length));
      pieces->append(piece);
      continue;
    }
    if (li == right->line) {
      found_right = true;
      piece = li->content->slice(0, right->col);
      pieces->append(piece);
      saving = false;
      break;
    }
    if (saving) {
      pieces->append(li->content);
    }
  }
  return str566->join(pieces);
}

ctx_SourceCode::ctx_SourceCode(alloc::Arena* arena, syntax_asdl::source_t* src) {
  gHeap.PushRoot(reinterpret_cast<RawObject**>(&(this->arena)));
  arena->PushSource(src);
  this->arena = arena;
}

ctx_SourceCode::~ctx_SourceCode() {
  this->arena->PopSource();
  gHeap.PopRoot();
}

Arena::Arena(bool save_tokens) {
  this->save_tokens = save_tokens;
  this->tokens = Alloc<List<syntax_asdl::Token*>>();
  this->num_tokens = 0;
  this->span_id_lookup = Alloc<Dict<syntax_asdl::Token*, int>>();
  this->lines_list = Alloc<List<syntax_asdl::SourceLine*>>();
  this->source_instances = Alloc<List<syntax_asdl::source_t*>>();
}

void Arena::SaveTokens() {
  this->save_tokens = true;
}

void Arena::PushSource(syntax_asdl::source_t* src) {
  StackRoot _root0(&src);

  this->source_instances->append(src);
}

void Arena::PopSource() {
  this->source_instances->pop();
}

syntax_asdl::SourceLine* Arena::AddLine(BigStr* line, int line_num) {
  syntax_asdl::SourceLine* src_line = nullptr;
  StackRoot _root0(&line);
  StackRoot _root1(&src_line);

  src_line = Alloc<SourceLine>(line_num, line, this->source_instances->at(-1));
  this->lines_list->append(src_line);
  return src_line;
}

void Arena::DiscardLines() {
  this->lines_list->clear();
}

List<syntax_asdl::SourceLine*>* Arena::SaveLinesAndDiscard(syntax_asdl::Token* left, syntax_asdl::Token* right) {
  List<syntax_asdl::SourceLine*>* saved = nullptr;
  bool saving;
  StackRoot _root0(&left);
  StackRoot _root1(&right);
  StackRoot _root2(&saved);

  saved = Alloc<List<syntax_asdl::SourceLine*>>();
  saving = false;
  for (ListIter<syntax_asdl::SourceLine*> it(this->lines_list); !it.Done(); it.Next()) {
    syntax_asdl::SourceLine* li = it.Value();
    StackRoot _for(&li  );
    if (li == left->line) {
      saving = true;
    }
    if (saving) {
      saved->append(li);
    }
    if (li == right->line) {
      saving = false;
      break;
    }
  }
  this->DiscardLines();
  return saved;
}

BigStr* Arena::SnipCodeString(syntax_asdl::Token* left, syntax_asdl::Token* right) {
  BigStr* piece = nullptr;
  List<BigStr*>* pieces = nullptr;
  bool saving;
  bool found_left;
  bool found_right;
  StackRoot _root0(&left);
  StackRoot _root1(&right);
  StackRoot _root2(&piece);
  StackRoot _root3(&pieces);

  if (left->line == right->line) {
    for (ListIter<syntax_asdl::SourceLine*> it(this->lines_list); !it.Done(); it.Next()) {
      syntax_asdl::SourceLine* li = it.Value();
      StackRoot _for(&li    );
      if (li == left->line) {
        piece = li->content->slice(left->col, (right->col + right->length));
        return piece;
      }
    }
  }
  pieces = Alloc<List<BigStr*>>();
  saving = false;
  found_left = false;
  found_right = false;
  for (ListIter<syntax_asdl::SourceLine*> it(this->lines_list); !it.Done(); it.Next()) {
    syntax_asdl::SourceLine* li = it.Value();
    StackRoot _for(&li  );
    if (li == left->line) {
      found_left = true;
      saving = true;
      piece = li->content->slice(left->col);
      pieces->append(piece);
      continue;
    }
    if (li == right->line) {
      found_right = true;
      piece = li->content->slice(0, (right->col + right->length));
      pieces->append(piece);
      saving = false;
      break;
    }
    if (saving) {
      pieces->append(li->content);
    }
  }
  return str567->join(pieces);
}

syntax_asdl::Token* Arena::NewToken(int id_, int col, int length, syntax_asdl::SourceLine* src_line) {
  syntax_asdl::Token* tok = nullptr;
  int span_id;
  StackRoot _root0(&src_line);
  StackRoot _root1(&tok);

  if (length >= 65536) {
    throw Alloc<error::Parse>(str568, Alloc<loc::TokenTooLong>(src_line, id_, length, col));
  }
  tok = Alloc<Token>(id_, length, col, src_line, nullptr);
  if (this->save_tokens) {
    span_id = this->num_tokens;
    this->num_tokens += 1;
    this->tokens->append(tok);
    this->span_id_lookup->set(tok, span_id);
  }
  return tok;
}

void Arena::UnreadOne() {
  if (this->save_tokens) {
    this->tokens->pop();
    this->num_tokens -= 1;
  }
}

syntax_asdl::Token* Arena::GetToken(int span_id) {
  return this->tokens->at(span_id);
}

int Arena::GetSpanId(syntax_asdl::Token* tok) {
  StackRoot _root0(&tok);

  return this->span_id_lookup->at(tok);
}

int Arena::LastSpanId() {
  return len(this->tokens);
}

}  // define namespace alloc

namespace ansi {  // define

BigStr* RESET = str569;
BigStr* BOLD = str570;
BigStr* UNDERLINE = str571;
BigStr* REVERSE = str572;
BigStr* RED = str573;
BigStr* GREEN = str574;
BigStr* YELLOW = str575;
BigStr* BLUE = str576;
BigStr* MAGENTA = str577;
BigStr* CYAN = str578;

}  // define namespace ansi

namespace comp_ui {  // define


int _PromptLen(BigStr* prompt_str) {
  bool escaped;
  BigStr* display_str = nullptr;
  BigStr* last_line = nullptr;
  StackRoot _root0(&prompt_str);
  StackRoot _root1(&display_str);
  StackRoot _root2(&last_line);

  escaped = false;
  display_str = str579;
  for (StrIter it(prompt_str); !it.Done(); it.Next()) {
    BigStr* c = it.Value();
    StackRoot _for(&c  );
    if (str_equals(c, str580)) {
      escaped = true;
    }
    else {
      if (str_equals(c, str581)) {
        escaped = false;
      }
      else {
        if (!escaped) {
          display_str = str_concat(display_str, c);
        }
      }
    }
  }
  last_line = display_str->split(str582)->at(-1);
  return pretty::TryUnicodeWidth(last_line);
}

PromptState::PromptState() {
  this->last_prompt_str = nullptr;
  this->last_prompt_len = -1;
}

void PromptState::SetLastPrompt(BigStr* prompt_str) {
  StackRoot _root0(&prompt_str);

  this->last_prompt_str = prompt_str;
  this->last_prompt_len = _PromptLen(prompt_str);
}

State::State() {
  this->line_until_tab = nullptr;
  this->display_pos = -1;
  this->descriptions = Alloc<Dict<BigStr*, BigStr*>>();
}

_IDisplay::_IDisplay(comp_ui::State* comp_state, comp_ui::PromptState* prompt_state, int num_lines_cap, mylib::Writer* f, util::_DebugFile* debug_f) {
  this->comp_state = comp_state;
  this->prompt_state = prompt_state;
  this->num_lines_cap = num_lines_cap;
  this->f = f;
  this->debug_f = debug_f;
}

void _IDisplay::PrintCandidates(BigStr* unused_subst, List<BigStr*>* matches, int unused_match_len) {
  StackRoot _root0(&unused_subst);
  StackRoot _root1(&matches);

  try {
    this->_PrintCandidates(unused_subst, matches, unused_match_len);
  }
  catch (Exception*) {
  }
}

void _IDisplay::_PrintCandidates(BigStr* unused_subst, List<BigStr*>* matches, int unused_match_len) {
  StackRoot _root0(&unused_subst);
  StackRoot _root1(&matches);

  FAIL(kNotImplemented);  // Python NotImplementedError
}

void _IDisplay::Reset() {
  ;  // pass
}

void _IDisplay::ShowPromptOnRight(BigStr* rendered) {
  StackRoot _root0(&rendered);

  ;  // pass
}

void _IDisplay::EraseLines() {
  ;  // pass
}

MinimalDisplay::MinimalDisplay(comp_ui::State* comp_state, comp_ui::PromptState* prompt_state, util::_DebugFile* debug_f) : ::comp_ui::_IDisplay(comp_state, prompt_state, 10, mylib::Stdout(), debug_f) {
  this->reader = nullptr;
}

void MinimalDisplay::_RedrawPrompt() {
  this->f->write(this->prompt_state->last_prompt_str);
  this->f->write(this->comp_state->line_until_tab);
}

void MinimalDisplay::_PrintCandidates(BigStr* unused_subst, List<BigStr*>* matches, int unused_match_len) {
  int display_pos;
  bool too_many;
  int i;
  int num_left;
  StackRoot _root0(&unused_subst);
  StackRoot _root1(&matches);

  this->f->write(str583);
  display_pos = this->comp_state->display_pos;
  too_many = false;
  i = 0;
  for (ListIter<BigStr*> it(matches); !it.Done(); it.Next()) {
    BigStr* m = it.Value();
    StackRoot _for(&m  );
    this->f->write(StrFormat(" %s\n", m->slice(display_pos)));
    if (i == this->num_lines_cap) {
      too_many = true;
      i += 1;
      break;
    }
    i += 1;
  }
  if (too_many) {
    num_left = (len(matches) - i);
    if (num_left) {
      this->f->write(StrFormat(" ... and %d more\n", num_left));
    }
  }
  this->_RedrawPrompt();
}

int _PrintPacked(List<BigStr*>* matches, int max_match_len, int term_width, int max_lines, mylib::Writer* f) {
  int w;
  int num_per_line;
  BigStr* fmt = nullptr;
  int num_lines;
  bool too_many;
  int remainder;
  int i;
  BigStr* fmt2 = nullptr;
  int num_left;
  StackRoot _root0(&matches);
  StackRoot _root1(&f);
  StackRoot _root2(&fmt);
  StackRoot _root3(&fmt2);

  w = (max_match_len + 2);
  num_per_line = max(1, ((term_width - 2) / w));
  fmt = str_concat(str_concat(str586, str(w)), str587);
  num_lines = 0;
  too_many = false;
  remainder = (num_per_line - 1);
  i = 0;
  for (ListIter<BigStr*> it(matches); !it.Done(); it.Next()) {
    BigStr* m = it.Value();
    StackRoot _for(&m  );
    if ((i % num_per_line) == 0) {
      f->write(str588);
    }
    f->write(StrFormat(fmt, m));
    if ((i % num_per_line) == remainder) {
      f->write(str589);
      num_lines += 1;
      if (num_lines == max_lines) {
        too_many = true;
        i += 1;
        break;
      }
    }
    i += 1;
  }
  if ((i % num_per_line) != 0) {
    f->write(str590);
    num_lines += 1;
  }
  if (too_many) {
    fmt2 = str_concat(str_concat(str_concat(str_concat(str_concat(ansi::BOLD, ansi::BLUE), str591), str((term_width - 2))), str592), ansi::RESET);
    num_left = (len(matches) - i);
    if (num_left) {
      f->write(StrFormat(StrFormat(fmt2, str593), num_left));
      num_lines += 1;
    }
  }
  return num_lines;
}

int _PrintLong(List<BigStr*>* matches, int max_match_len, int term_width, int max_lines, Dict<BigStr*, BigStr*>* descriptions, mylib::Writer* f) {
  int max_desc;
  BigStr* fmt = nullptr;
  int num_lines;
  BigStr* desc = nullptr;
  BigStr* fmt2 = nullptr;
  int num_left;
  StackRoot _root0(&matches);
  StackRoot _root1(&descriptions);
  StackRoot _root2(&f);
  StackRoot _root3(&fmt);
  StackRoot _root4(&desc);
  StackRoot _root5(&fmt2);

  max_desc = max(0, ((term_width - max_match_len) - 3));
  fmt = str_concat(str_concat(str_concat(str_concat(str_concat(str_concat(str594, str(max_match_len)), str595), ansi::YELLOW), str596), ansi::RESET), str597);
  num_lines = 0;
  for (ListIter<BigStr*> it(matches); !it.Done(); it.Next()) {
    BigStr* rl_match = it.Value();
    StackRoot _for(&rl_match  );
    desc = descriptions->get(rl_match);
    if (desc == nullptr) {
      desc = str598;
    }
    if (max_desc == 0) {
      f->write(StrFormat(" %s\n", rl_match));
    }
    else {
      if (len(desc) > max_desc) {
        desc = str_concat(desc->slice(0, (max_desc - 5)), str600);
      }
      f->write(StrFormat(fmt, rl_match, desc));
    }
    num_lines += 1;
    if (num_lines == max_lines) {
      fmt2 = str_concat(str_concat(str_concat(str_concat(str_concat(ansi::BOLD, ansi::BLUE), str601), str((term_width - 1))), str602), ansi::RESET);
      num_left = (len(matches) - num_lines);
      if (num_left) {
        f->write(StrFormat(StrFormat(fmt2, str603), num_left));
        num_lines += 1;
      }
      break;
    }
  }
  return num_lines;
}

NiceDisplay::NiceDisplay(int term_width, comp_ui::State* comp_state, comp_ui::PromptState* prompt_state, util::_DebugFile* debug_f, py_readline::Readline* readline, pyos::SignalSafe* signal_safe) : ::comp_ui::_IDisplay(comp_state, prompt_state, 10, mylib::Stdout(), debug_f) {
  this->term_width = term_width;
  this->readline = readline;
  this->signal_safe = signal_safe;
  this->bold_line = false;
  this->num_lines_last_displayed = 0;
  this->c_count = 0;
  this->m_count = 0;
  this->dupes = Alloc<Dict<int, int>>();
}

void NiceDisplay::Reset() {
  this->num_lines_last_displayed = 0;
  this->dupes->clear();
}

void NiceDisplay::_ReturnToPrompt(int num_lines) {
  int orig_len;
  int last_prompt_len;
  int n;
  orig_len = len(this->comp_state->line_until_tab);
  this->f->write(StrFormat("\u001b[%dA", num_lines));
  last_prompt_len = this->prompt_state->last_prompt_len;
  n = (orig_len + last_prompt_len);
  n = (n % this->_GetTerminalWidth());
  this->f->write(StrFormat("\u001b[%dC", n));
  if (this->bold_line) {
    this->f->write(ansi::BOLD);
  }
  this->f->flush();
}

void NiceDisplay::_PrintCandidates(BigStr* unused_subst, List<BigStr*>* matches, int unused_max_match_len) {
  int term_width;
  int display_pos;
  int comp_id;
  int max_lines;
  List<BigStr*>* to_display = nullptr;
  List<int>* lens = nullptr;
  int max_match_len;
  int num_lines;
  StackRoot _root0(&unused_subst);
  StackRoot _root1(&matches);
  StackRoot _root2(&to_display);
  StackRoot _root3(&lens);

  term_width = this->_GetTerminalWidth();
  display_pos = this->comp_state->display_pos;
  this->debug_f->write(StrFormat("DISPLAY POS in _PrintCandidates = %d\n", display_pos));
  this->f->write(str607);
  this->EraseLines();
  comp_id = hash(str608->join(matches));
  if (dict_contains(this->dupes, comp_id)) {
    this->dupes->set(comp_id, (this->dupes->at(comp_id) + 1));
  }
  else {
    this->dupes->clear();
    this->dupes->set(comp_id, 1);
  }
  max_lines = (this->num_lines_cap * this->dupes->at(comp_id));
  if (display_pos == 0) {
    to_display = matches;
  }
  else {
    to_display = Alloc<List<BigStr*>>();
    for (ListIter<BigStr*> it(matches); !it.Done(); it.Next()) {
      BigStr* m = it.Value();
      to_display->append(m->slice(display_pos));
    }
  }
  lens = Alloc<List<int>>();
  for (ListIter<BigStr*> it(to_display); !it.Done(); it.Next()) {
    BigStr* m = it.Value();
    lens->append(len(m));
  }
  max_match_len = max(lens);
  if ((this->comp_state->descriptions != nullptr and len(this->comp_state->descriptions) > 0)) {
    num_lines = _PrintLong(to_display, max_match_len, term_width, max_lines, this->comp_state->descriptions, this->f);
  }
  else {
    num_lines = _PrintPacked(to_display, max_match_len, term_width, max_lines, this->f);
  }
  this->_ReturnToPrompt((num_lines + 1));
  this->num_lines_last_displayed = num_lines;
  this->c_count += 1;
}

void NiceDisplay::ShowPromptOnRight(BigStr* rendered) {
  int n;
  BigStr* spaces = nullptr;
  StackRoot _root0(&rendered);
  StackRoot _root1(&spaces);

  n = ((this->_GetTerminalWidth() - 2) - len(rendered));
  spaces = str_repeat(str609, n);
  this->f->write(str_concat(str_concat(str_concat(str_concat(str_concat(str_concat(spaces, ansi::REVERSE), str610), rendered), str611), ansi::RESET), str612));
}

void NiceDisplay::EraseLines() {
  int n;
  if (this->bold_line) {
    this->f->write(ansi::RESET);
    this->f->flush();
  }
  n = this->num_lines_last_displayed;
  if (n == 0) {
    return ;
  }
  for (int i = 0; i < n; ++i) {
    this->f->write(str613);
    this->f->write(str614);
  }
  this->f->write(StrFormat("\u001b[%dA", n));
  this->f->flush();
}

int NiceDisplay::_GetTerminalWidth() {
  if (this->signal_safe->PollSigWinch()) {
    try {
      this->term_width = libc::get_terminal_width();
    }
    catch (IOError_OSError*) {
      this->term_width = 80;
    }
  }
  return this->term_width;
}

void ExecutePrintCandidates(comp_ui::_IDisplay* display, BigStr* sub, List<BigStr*>* matches, int max_len) {
  StackRoot _root0(&display);
  StackRoot _root1(&sub);
  StackRoot _root2(&matches);

  display->PrintCandidates(sub, matches, max_len);
}

void InitReadline(py_readline::Readline* readline, BigStr* hist_file, completion::RootCompleter* root_comp, comp_ui::_IDisplay* display, util::_DebugFile* debug_f) {
  completion::ReadlineCallback* complete_cb = nullptr;
  StackRoot _root0(&readline);
  StackRoot _root1(&hist_file);
  StackRoot _root2(&root_comp);
  StackRoot _root3(&display);
  StackRoot _root4(&debug_f);
  StackRoot _root5(&complete_cb);

  if (hist_file != nullptr) {
    try {
      readline->read_history_file(hist_file);
    }
    catch (IOError_OSError*) {
      ;  // pass
    }
  }
  readline->parse_and_bind(str616);
  readline->parse_and_bind(str617);
  complete_cb = Alloc<completion::ReadlineCallback>(readline, root_comp, debug_f);
  readline->set_completer(complete_cb);
  readline->set_completer_delims(str618);
  readline->set_completion_display_matches_hook(display);
}

}  // define namespace comp_ui

namespace completion {  // define

using id_kind_asdl::Id;
using syntax_asdl::CompoundWord;
using syntax_asdl::word_part_e;
using syntax_asdl::word_t;
using syntax_asdl::redir_param_e;
using syntax_asdl::Token;
using runtime_asdl::scope_e;
using runtime_asdl::comp_action_e;
using runtime_asdl::comp_action_t;
using types_asdl::redir_arg_type_e;
using value_asdl::value;
using value_asdl::value_e;
using mylib::print_stderr;
using string_ops::ShellQuoteB;

_RetryCompletion::_RetryCompletion() {
  ;  // pass
}
int CH_Break = 0;
int CH_Other = 1;
int ST_Begin = 0;
int ST_Break = 1;
int ST_Other = 2;

Tuple2<int, bool> _TRANSITIONS(int state, int ch) {
  if ((state == ST_Begin and ch == CH_Break)) {
    return Tuple2<int, bool>(ST_Break, false);
  }
  if ((state == ST_Begin and ch == CH_Other)) {
    return Tuple2<int, bool>(ST_Other, false);
  }
  if ((state == ST_Break and ch == CH_Break)) {
    return Tuple2<int, bool>(ST_Break, false);
  }
  if ((state == ST_Break and ch == CH_Other)) {
    return Tuple2<int, bool>(ST_Other, true);
  }
  if ((state == ST_Other and ch == CH_Break)) {
    return Tuple2<int, bool>(ST_Break, true);
  }
  if ((state == ST_Other and ch == CH_Other)) {
    return Tuple2<int, bool>(ST_Other, false);
  }
  throw Alloc<ValueError>(str619);
}

void AdjustArg(BigStr* arg, List<BigStr*>* break_chars, List<BigStr*>* argv_out) {
  List<int>* end_indices = nullptr;
  int state;
  int i;
  int ch;
  bool emit_span;
  int begin;
  StackRoot _root0(&arg);
  StackRoot _root1(&break_chars);
  StackRoot _root2(&argv_out);
  StackRoot _root3(&end_indices);

  end_indices = Alloc<List<int>>();
  state = ST_Begin;
  i = 0;
  for (StrIter it(arg); !it.Done(); it.Next(), ++i) {
    BigStr* c = it.Value();
    StackRoot _for(&c  );
    ch = list_contains(break_chars, c) ? CH_Break : CH_Other;
    Tuple2<int, bool> tup0 = _TRANSITIONS(state, ch);
    state = tup0.at0();
    emit_span = tup0.at1();
    if (emit_span) {
      end_indices->append(i);
    }
  }
  end_indices->append(len(arg));
  begin = 0;
  for (ListIter<int> it(end_indices); !it.Done(); it.Next()) {
    int end = it.Value();
    argv_out->append(arg->slice(begin, end));
    begin = end;
  }
}
GLOBAL_DICT(_DEFAULT_OPTS, BigStr*, bool, 0, {}, {});

OptionState::OptionState() {
  this->currently_completing = false;
  this->dynamic_opts = nullptr;
}

ctx_Completing::ctx_Completing(completion::OptionState* compopt_state) {
  gHeap.PushRoot(reinterpret_cast<RawObject**>(&(this->compopt_state)));
  compopt_state->currently_completing = true;
  this->compopt_state = compopt_state;
}

ctx_Completing::~ctx_Completing() {
  this->compopt_state->currently_completing = false;
  gHeap.PopRoot();
}

void _PrintOpts(Dict<BigStr*, bool>* opts, mylib::BufWriter* f) {
  StackRoot _root0(&opts);
  StackRoot _root1(&f);

  f->write(str620);
  for (DictIter<BigStr*, bool> it(opts); !it.Done(); it.Next()) {
    BigStr* k = it.Key();
    bool v = it.Value();
    f->write(StrFormat(" %s=%s", k, v ? str622 : str623));
  }
  f->write(str624);
}

Lookup::Lookup() {
  completion::UserSpec* empty_spec = Alloc<UserSpec>(Alloc<List<completion::CompletionAction*>>(), Alloc<List<completion::CompletionAction*>>(), Alloc<List<completion::CompletionAction*>>(), Alloc<DefaultPredicate>(), str625, str626);
  Tuple2<Dict<BigStr*, bool>*, completion::UserSpec*>* do_nothing = (Alloc<Tuple2<Dict<BigStr*, bool>*, completion::UserSpec*>>(_DEFAULT_OPTS, empty_spec));
  this->lookup = Alloc<Dict<BigStr*, Tuple2<Dict<BigStr*, bool>*, completion::UserSpec*>*>>(std::initializer_list<BigStr*>{str627, str628}, std::initializer_list<Tuple2<Dict<BigStr*, bool>*, completion::UserSpec*>*>{do_nothing, do_nothing});
  this->commands_with_spec_changes = Alloc<List<BigStr*>>();
  this->patterns = Alloc<List<Tuple3<BigStr*, Dict<BigStr*, bool>*, completion::UserSpec*>*>>();
}

BigStr* Lookup::__str__() {
  return StrFormat("<completion.Lookup %s>", this->lookup);
}

void Lookup::PrintSpecs() {
  mylib::BufWriter* f = nullptr;
  Dict<BigStr*, bool>* base_opts = nullptr;
  completion::UserSpec* user_spec = nullptr;
  BigStr* pat = nullptr;
  completion::UserSpec* spec = nullptr;
  StackRoot _root0(&f);
  StackRoot _root1(&base_opts);
  StackRoot _root2(&user_spec);
  StackRoot _root3(&pat);
  StackRoot _root4(&spec);

  f = Alloc<mylib::BufWriter>();
  f->write(str630);
  for (ListIter<BigStr*> it(sorted(this->lookup)); !it.Done(); it.Next()) {
    BigStr* name = it.Value();
    StackRoot _for(&name  );
    Tuple2<Dict<BigStr*, bool>*, completion::UserSpec*>* tup1 = this->lookup->at(name);
    base_opts = tup1->at0();
    user_spec = tup1->at1();
    f->write(StrFormat("%s:\n", name));
    _PrintOpts(base_opts, f);
    user_spec->PrintSpec(f);
  }
  f->write(str632);
  for (ListIter<Tuple3<BigStr*, Dict<BigStr*, bool>*, completion::UserSpec*>*> it(this->patterns); !it.Done(); it.Next()) {
    Tuple3<BigStr*, Dict<BigStr*, bool>*, completion::UserSpec*>* tup2 = it.Value();
    pat = tup2->at0();
    base_opts = tup2->at1();
    spec = tup2->at2();
    f->write(StrFormat("%s:\n", pat));
    _PrintOpts(base_opts, f);
    user_spec->PrintSpec(f);
  }
  print_stderr(f->getvalue());
}

void Lookup::ClearCommandsChanged() {
  this->commands_with_spec_changes->clear();
}

List<BigStr*>* Lookup::GetCommandsChanged() {
  return this->commands_with_spec_changes;
}

void Lookup::RegisterName(BigStr* name, Dict<BigStr*, bool>* base_opts, completion::UserSpec* user_spec) {
  StackRoot _root0(&name);
  StackRoot _root1(&base_opts);
  StackRoot _root2(&user_spec);

  this->lookup->set(name, (Alloc<Tuple2<Dict<BigStr*, bool>*, completion::UserSpec*>>(base_opts, user_spec)));
  if ((!str_equals(name, str634) && !str_equals(name, str635))) {
    this->commands_with_spec_changes->append(name);
  }
}

void Lookup::RegisterGlob(BigStr* glob_pat, Dict<BigStr*, bool>* base_opts, completion::UserSpec* user_spec) {
  StackRoot _root0(&glob_pat);
  StackRoot _root1(&base_opts);
  StackRoot _root2(&user_spec);

  this->patterns->append((Alloc<Tuple3<BigStr*, Dict<BigStr*, bool>*, completion::UserSpec*>>(glob_pat, base_opts, user_spec)));
}

Tuple2<Dict<BigStr*, bool>*, completion::UserSpec*> Lookup::GetSpecForName(BigStr* argv0) {
  Tuple2<Dict<BigStr*, bool>*, completion::UserSpec*>* pair = nullptr;
  Dict<BigStr*, bool>* a = nullptr;
  completion::UserSpec* b = nullptr;
  BigStr* key = nullptr;
  BigStr* glob_pat = nullptr;
  Dict<BigStr*, bool>* base_opts = nullptr;
  completion::UserSpec* user_spec = nullptr;
  StackRoot _root0(&argv0);
  StackRoot _root1(&pair);
  StackRoot _root2(&a);
  StackRoot _root3(&b);
  StackRoot _root4(&key);
  StackRoot _root5(&glob_pat);
  StackRoot _root6(&base_opts);
  StackRoot _root7(&user_spec);

  pair = this->lookup->get(argv0);
  if (pair) {
    Tuple2<Dict<BigStr*, bool>*, completion::UserSpec*>* tup3 = pair;
    a = tup3->at0();
    b = tup3->at1();
    return Tuple2<Dict<BigStr*, bool>*, completion::UserSpec*>(a, b);
  }
  key = os_path::basename(argv0);
  pair = this->lookup->get(key);
  if (pair) {
    Tuple2<Dict<BigStr*, bool>*, completion::UserSpec*>* tup4 = pair;
    a = tup4->at0();
    b = tup4->at1();
    return Tuple2<Dict<BigStr*, bool>*, completion::UserSpec*>(a, b);
  }
  for (ListIter<Tuple3<BigStr*, Dict<BigStr*, bool>*, completion::UserSpec*>*> it(this->patterns); !it.Done(); it.Next()) {
    Tuple3<BigStr*, Dict<BigStr*, bool>*, completion::UserSpec*>* tup5 = it.Value();
    glob_pat = tup5->at0();
    base_opts = tup5->at1();
    user_spec = tup5->at2();
    if (libc::fnmatch(glob_pat, key)) {
      return Tuple2<Dict<BigStr*, bool>*, completion::UserSpec*>(base_opts, user_spec);
    }
  }
  return Tuple2<Dict<BigStr*, bool>*, completion::UserSpec*>(nullptr, nullptr);
}

Tuple2<Dict<BigStr*, bool>*, completion::UserSpec*> Lookup::GetFirstSpec() {
  Dict<BigStr*, bool>* a = nullptr;
  completion::UserSpec* b = nullptr;
  StackRoot _root0(&a);
  StackRoot _root1(&b);

  Tuple2<Dict<BigStr*, bool>*, completion::UserSpec*>* tup6 = this->lookup->at(str636);
  a = tup6->at0();
  b = tup6->at1();
  return Tuple2<Dict<BigStr*, bool>*, completion::UserSpec*>(a, b);
}

Tuple2<Dict<BigStr*, bool>*, completion::UserSpec*> Lookup::GetFallback() {
  Dict<BigStr*, bool>* a = nullptr;
  completion::UserSpec* b = nullptr;
  StackRoot _root0(&a);
  StackRoot _root1(&b);

  Tuple2<Dict<BigStr*, bool>*, completion::UserSpec*>* tup7 = this->lookup->at(str637);
  a = tup7->at0();
  b = tup7->at1();
  return Tuple2<Dict<BigStr*, bool>*, completion::UserSpec*>(a, b);
}

Api::Api(BigStr* line, int begin, int end) {
  this->line = line;
  this->begin = begin;
  this->end = end;
  this->first = nullptr;
  this->to_complete = nullptr;
  this->prev = nullptr;
  this->index = -1;
  this->partial_argv = Alloc<List<BigStr*>>();
}

void Api::Update(BigStr* first, BigStr* to_complete, BigStr* prev, int index, List<BigStr*>* partial_argv) {
  StackRoot _root0(&first);
  StackRoot _root1(&to_complete);
  StackRoot _root2(&prev);
  StackRoot _root3(&partial_argv);

  this->first = first;
  this->to_complete = to_complete;
  this->prev = prev;
  this->index = index;
  this->partial_argv = partial_argv;
  if (this->partial_argv == nullptr) {
    this->partial_argv = Alloc<List<BigStr*>>();
  }
}

CompletionAction::CompletionAction() {
  ;  // pass
}

void CompletionAction::Matches(completion::Api* comp, List<BigStr*>* _out_yield_acc) {
  StackRoot _root0(&comp);

  ;  // pass
}

runtime_asdl::comp_action_t CompletionAction::ActionKind() {
  return comp_action_e::Other;
}

void CompletionAction::Print(mylib::BufWriter* f) {
  StackRoot _root0(&f);

  f->write(str639);
}

UsersAction::UsersAction() {
  ;  // pass
}

void UsersAction::Matches(completion::Api* comp, List<BigStr*>* _out_yield_acc) {
  BigStr* name = nullptr;
  StackRoot _root0(&comp);
  StackRoot _root1(&name);

  for (ListIter<pyos::PasswdEntry*> it(pyos::GetAllUsers()); !it.Done(); it.Next()) {
    pyos::PasswdEntry* u = it.Value();
    StackRoot _for(&u  );
    name = u->pw_name;
    if (name->startswith(comp->to_complete)) {
            _out_yield_acc->append(name);
;
    }
  }
}

void UsersAction::Print(mylib::BufWriter* f) {
  StackRoot _root0(&f);

  f->write(str640);
}

TestAction::TestAction(List<BigStr*>* words, double delay) {
  this->words = words;
  this->delay = delay;
}

void TestAction::Matches(completion::Api* comp, List<BigStr*>* _out_yield_acc) {
  StackRoot _root0(&comp);

  for (ListIter<BigStr*> it(this->words); !it.Done(); it.Next()) {
    BigStr* w = it.Value();
    StackRoot _for(&w  );
    if (w->startswith(comp->to_complete)) {
      if (this->delay != 0.0) {
        time_::sleep(this->delay);
      }
            _out_yield_acc->append(w);
;
    }
  }
}

void TestAction::Print(mylib::BufWriter* f) {
  StackRoot _root0(&f);

  f->write(str641);
}

DynamicWordsAction::DynamicWordsAction(word_eval::AbstractWordEvaluator* word_ev, split::SplitContext* splitter, syntax_asdl::CompoundWord* arg_word, ui::ErrorFormatter* errfmt) {
  this->word_ev = word_ev;
  this->splitter = splitter;
  this->arg_word = arg_word;
  this->errfmt = errfmt;
}

void DynamicWordsAction::Matches(completion::Api* comp, List<BigStr*>* _out_yield_acc) {
  value::Str* val = nullptr;
  List<BigStr*>* candidates = nullptr;
  StackRoot _root0(&comp);
  StackRoot _root1(&val);
  StackRoot _root2(&candidates);

  try {
    val = this->word_ev->EvalWordToString(this->arg_word);
  }
  catch (error::FatalRuntime* e) {
    this->errfmt->PrettyPrintError(e);
    throw ;
  }
  candidates = this->splitter->SplitForWordEval(val->s);
  for (ListIter<BigStr*> it(candidates); !it.Done(); it.Next()) {
    BigStr* c = it.Value();
    StackRoot _for(&c  );
    if (c->startswith(comp->to_complete)) {
            _out_yield_acc->append(c);
;
    }
  }
}

void DynamicWordsAction::Print(mylib::BufWriter* f) {
  StackRoot _root0(&f);

  f->write(str642);
}

FileSystemAction::FileSystemAction(bool dirs_only, bool exec_only, bool add_slash) {
  this->dirs_only = dirs_only;
  this->exec_only = exec_only;
  this->add_slash = add_slash;
}

runtime_asdl::comp_action_t FileSystemAction::ActionKind() {
  return comp_action_e::FileSystem;
}

void FileSystemAction::Print(mylib::BufWriter* f) {
  StackRoot _root0(&f);

  f->write(str643);
}

void FileSystemAction::Matches(completion::Api* comp, List<BigStr*>* _out_yield_acc) {
  BigStr* to_complete = nullptr;
  BigStr* dirname = nullptr;
  BigStr* basename = nullptr;
  BigStr* to_list = nullptr;
  List<BigStr*>* names = nullptr;
  BigStr* path = nullptr;
  StackRoot _root0(&comp);
  StackRoot _root1(&to_complete);
  StackRoot _root2(&dirname);
  StackRoot _root3(&basename);
  StackRoot _root4(&to_list);
  StackRoot _root5(&names);
  StackRoot _root6(&path);

  to_complete = comp->to_complete;
  Tuple2<BigStr*, BigStr*> tup8 = os_path::split(to_complete);
  dirname = tup8.at0();
  basename = tup8.at1();
  if (str_equals(dirname, str644)) {
    to_list = str645;
  }
  else {
    to_list = dirname;
  }
  try {
    names = posix::listdir(to_list);
  }
  catch (IOError_OSError* e) {
    return ;
  }
  for (ListIter<BigStr*> it(names); !it.Done(); it.Next()) {
    BigStr* name = it.Value();
    StackRoot _for(&name  );
    path = os_path::join(dirname, name);
    if (path->startswith(to_complete)) {
      if (this->dirs_only) {
        if (path_stat::isdir(path)) {
                    _out_yield_acc->append(path);
;
        }
        continue;
      }
      if (this->exec_only) {
        if (!posix::access(path, X_OK)) {
          continue;
        }
      }
      if ((this->add_slash and path_stat::isdir(path))) {
        path = str_concat(path, str649);
                _out_yield_acc->append(path);
;
      }
      else {
                _out_yield_acc->append(path);
;
      }
    }
  }
}

CommandAction::CommandAction(cmd_eval::CommandEvaluator* cmd_ev, BigStr* command_name) {
  this->cmd_ev = cmd_ev;
  this->command_name = command_name;
}

void CommandAction::Matches(completion::Api* comp, List<BigStr*>* _out_yield_acc) {
  StackRoot _root0(&comp);

  for (ListIter<BigStr*> it(NewList<BigStr*>(std::initializer_list<BigStr*>{str650})); !it.Done(); it.Next()) {
    BigStr* candidate = it.Value();
    StackRoot _for(&candidate  );
        _out_yield_acc->append(candidate);
;
  }
}

ShellFuncAction::ShellFuncAction(cmd_eval::CommandEvaluator* cmd_ev, value::Proc* func, completion::Lookup* comp_lookup) {
  this->cmd_ev = cmd_ev;
  this->func = func;
  this->comp_lookup = comp_lookup;
}

void ShellFuncAction::Print(mylib::BufWriter* f) {
  StackRoot _root0(&f);

  f->write(StrFormat("[ShellFuncAction %s] ", this->func->name));
}

runtime_asdl::comp_action_t ShellFuncAction::ActionKind() {
  return comp_action_e::BashFunc;
}

void ShellFuncAction::debug(BigStr* msg) {
  StackRoot _root0(&msg);

  this->cmd_ev->debug_f->writeln(msg);
}

void ShellFuncAction::Matches(completion::Api* comp, List<BigStr*>* _out_yield_acc) {
  List<BigStr*>* comp_words = nullptr;
  int comp_cword;
  List<BigStr*>* argv = nullptr;
  int status;
  List<BigStr*>* commands_changed = nullptr;
  BigStr* cmd = nullptr;
  value_asdl::value_t* val = nullptr;
  value::BashArray* array_val = nullptr;
  StackRoot _root0(&comp);
  StackRoot _root1(&comp_words);
  StackRoot _root2(&argv);
  StackRoot _root3(&commands_changed);
  StackRoot _root4(&cmd);
  StackRoot _root5(&val);
  StackRoot _root6(&array_val);

  state::SetGlobalArray(this->cmd_ev->mem, str652, Alloc<List<BigStr*>>());
  state::SetGlobalArray(this->cmd_ev->mem, str653, comp->partial_argv);
  comp_words = Alloc<List<BigStr*>>();
  for (ListIter<BigStr*> it(comp->partial_argv); !it.Done(); it.Next()) {
    BigStr* a = it.Value();
    StackRoot _for(&a  );
    AdjustArg(a, NewList<BigStr*>(std::initializer_list<BigStr*>{str654, str655}), comp_words);
  }
  if (comp->index == -1) {
    comp_cword = comp->index;
  }
  else {
    comp_cword = (len(comp_words) - 1);
  }
  state::SetGlobalArray(this->cmd_ev->mem, str656, comp_words);
  state::SetGlobalString(this->cmd_ev->mem, str657, str(comp_cword));
  state::SetGlobalString(this->cmd_ev->mem, str658, comp->line);
  state::SetGlobalString(this->cmd_ev->mem, str659, str(comp->end));
  argv = NewList<BigStr*>(std::initializer_list<BigStr*>{comp->first, comp->to_complete, comp->prev});
  this->debug(StrFormat("Running completion function %r with %d arguments", this->func->name, len(argv)));
  this->comp_lookup->ClearCommandsChanged();
  status = this->cmd_ev->RunFuncForCompletion(this->func, argv);
  commands_changed = this->comp_lookup->GetCommandsChanged();
  this->debug(StrFormat("comp.first %r, commands_changed: %s", comp->first, str662->join(commands_changed)));
  if (status == 124) {
    cmd = os_path::basename(comp->first);
    if (list_contains(commands_changed, cmd)) {
      throw Alloc<_RetryCompletion>();
    }
    else {
      this->debug(StrFormat("Function %r returned 124, but the completion spec for %r wasn't changed", this->func->name, cmd));
      return ;
    }
  }
  val = this->cmd_ev->mem->GetValue(str664, scope_e::GlobalOnly);
  if (val->tag() == value_e::Undef) {
    print_stderr(StrFormat("osh error: Ran function %r but COMPREPLY was unset", this->func->name));
    return ;
  }
  if (val->tag() != value_e::BashArray) {
    print_stderr(StrFormat("osh error: COMPREPLY should be an array, got %s", ui::ValType(val)));
    return ;
  }
  array_val = static_cast<value::BashArray*>(val);
  for (ListIter<BigStr*> it(array_val->strs); !it.Done(); it.Next()) {
    BigStr* s = it.Value();
    StackRoot _for(&s  );
        _out_yield_acc->append(s);
;
  }
}

VariablesAction::VariablesAction(state::Mem* mem) {
  this->mem = mem;
}

void VariablesAction::Matches(completion::Api* comp, List<BigStr*>* _out_yield_acc) {
  StackRoot _root0(&comp);

  for (ListIter<BigStr*> it(this->mem->VarNames()); !it.Done(); it.Next()) {
    BigStr* var_name = it.Value();
    StackRoot _for(&var_name  );
        _out_yield_acc->append(var_name);
;
  }
}

void VariablesAction::Print(mylib::BufWriter* f) {
  StackRoot _root0(&f);

  f->write(str668);
}

ExportedVarsAction::ExportedVarsAction(state::Mem* mem) {
  this->mem = mem;
}

void ExportedVarsAction::Matches(completion::Api* comp, List<BigStr*>* _out_yield_acc) {
  StackRoot _root0(&comp);

  for (DictIter<BigStr*, BigStr*> it(this->mem->GetExported()); !it.Done(); it.Next()) {
    BigStr* var_name = it.Key();
    StackRoot _for(&var_name  );
        _out_yield_acc->append(var_name);
;
  }
}

ExternalCommandAction::ExternalCommandAction(state::Mem* mem) {
  this->mem = mem;
  this->cache = Alloc<Dict<Tuple2<BigStr*, int>*, List<BigStr*>*>>();
}

void ExternalCommandAction::Print(mylib::BufWriter* f) {
  StackRoot _root0(&f);

  f->write(str669);
}

void ExternalCommandAction::Matches(completion::Api* comp, List<BigStr*>* _out_yield_acc) {
  value_asdl::value_t* val = nullptr;
  value::Str* val_s = nullptr;
  List<BigStr*>* path_dirs = nullptr;
  List<BigStr*>* executables = nullptr;
  Tuple2<BigStr*, int>* key = nullptr;
  List<BigStr*>* dir_exes = nullptr;
  List<BigStr*>* entries = nullptr;
  BigStr* path = nullptr;
  StackRoot _root0(&comp);
  StackRoot _root1(&val);
  StackRoot _root2(&val_s);
  StackRoot _root3(&path_dirs);
  StackRoot _root4(&executables);
  StackRoot _root5(&key);
  StackRoot _root6(&dir_exes);
  StackRoot _root7(&entries);
  StackRoot _root8(&path);

  val = this->mem->GetValue(str670);
  if (val->tag() != value_e::Str) {
    return ;
  }
  val_s = static_cast<value::Str*>(val);
  path_dirs = val_s->s->split(str671);
  executables = Alloc<List<BigStr*>>();
  for (ListIter<BigStr*> it(path_dirs); !it.Done(); it.Next()) {
    BigStr* d = it.Value();
    StackRoot _for(&d  );
    try {
      key = pyos::MakeDirCacheKey(d);
    }
    catch (IOError_OSError* e) {
      continue;
    }
    dir_exes = this->cache->get(key);
    if (dir_exes == nullptr) {
      entries = posix::listdir(d);
      dir_exes = Alloc<List<BigStr*>>();
      for (ListIter<BigStr*> it(entries); !it.Done(); it.Next()) {
        BigStr* name = it.Value();
        StackRoot _for(&name      );
        path = os_path::join(d, name);
        if (!posix::access(path, X_OK)) {
          continue;
        }
        dir_exes->append(name);
      }
      this->cache->set(key, dir_exes);
    }
    executables->extend(dir_exes);
  }
  for (ListIter<BigStr*> it(executables); !it.Done(); it.Next()) {
    BigStr* word = it.Value();
    StackRoot _for(&word  );
    if (word->startswith(comp->to_complete)) {
            _out_yield_acc->append(word);
;
    }
  }
}

_Predicate::_Predicate() {
  ;  // pass
}

bool _Predicate::Evaluate(BigStr* candidate) {
  StackRoot _root0(&candidate);

  FAIL(kNotImplemented);  // Python NotImplementedError
}

void _Predicate::Print(mylib::BufWriter* f) {
  StackRoot _root0(&f);

  f->write(str672);
}

DefaultPredicate::DefaultPredicate() {
  ;  // pass
}

bool DefaultPredicate::Evaluate(BigStr* candidate) {
  StackRoot _root0(&candidate);

  return true;
}

void DefaultPredicate::Print(mylib::BufWriter* f) {
  StackRoot _root0(&f);

  f->write(str673);
}

GlobPredicate::GlobPredicate(bool include, BigStr* glob_pat) {
  this->include = include;
  this->glob_pat = glob_pat;
}

bool GlobPredicate::Evaluate(BigStr* candidate) {
  bool matched;
  StackRoot _root0(&candidate);

  matched = libc::fnmatch(this->glob_pat, candidate);
  if (this->include) {
    return !matched;
  }
  else {
    return matched;
  }
}

void GlobPredicate::Print(mylib::BufWriter* f) {
  StackRoot _root0(&f);

  f->write(str675);
}

UserSpec::UserSpec(List<completion::CompletionAction*>* actions, List<completion::CompletionAction*>* extra_actions, List<completion::CompletionAction*>* else_actions, completion::_Predicate* predicate, BigStr* prefix, BigStr* suffix) {
  this->actions = actions;
  this->extra_actions = extra_actions;
  this->else_actions = else_actions;
  this->predicate = predicate;
  this->prefix = prefix;
  this->suffix = suffix;
}

void UserSpec::PrintSpec(mylib::BufWriter* f) {
  StackRoot _root0(&f);

  f->write(str676);
  for (ListIter<completion::CompletionAction*> it(this->actions); !it.Done(); it.Next()) {
    completion::CompletionAction* a = it.Value();
    StackRoot _for(&a  );
    a->Print(f);
  }
  f->write(str677);
  f->write(str678);
  for (ListIter<completion::CompletionAction*> it(this->extra_actions); !it.Done(); it.Next()) {
    completion::CompletionAction* a = it.Value();
    StackRoot _for(&a  );
    a->Print(f);
  }
  f->write(str679);
  f->write(str680);
  for (ListIter<completion::CompletionAction*> it(this->else_actions); !it.Done(); it.Next()) {
    completion::CompletionAction* a = it.Value();
    StackRoot _for(&a  );
    a->Print(f);
  }
  f->write(str681);
  f->write(str682);
  this->predicate->Print(f);
  f->write(str683);
  f->write(StrFormat("  prefix: %s\n", this->prefix));
  f->write(StrFormat("  suffix: %s\n", this->prefix));
}

void UserSpec::AllMatches(completion::Api* comp, List<Tuple2<BigStr*, runtime_asdl::comp_action_t>*>* _out_yield_acc) {
  int num_matches;
  runtime_asdl::comp_action_t action_kind;
  bool show;
  StackRoot _root0(&comp);

  num_matches = 0;
  for (ListIter<completion::CompletionAction*> it(this->actions); !it.Done(); it.Next()) {
    completion::CompletionAction* a = it.Value();
    StackRoot _for(&a  );
    action_kind = a->ActionKind();
    List<BigStr*> _for_yield_acc9;
    a->Matches(comp, &_for_yield_acc9);
    for (ListIter<BigStr*> it(&_for_yield_acc9); !it.Done(); it.Next()) {
      BigStr* match = it.Value();
      StackRoot _for(&match    );
      show = (this->predicate->Evaluate(match) and (match->startswith(comp->to_complete) or action_kind == comp_action_e::BashFunc));
      if (show) {
                _out_yield_acc->append((Alloc<Tuple2<BigStr*, runtime_asdl::comp_action_t>>(str_concat(str_concat(this->prefix, match), this->suffix), action_kind)));
;
        num_matches += 1;
      }
    }
  }
  for (ListIter<completion::CompletionAction*> it(this->extra_actions); !it.Done(); it.Next()) {
    completion::CompletionAction* a = it.Value();
    StackRoot _for(&a  );
    List<BigStr*> _for_yield_acc10;
    a->Matches(comp, &_for_yield_acc10);
    for (ListIter<BigStr*> it(&_for_yield_acc10); !it.Done(); it.Next()) {
      BigStr* match = it.Value();
      StackRoot _for(&match    );
            _out_yield_acc->append((Alloc<Tuple2<BigStr*, runtime_asdl::comp_action_t>>(match, comp_action_e::FileSystem)));
;
    }
  }
  if (num_matches == 0) {
    for (ListIter<completion::CompletionAction*> it(this->else_actions); !it.Done(); it.Next()) {
      completion::CompletionAction* a = it.Value();
      StackRoot _for(&a    );
      List<BigStr*> _for_yield_acc11;
      a->Matches(comp, &_for_yield_acc11);
      for (ListIter<BigStr*> it(&_for_yield_acc11); !it.Done(); it.Next()) {
        BigStr* match = it.Value();
        StackRoot _for(&match      );
                _out_yield_acc->append((Alloc<Tuple2<BigStr*, runtime_asdl::comp_action_t>>(match, comp_action_e::FileSystem)));
;
      }
    }
  }
}

bool IsDollar(syntax_asdl::Token* t) {
  StackRoot _root0(&t);

  return t->id == Id::Lit_Dollar;
}

bool IsDummy(syntax_asdl::Token* t) {
  StackRoot _root0(&t);

  return t->id == Id::Lit_CompDummy;
}

bool WordEndsWithCompDummy(syntax_asdl::CompoundWord* w) {
  syntax_asdl::word_part_t* last_part = nullptr;
  syntax_asdl::word_part_t* UP_part = nullptr;
  StackRoot _root0(&w);
  StackRoot _root1(&last_part);
  StackRoot _root2(&UP_part);

  last_part = w->parts->at(-1);
  UP_part = last_part;
  if (last_part->tag() == word_part_e::Literal) {
    Token* last_part = static_cast<Token*>(UP_part);
    return last_part->id == Id::Lit_CompDummy;
  }
  else {
    return false;
  }
}

RootCompleter::RootCompleter(word_eval::AbstractWordEvaluator* word_ev, state::Mem* mem, completion::Lookup* comp_lookup, completion::OptionState* compopt_state, comp_ui::State* comp_ui_state, parse_lib::ParseContext* parse_ctx, util::_DebugFile* debug_f) {
  this->word_ev = word_ev;
  this->mem = mem;
  this->comp_lookup = comp_lookup;
  this->compopt_state = compopt_state;
  this->comp_ui_state = comp_ui_state;
  this->parse_ctx = parse_ctx;
  this->debug_f = debug_f;
}

void RootCompleter::Matches(completion::Api* comp, List<BigStr*>* _out_yield_acc) {
  BigStr* line_until_tab = nullptr;
  reader::FileLineReader* line_reader = nullptr;
  cmd_parse::CommandParser* c_parser = nullptr;
  util::_DebugFile* debug_f = nullptr;
  parse_lib::_BaseTrail* trail = nullptr;
  List<syntax_asdl::Token*>* tokens = nullptr;
  int last;
  syntax_asdl::Token* t1 = nullptr;
  syntax_asdl::Token* t2 = nullptr;
  BigStr* to_complete = nullptr;
  int n;
  List<syntax_asdl::word_part_t*>* parts = nullptr;
  Token* tilde_tok = nullptr;
  BigStr* name = nullptr;
  BigStr* s = nullptr;
  Token* chars_tok = nullptr;
  syntax_asdl::Redir* r = nullptr;
  syntax_asdl::redir_param_t* arg_word = nullptr;
  syntax_asdl::redir_param_t* UP_word = nullptr;
  value::Str* val = nullptr;
  syntax_asdl::Token* tok = nullptr;
  completion::FileSystemAction* action = nullptr;
  Dict<BigStr*, bool>* base_opts = nullptr;
  completion::UserSpec* user_spec = nullptr;
  List<BigStr*>* partial_argv = nullptr;
  int num_partial;
  BigStr* first = nullptr;
  List<syntax_asdl::word_t*>* trail_words = nullptr;
  List<syntax_asdl::word_t*>* words2 = nullptr;
  BigStr* alias_first = nullptr;
  syntax_asdl::word_t* w = nullptr;
  int index;
  BigStr* prev = nullptr;
  Dict<BigStr*, bool>* dynamic_opts = nullptr;
  bool done;
  StackRoot _root0(&comp);
  StackRoot _root1(&line_until_tab);
  StackRoot _root2(&line_reader);
  StackRoot _root3(&c_parser);
  StackRoot _root4(&debug_f);
  StackRoot _root5(&trail);
  StackRoot _root6(&tokens);
  StackRoot _root7(&t1);
  StackRoot _root8(&t2);
  StackRoot _root9(&to_complete);
  StackRoot _root10(&parts);
  StackRoot _root11(&tilde_tok);
  StackRoot _root12(&name);
  StackRoot _root13(&s);
  StackRoot _root14(&chars_tok);
  StackRoot _root15(&r);
  StackRoot _root16(&arg_word);
  StackRoot _root17(&UP_word);
  StackRoot _root18(&val);
  StackRoot _root19(&tok);
  StackRoot _root20(&action);
  StackRoot _root21(&base_opts);
  StackRoot _root22(&user_spec);
  StackRoot _root23(&partial_argv);
  StackRoot _root24(&first);
  StackRoot _root25(&trail_words);
  StackRoot _root26(&words2);
  StackRoot _root27(&alias_first);
  StackRoot _root28(&w);
  StackRoot _root29(&prev);
  StackRoot _root30(&dynamic_opts);

  line_until_tab = comp->line->slice(0, comp->end);
  this->comp_ui_state->line_until_tab = line_until_tab;
  this->parse_ctx->trail->Clear();
  line_reader = reader::StringLineReader(line_until_tab, this->parse_ctx->arena);
  c_parser = this->parse_ctx->MakeOshParser(line_reader, true);
  try {
    c_parser->ParseLogicalLine();
  }
  catch (error::Parse* e) {
    ;  // pass
  }
  debug_f = this->debug_f;
  trail = this->parse_ctx->trail;
  tokens = trail->tokens;
  last = -1;
  if (tokens->at(-1)->id == Id::Eof_Real) {
    last -= 1;
  }
  try {
    t1 = tokens->at(last);
  }
  catch (IndexError*) {
    t1 = nullptr;
  }
  try {
    t2 = tokens->at((last - 1));
  }
  catch (IndexError*) {
    t2 = nullptr;
  }
  debug_f->writeln(StrFormat("line: %r", comp->line));
  debug_f->writeln(StrFormat("rl_slice from byte %d to %d: %r", comp->begin, comp->end, comp->line->slice(comp->begin, comp->end)));
  if (t1) {
    ;  // pass
  }
  if (t2) {
    ;  // pass
  }
  if (t2) {
    if ((IsDollar(t2) and IsDummy(t1))) {
      this->comp_ui_state->display_pos = (t2->col + 1);
      for (ListIter<BigStr*> it(this->mem->VarNames()); !it.Done(); it.Next()) {
        BigStr* name = it.Value();
        StackRoot _for(&name      );
                _out_yield_acc->append(str_concat(line_until_tab, name));
;
      }
      return ;
    }
    if ((t2->id == Id::Left_DollarBrace and IsDummy(t1))) {
      this->comp_ui_state->display_pos = (t2->col + 2);
      for (ListIter<BigStr*> it(this->mem->VarNames()); !it.Done(); it.Next()) {
        BigStr* name = it.Value();
        StackRoot _for(&name      );
                _out_yield_acc->append(str_concat(line_until_tab, name));
;
      }
      return ;
    }
    if ((t2->id == Id::VSub_DollarName and IsDummy(t1))) {
      this->comp_ui_state->display_pos = (t2->col + 1);
      to_complete = lexer::LazyStr(t2);
      n = len(to_complete);
      for (ListIter<BigStr*> it(this->mem->VarNames()); !it.Done(); it.Next()) {
        BigStr* name = it.Value();
        StackRoot _for(&name      );
        if (name->startswith(to_complete)) {
                    _out_yield_acc->append(str_concat(line_until_tab, name->slice(n)));
;
        }
      }
      return ;
    }
    if ((t2->id == Id::VSub_Name and IsDummy(t1))) {
      this->comp_ui_state->display_pos = t2->col;
      to_complete = lexer::LazyStr(t2);
      n = len(to_complete);
      for (ListIter<BigStr*> it(this->mem->VarNames()); !it.Done(); it.Next()) {
        BigStr* name = it.Value();
        StackRoot _for(&name      );
        if (name->startswith(to_complete)) {
                    _out_yield_acc->append(str_concat(line_until_tab, name->slice(n)));
;
        }
      }
      return ;
    }
    if ((t2->id == Id::Lit_ArithVarLike and IsDummy(t1))) {
      this->comp_ui_state->display_pos = t2->col;
      to_complete = lexer::LazyStr(t2);
      n = len(to_complete);
      for (ListIter<BigStr*> it(this->mem->VarNames()); !it.Done(); it.Next()) {
        BigStr* name = it.Value();
        StackRoot _for(&name      );
        if (name->startswith(to_complete)) {
                    _out_yield_acc->append(str_concat(line_until_tab, name->slice(n)));
;
        }
      }
      return ;
    }
  }
  if (len(trail->words) > 0) {
    parts = trail->words->at(-1)->parts;
    if ((len(parts) > 0 and word_::LiteralId(parts->at(0)) == Id::Lit_Tilde)) {
      if ((len(parts) == 2 and word_::LiteralId(parts->at(1)) == Id::Lit_CompDummy)) {
        tilde_tok = static_cast<Token*>(parts->at(0));
        this->comp_ui_state->display_pos = (tilde_tok->col + 1);
        to_complete = str688;
        for (ListIter<pyos::PasswdEntry*> it(pyos::GetAllUsers()); !it.Done(); it.Next()) {
          pyos::PasswdEntry* u = it.Value();
          StackRoot _for(&u        );
          name = u->pw_name;
          s = str_concat(str_concat(line_until_tab, ShellQuoteB(name)), str689);
                    _out_yield_acc->append(s);
;
        }
        return ;
      }
      if ((len(parts) == 3 and (word_::LiteralId(parts->at(1)) == Id::Lit_Chars and word_::LiteralId(parts->at(2)) == Id::Lit_CompDummy))) {
        chars_tok = static_cast<Token*>(parts->at(1));
        this->comp_ui_state->display_pos = chars_tok->col;
        to_complete = lexer::TokenVal(chars_tok);
        n = len(to_complete);
        for (ListIter<pyos::PasswdEntry*> it(pyos::GetAllUsers()); !it.Done(); it.Next()) {
          pyos::PasswdEntry* u = it.Value();
          StackRoot _for(&u        );
          name = u->pw_name;
          if (name->startswith(to_complete)) {
            s = str_concat(str_concat(line_until_tab, ShellQuoteB(name->slice(n))), str690);
                        _out_yield_acc->append(s);
;
          }
        }
        return ;
      }
    }
  }
  if (len(trail->redirects) > 0) {
    r = trail->redirects->at(-1);
    if ((r->arg->tag() == redir_param_e::Word and consts::RedirArgType(r->op->id) == redir_arg_type_e::Path)) {
      arg_word = r->arg;
      UP_word = arg_word;
      CompoundWord* arg_word = static_cast<CompoundWord*>(UP_word);
      if (WordEndsWithCompDummy(arg_word)) {
        debug_f->writeln(str691);
        try {
          val = this->word_ev->EvalWordToString(arg_word);
        }
        catch (error::FatalRuntime* e) {
          debug_f->writeln(StrFormat("Error evaluating redirect word: %s", e));
          return ;
        }
        if (val->tag() != value_e::Str) {
          debug_f->writeln(str693);
          return ;
        }
        tok = location::LeftTokenForWord(arg_word);
        this->comp_ui_state->display_pos = tok->col;
        comp->Update(str694, val->s, str695, 0, Alloc<List<BigStr*>>());
        n = len(val->s);
        action = Alloc<FileSystemAction>(false, false, true);
        List<BigStr*> _for_yield_acc12;
        action->Matches(comp, &_for_yield_acc12);
        for (ListIter<BigStr*> it(&_for_yield_acc12); !it.Done(); it.Next()) {
          BigStr* name = it.Value();
          StackRoot _for(&name        );
                    _out_yield_acc->append(str_concat(line_until_tab, ShellQuoteB(name->slice(n))));
;
        }
        return ;
      }
    }
  }
  base_opts = nullptr;
  user_spec = nullptr;
  partial_argv = Alloc<List<BigStr*>>();
  num_partial = -1;
  first = nullptr;
  if (len(trail->words) > 0) {
    if (WordEndsWithCompDummy(trail->words->at(-1))) {
      debug_f->writeln(str696);
      trail_words = Alloc<List<syntax_asdl::word_t*>>();
      for (ListIter<syntax_asdl::CompoundWord*> it(trail->words); !it.Done(); it.Next()) {
        syntax_asdl::CompoundWord* w = it.Value();
        trail_words->append(static_cast<word_t*>(w));
      }
      words2 = word_::TildeDetectAll(trail_words);
      for (ListIter<syntax_asdl::word_t*> it(words2); !it.Done(); it.Next()) {
        syntax_asdl::word_t* w = it.Value();
        StackRoot _for(&w      );
        try {
          val = this->word_ev->EvalWordToString(w);
        }
        catch (error::FatalRuntime*) {
          continue;
        }
        if (val->tag() == value_e::Str) {
          partial_argv->append(val->s);
        }
        else {
          ;  // pass
        }
      }
      debug_f->writeln(StrFormat("partial_argv: [%s]", str701->join(partial_argv)));
      num_partial = len(partial_argv);
      first = partial_argv->at(0);
      alias_first = nullptr;
      if (len(trail->alias_words) > 0) {
        w = trail->alias_words->at(0);
        try {
          val = this->word_ev->EvalWordToString(w);
        }
        catch (error::FatalRuntime*) {
          ;  // pass
        }
        alias_first = val->s;
        debug_f->writeln(StrFormat("alias_first: %s", alias_first));
      }
      if (num_partial == 0) {
        assert(0);  // AssertionError
      }
      else {
        if (num_partial == 1) {
          Tuple2<Dict<BigStr*, bool>*, completion::UserSpec*> tup13 = this->comp_lookup->GetFirstSpec();
          base_opts = tup13.at0();
          user_spec = tup13.at1();
          tok = location::LeftTokenForWord(trail->words->at(0));
          this->comp_ui_state->display_pos = tok->col;
          this->debug_f->writeln(StrFormat("** DISPLAY_POS = %d", this->comp_ui_state->display_pos));
        }
        else {
          Tuple2<Dict<BigStr*, bool>*, completion::UserSpec*> tup14 = this->comp_lookup->GetSpecForName(first);
          base_opts = tup14.at0();
          user_spec = tup14.at1();
          if ((!user_spec and alias_first != nullptr)) {
            Tuple2<Dict<BigStr*, bool>*, completion::UserSpec*> tup15 = this->comp_lookup->GetSpecForName(alias_first);
            base_opts = tup15.at0();
            user_spec = tup15.at1();
            if (user_spec) {
              first = alias_first;
            }
          }
          if (!user_spec) {
            Tuple2<Dict<BigStr*, bool>*, completion::UserSpec*> tup16 = this->comp_lookup->GetFallback();
            base_opts = tup16.at0();
            user_spec = tup16.at1();
          }
          tok = location::LeftTokenForWord(trail->words->at(-1));
          this->comp_ui_state->display_pos = tok->col;
          this->debug_f->writeln(StrFormat("display_pos %d", this->comp_ui_state->display_pos));
        }
      }
      index = (len(partial_argv) - 1);
      prev = index == 0 ? str705 : partial_argv->at((index - 1));
      comp->Update(first, partial_argv->at(-1), prev, index, partial_argv);
    }
  }
  if (!user_spec) {
    debug_f->writeln(str706);
    return ;
  }
  dynamic_opts = Alloc<Dict<BigStr*, bool>>();
  this->compopt_state->dynamic_opts = dynamic_opts;
  {  // with
    ctx_Completing ctx{this->compopt_state};

    done = false;
    while (!done) {
      done = true;
      try {
        List<BigStr*> _for_yield_acc17;
        this->_PostProcess(base_opts, dynamic_opts, user_spec, comp, &_for_yield_acc17);
        for (ListIter<BigStr*> it(&_for_yield_acc17); !it.Done(); it.Next()) {
          BigStr* candidate = it.Value();
          StackRoot _for(&candidate        );
                    _out_yield_acc->append(candidate);
;
        }
      }
      catch (_RetryCompletion* e) {
        debug_f->writeln(str707);
        done = false;
        if (num_partial == 0) {
          assert(0);  // AssertionError
        }
        else {
          if (num_partial == 1) {
            Tuple2<Dict<BigStr*, bool>*, completion::UserSpec*> tup18 = this->comp_lookup->GetFirstSpec();
            base_opts = tup18.at0();
            user_spec = tup18.at1();
          }
          else {
            Tuple2<Dict<BigStr*, bool>*, completion::UserSpec*> tup19 = this->comp_lookup->GetSpecForName(first);
            base_opts = tup19.at0();
            user_spec = tup19.at1();
            if (!user_spec) {
              Tuple2<Dict<BigStr*, bool>*, completion::UserSpec*> tup20 = this->comp_lookup->GetFallback();
              base_opts = tup20.at0();
              user_spec = tup20.at1();
            }
          }
        }
      }
    }
  }
}

void RootCompleter::_PostProcess(Dict<BigStr*, bool>* base_opts, Dict<BigStr*, bool>* dynamic_opts, completion::UserSpec* user_spec, completion::Api* comp, List<BigStr*>* _out_yield_acc) {
  double start_time;
  int i;
  BigStr* candidate = nullptr;
  runtime_asdl::comp_action_t action_kind;
  BigStr* line_until_tab = nullptr;
  BigStr* line_until_word = nullptr;
  bool opt_filenames;
  BigStr* s = nullptr;
  bool opt_nospace;
  BigStr* sp = nullptr;
  BigStr* cand = nullptr;
  double elapsed_ms;
  BigStr* plural = nullptr;
  StackRoot _root0(&base_opts);
  StackRoot _root1(&dynamic_opts);
  StackRoot _root2(&user_spec);
  StackRoot _root3(&comp);
  StackRoot _root4(&candidate);
  StackRoot _root5(&line_until_tab);
  StackRoot _root6(&line_until_word);
  StackRoot _root7(&s);
  StackRoot _root8(&sp);
  StackRoot _root9(&cand);
  StackRoot _root10(&plural);

  this->debug_f->writeln(StrFormat("Completing %r ... (Ctrl-C to cancel)", comp->line));
  start_time = time_::time();
  i = 0;
  List<Tuple2<BigStr*, runtime_asdl::comp_action_t>*> _for_yield_acc21;
  user_spec->AllMatches(comp, &_for_yield_acc21);
  for (ListIter<Tuple2<BigStr*, runtime_asdl::comp_action_t>*> it(&_for_yield_acc21); !it.Done(); it.Next()) {
    Tuple2<BigStr*, runtime_asdl::comp_action_t>* tup22 = it.Value();
    candidate = tup22->at0();
    action_kind = tup22->at1();
    line_until_tab = this->comp_ui_state->line_until_tab;
    line_until_word = line_until_tab->slice(0, this->comp_ui_state->display_pos);
    opt_filenames = base_opts->get(str709, false);
    if (dict_contains(dynamic_opts, str710)) {
      opt_filenames = dynamic_opts->at(str711);
    }
    if ((action_kind == comp_action_e::FileSystem or opt_filenames)) {
      if (path_stat::isdir(candidate)) {
        s = str_concat(str_concat(line_until_word, ShellQuoteB(candidate)), str712);
                _out_yield_acc->append(s);
;
        continue;
      }
    }
    opt_nospace = base_opts->get(str713, false);
    if (dict_contains(dynamic_opts, str714)) {
      opt_nospace = dynamic_opts->at(str715);
    }
    sp = opt_nospace ? str716 : str717;
    cand = action_kind == comp_action_e::BashFunc ? candidate : ShellQuoteB(candidate);
        _out_yield_acc->append(str_concat(str_concat(line_until_word, cand), sp));
;
    i += 1;
    elapsed_ms = ((time_::time() - start_time) * 1000.0);
    plural = i == 1 ? str718 : str719;
  }
  elapsed_ms = ((time_::time() - start_time) * 1000.0);
  plural = i == 1 ? str721 : str722;
  this->debug_f->writeln(StrFormat("Found %d match%s for %r in %d ms", i, plural, comp->line, elapsed_ms));
}

ReadlineCallback::ReadlineCallback(py_readline::Readline* readline, completion::RootCompleter* root_comp, util::_DebugFile* debug_f) {
  this->readline = readline;
  this->root_comp = root_comp;
  this->debug_f = debug_f;
  // if not PYTHON
  {
    this->comp_matches = nullptr;
  }
  // endif MYCPP
}

BigStr* ReadlineCallback::_GetNextCompletion(int state) {
  BigStr* buf = nullptr;
  int begin;
  int end;
  completion::Api* comp = nullptr;
  BigStr* next_completion = nullptr;
  StackRoot _root0(&buf);
  StackRoot _root1(&comp);
  StackRoot _root2(&next_completion);

  if (state == 0) {
    buf = this->readline->get_line_buffer();
    begin = this->readline->get_begidx();
    end = this->readline->get_endidx();
    comp = Alloc<Api>(buf, begin, end);
    this->debug_f->writeln(StrFormat("Api %r %d %d", buf, begin, end));
    // if not PYTHON
    {
      List<BigStr*> _iter_buf_it;
      this->root_comp->Matches(comp, &_iter_buf_it);
      ListIter<BigStr*> it(&_iter_buf_it);
      this->comp_matches = list(it);
      this->comp_matches->reverse();
    }
    // endif MYCPP
  }
  // if not PYTHON
  {
    try {
      next_completion = this->comp_matches->pop();
    }
    catch (IndexError*) {
      next_completion = nullptr;
    }
  }
  // endif MYCPP
  return next_completion;
}

BigStr* ReadlineCallback::__call__(BigStr* unused_word, int state) {
  StackRoot _root0(&unused_word);

  try {
    return this->_GetNextCompletion(state);
  }
  catch (util::UserExit* e) {
    print_stderr(str725);
  }
  catch (error::FatalRuntime* e) {
    print_stderr(StrFormat("osh: Runtime error while completing: %s", e->UserErrorString()));
    this->debug_f->writeln(StrFormat("Runtime error while completing: %s", e->UserErrorString()));
  }
  catch (IOError_OSError* e) {
    print_stderr(StrFormat("osh: I/O error (completion): %s", posix::strerror(e->errno_)));
  }
  catch (KeyboardInterrupt*) {
    print_stderr(str729);
  }
  catch (Exception* e) {
    print_stderr(StrFormat("osh: Unhandled exception while completing: %s", e));
    this->debug_f->writeln(StrFormat("Unhandled exception while completing: %s", e));
  }
  catch (SystemExit* e) {
    posix::_exit(e->code);
  }
  return nullptr;
}

BigStr* ExecuteReadlineCallback(completion::ReadlineCallback* cb, BigStr* word, int state) {
  StackRoot _root0(&cb);
  StackRoot _root1(&word);

  return cb->__call__(word, state);
}

}  // define namespace completion

namespace dev {  // define

using option_asdl::option_i;
using option_asdl::builtin_i;
using option_asdl::builtin_t;
using runtime_asdl::cmd_value;
using runtime_asdl::scope_e;
using runtime_asdl::trace;
using runtime_asdl::trace_e;
using runtime_asdl::trace_t;
using syntax_asdl::assign_op_e;
using syntax_asdl::Token;
using value_asdl::value;
using value_asdl::value_e;
using value_asdl::value_t;
using value_asdl::sh_lvalue;
using value_asdl::sh_lvalue_e;
using value_asdl::LeftName;
using mylib::print_stderr;

CrashDumper::CrashDumper(BigStr* crash_dump_dir, process::FdState* fd_state) {
  this->crash_dump_dir = crash_dump_dir;
  this->fd_state = fd_state;
  this->do_collect = to_bool(crash_dump_dir);
  this->collected = false;
  this->var_stack = nullptr;
  this->argv_stack = nullptr;
  this->debug_stack = nullptr;
  this->error = nullptr;
}

void CrashDumper::MaybeRecord(cmd_eval::CommandEvaluator* cmd_ev, error::_ErrorWithLocation* err) {
  syntax_asdl::Token* blame_tok = nullptr;
  StackRoot _root0(&cmd_ev);
  StackRoot _root1(&err);
  StackRoot _root2(&blame_tok);

  if (!this->do_collect) {
    return ;
  }
  Tuple3<List<value_asdl::value_t*>*, List<value_asdl::value_t*>*, List<value_asdl::value_t*>*> tup0 = cmd_ev->mem->Dump();
  this->var_stack = tup0.at0();
  this->argv_stack = tup0.at1();
  this->debug_stack = tup0.at2();
  blame_tok = location::TokenFor(err->location);
  this->error = Alloc<Dict<BigStr*, value_asdl::value_t*>>(std::initializer_list<BigStr*>{str732}, std::initializer_list<value_asdl::value_t*>{Alloc<value::Str>(err->UserErrorString())});
  if (blame_tok) {
    this->error->set(str733, Alloc<value::Str>(ui::GetLineSourceString(blame_tok->line)));
    this->error->set(str734, num::ToBig(blame_tok->line->line_num));
    this->error->set(str735, Alloc<value::Str>(blame_tok->line->content));
  }
  this->do_collect = false;
  this->collected = true;
}

void CrashDumper::MaybeDump(int status) {
  int my_pid;
  Dict<BigStr*, value_asdl::value_t*>* d = nullptr;
  BigStr* path = nullptr;
  mylib::BufWriter* buf = nullptr;
  BigStr* json_str = nullptr;
  mylib::Writer* f = nullptr;
  StackRoot _root0(&d);
  StackRoot _root1(&path);
  StackRoot _root2(&buf);
  StackRoot _root3(&json_str);
  StackRoot _root4(&f);

  if (!this->collected) {
    return ;
  }
  my_pid = posix::getpid();
  d = Alloc<Dict<BigStr*, value_asdl::value_t*>>(std::initializer_list<BigStr*>{str736, str737, str738, str739, str740, str741}, std::initializer_list<value_asdl::value_t*>{Alloc<value::List>(this->var_stack), Alloc<value::List>(this->argv_stack), Alloc<value::List>(this->debug_stack), Alloc<value::Dict>(this->error), num::ToBig(status), num::ToBig(my_pid)});
  path = os_path::join(this->crash_dump_dir, StrFormat("%d-osh-crash-dump.json", my_pid));
  buf = Alloc<mylib::BufWriter>();
  j8::PrintMessage(Alloc<value::Dict>(d), buf, 2);
  json_str = buf->getvalue();
  try {
    f = this->fd_state->OpenForWrite(path);
  }
  catch (IOError_OSError* e) {
    return ;
  }
  f->write(json_str);
  print_stderr(StrFormat("[%d] Wrote crash dump to %s", my_pid, path));
}

ctx_Tracer::ctx_Tracer(dev::Tracer* tracer, BigStr* label, List<BigStr*>* argv) {
  gHeap.PushRoot(reinterpret_cast<RawObject**>(&(this->arg)));
  gHeap.PushRoot(reinterpret_cast<RawObject**>(&(this->label)));
  gHeap.PushRoot(reinterpret_cast<RawObject**>(&(this->tracer)));
  this->arg = nullptr;
  if (str_equals(label, str744)) {
    this->arg = argv->at(0);
  }
  else {
    if (str_equals(label, str745)) {
      this->arg = argv->at(1);
    }
  }
  tracer->PushMessage(label, argv);
  this->label = label;
  this->tracer = tracer;
}

ctx_Tracer::~ctx_Tracer() {
  this->tracer->PopMessage(this->label, this->arg);
  gHeap.PopRoot();
  gHeap.PopRoot();
  gHeap.PopRoot();
}

void _PrintShValue(value_asdl::value_t* val, mylib::BufWriter* buf) {
  BigStr* result = nullptr;
  value_asdl::value_t* UP_val = nullptr;
  List<BigStr*>* parts = nullptr;
  StackRoot _root0(&val);
  StackRoot _root1(&buf);
  StackRoot _root2(&result);
  StackRoot _root3(&UP_val);
  StackRoot _root4(&parts);

  result = str746;
  UP_val = val;
  switch (val->tag()) {
    case value_e::Str: {
      value::Str* val = static_cast<value::Str*>(UP_val);
      result = j8_lite::MaybeShellEncode(val->s);
    }
      break;
    case value_e::BashArray: {
      value::BashArray* val = static_cast<value::BashArray*>(UP_val);
      parts = NewList<BigStr*>(std::initializer_list<BigStr*>{str747});
      for (ListIter<BigStr*> it(val->strs); !it.Done(); it.Next()) {
        BigStr* s = it.Value();
        StackRoot _for(&s      );
        parts->append(j8_lite::MaybeShellEncode(s));
      }
      parts->append(str748);
      result = str749->join(parts);
    }
      break;
    case value_e::BashAssoc: {
      value::BashAssoc* val = static_cast<value::BashAssoc*>(UP_val);
      parts = NewList<BigStr*>(std::initializer_list<BigStr*>{str750});
      for (DictIter<BigStr*, BigStr*> it(val->d); !it.Done(); it.Next()) {
        BigStr* k = it.Key();
        BigStr* v = it.Value();
        parts->append(StrFormat("[%s]=%s", j8_lite::ShellEncode(k), j8_lite::MaybeShellEncode(v)));
      }
      parts->append(str752);
      result = str753->join(parts);
    }
      break;
  }
  buf->write(result);
}

void PrintShellArgv(List<BigStr*>* argv, mylib::BufWriter* buf) {
  int i;
  StackRoot _root0(&argv);
  StackRoot _root1(&buf);

  i = 0;
  for (ListIter<BigStr*> it(argv); !it.Done(); it.Next(), ++i) {
    BigStr* arg = it.Value();
    StackRoot _for(&arg  );
    if (i != 0) {
      buf->write(str754);
    }
    buf->write(j8_lite::MaybeShellEncode(arg));
  }
}

void _PrintYshArgv(List<BigStr*>* argv, mylib::BufWriter* buf) {
  StackRoot _root0(&argv);
  StackRoot _root1(&buf);

  for (ListIter<BigStr*> it(argv); !it.Done(); it.Next()) {
    BigStr* arg = it.Value();
    StackRoot _for(&arg  );
    buf->write(str755);
    buf->write(j8_lite::MaybeShellEncode(arg));
  }
  buf->write(str756);
}

MultiTracer::MultiTracer(int shell_pid, BigStr* out_dir, BigStr* dumps, BigStr* streams, process::FdState* fd_state) {
  this->out_dir = out_dir;
  this->dumps = dumps;
  this->streams = streams;
  this->fd_state = fd_state;
  this->this_pid = shell_pid;
  this->hist_argv0 = Alloc<Dict<BigStr*, int>>();
}

void MultiTracer::OnNewProcess(int child_pid) {
  this->this_pid = child_pid;
  this->hist_argv0->clear();
}

void MultiTracer::EmitArgv0(BigStr* argv0) {
  StackRoot _root0(&argv0);

  if (!dict_contains(this->hist_argv0, argv0)) {
    this->hist_argv0->set(argv0, 1);
  }
  else {
    this->hist_argv0->set(argv0, (this->hist_argv0->at(argv0) + 1));
  }
}

void MultiTracer::WriteDumps() {
  List<value_asdl::value_t*>* metric_argv0 = nullptr;
  value::Str* a = nullptr;
  value::Int* c = nullptr;
  Dict<BigStr*, value_asdl::value_t*>* d = nullptr;
  Dict<BigStr*, value_asdl::value_t*>* j = nullptr;
  BigStr* path = nullptr;
  mylib::BufWriter* buf = nullptr;
  BigStr* json8_str = nullptr;
  mylib::Writer* f = nullptr;
  StackRoot _root0(&metric_argv0);
  StackRoot _root1(&a);
  StackRoot _root2(&c);
  StackRoot _root3(&d);
  StackRoot _root4(&j);
  StackRoot _root5(&path);
  StackRoot _root6(&buf);
  StackRoot _root7(&json8_str);
  StackRoot _root8(&f);

  if (len(this->out_dir) == 0) {
    return ;
  }
  metric_argv0 = Alloc<List<value_asdl::value_t*>>();
  for (DictIter<BigStr*, int> it(this->hist_argv0); !it.Done(); it.Next()) {
    BigStr* argv0 = it.Key();
    int count = it.Value();
    a = Alloc<value::Str>(argv0);
    c = Alloc<value::Int>(mops::IntWiden(count));
    d = Alloc<Dict<BigStr*, value_asdl::value_t*>>(std::initializer_list<BigStr*>{str757, str758}, std::initializer_list<value_asdl::value_t*>{a, c});
    metric_argv0->append(Alloc<value::Dict>(d));
  }
  j = Alloc<Dict<BigStr*, value_asdl::value_t*>>(std::initializer_list<BigStr*>{str759, str760}, std::initializer_list<value_asdl::value_t*>{Alloc<value::Int>(mops::IntWiden(this->this_pid)), Alloc<value::List>(metric_argv0)});
  path = os_path::join(this->out_dir, StrFormat("%d.argv0.json", this->this_pid));
  buf = Alloc<mylib::BufWriter>();
  j8::PrintMessage(Alloc<value::Dict>(j), buf, 2);
  json8_str = buf->getvalue();
  try {
    f = this->fd_state->OpenForWrite(path);
  }
  catch (IOError_OSError* e) {
    return ;
  }
  f->write(json8_str);
  f->close();
  print_stderr(StrFormat("[%d] Wrote metrics dump to %s", this->this_pid, path));
}

Tracer::Tracer(parse_lib::ParseContext* parse_ctx, optview::Exec* exec_opts, state::MutableOpts* mutable_opts, state::Mem* mem, util::_DebugFile* f, dev::MultiTracer* multi_trace) {
  this->parse_ctx = parse_ctx;
  this->exec_opts = exec_opts;
  this->mutable_opts = mutable_opts;
  this->mem = mem;
  this->f = f;
  this->multi_trace = multi_trace;
  this->word_ev = nullptr;
  this->ind = 0;
  this->indents = NewList<BigStr*>(std::initializer_list<BigStr*>{str763});
  this->parse_cache = Alloc<Dict<BigStr*, syntax_asdl::CompoundWord*>>();
  this->val_indent = Alloc<value::Str>(str764);
  this->val_punct = Alloc<value::Str>(str765);
  this->val_pid_str = Alloc<value::Str>(str766);
  this->lval_indent = location::LName(str767);
  this->lval_punct = location::LName(str768);
  this->lval_pid_str = location::LName(str769);
}

void Tracer::CheckCircularDeps() {
}

BigStr* Tracer::_EvalPS4(BigStr* punct) {
  value_asdl::value_t* val = nullptr;
  BigStr* ps4 = nullptr;
  syntax_asdl::CompoundWord* ps4_word = nullptr;
  word_parse::WordParser* w_parser = nullptr;
  value::Str* prefix = nullptr;
  StackRoot _root0(&punct);
  StackRoot _root1(&val);
  StackRoot _root2(&ps4);
  StackRoot _root3(&ps4_word);
  StackRoot _root4(&w_parser);
  StackRoot _root5(&prefix);

  val = this->mem->GetValue(str770);
  if (val->tag() == value_e::Str) {
    ps4 = static_cast<value::Str*>(val)->s;
  }
  else {
    ps4 = str771;
  }
  ps4_word = this->parse_cache->get(ps4);
  if (ps4_word == nullptr) {
    w_parser = this->parse_ctx->MakeWordParserForPlugin(ps4);
    try {
      ps4_word = w_parser->ReadForPlugin();
    }
    catch (error::Parse* e) {
      ps4_word = word_::ErrorWord(StrFormat("<ERROR: Can't parse PS4: %s>", e->UserErrorString()));
    }
    this->parse_cache->set(ps4, ps4_word);
  }
  if (this->exec_opts->xtrace_rich()) {
    this->val_indent->s = this->indents->at(this->ind);
  }
  else {
    this->val_indent->s = str773;
  }
  this->val_punct->s = punct;
  {  // with
    state::ctx_Option ctx{this->mutable_opts, NewList<int>(std::initializer_list<int>{option_i::xtrace}), false};

    {  // with
      state::ctx_Temp ctx{this->mem};

      this->mem->SetNamed(this->lval_indent, this->val_indent, scope_e::LocalOnly);
      this->mem->SetNamed(this->lval_punct, this->val_punct, scope_e::LocalOnly);
      this->mem->SetNamed(this->lval_pid_str, this->val_pid_str, scope_e::LocalOnly);
      prefix = this->word_ev->EvalForPlugin(ps4_word);
    }
  }
  return prefix->s;
}

void Tracer::_Inc() {
  this->ind += 1;
  if (this->ind >= len(this->indents)) {
    this->indents->append(str_repeat(str774, this->ind));
  }
}

void Tracer::_Dec() {
  this->ind -= 1;
}

mylib::BufWriter* Tracer::_ShTraceBegin() {
  BigStr* prefix = nullptr;
  mylib::BufWriter* buf = nullptr;
  StackRoot _root0(&prefix);
  StackRoot _root1(&buf);

  if ((!this->exec_opts->xtrace() or !this->exec_opts->xtrace_details())) {
    return nullptr;
  }
  prefix = this->_EvalPS4(str775);
  buf = Alloc<mylib::BufWriter>();
  buf->write(prefix);
  return buf;
}

mylib::BufWriter* Tracer::_RichTraceBegin(BigStr* punct) {
  BigStr* prefix = nullptr;
  mylib::BufWriter* buf = nullptr;
  StackRoot _root0(&punct);
  StackRoot _root1(&prefix);
  StackRoot _root2(&buf);

  if ((!this->exec_opts->xtrace() or !this->exec_opts->xtrace_rich())) {
    return nullptr;
  }
  prefix = this->_EvalPS4(punct);
  buf = Alloc<mylib::BufWriter>();
  buf->write(prefix);
  return buf;
}

void Tracer::OnProcessStart(int pid, runtime_asdl::trace_t* why) {
  runtime_asdl::trace_t* UP_why = nullptr;
  mylib::BufWriter* buf = nullptr;
  StackRoot _root0(&why);
  StackRoot _root1(&UP_why);
  StackRoot _root2(&buf);

  UP_why = why;
  switch (why->tag()) {
    case trace_e::External: {
      trace::External* why = static_cast<trace::External*>(UP_why);
      this->multi_trace->EmitArgv0(why->argv->at(0));
    }
      break;
  }
  buf = this->_RichTraceBegin(str776);
  if (!buf) {
    return ;
  }
  switch (why->tag()) {
    case trace_e::External: {
      trace::External* why = static_cast<trace::External*>(UP_why);
      buf->write(StrFormat("command %d:", pid));
      _PrintYshArgv(why->argv, buf);
    }
      break;
    case trace_e::ForkWait: {
      buf->write(StrFormat("forkwait %d\n", pid));
    }
      break;
    case trace_e::CommandSub: {
      buf->write(StrFormat("command sub %d\n", pid));
    }
      break;
    case trace_e::ProcessSub: {
      buf->write(StrFormat("proc sub %d\n", pid));
    }
      break;
    case trace_e::HereDoc: {
      buf->write(StrFormat("here doc %d\n", pid));
    }
      break;
    case trace_e::Fork: {
      buf->write(StrFormat("fork %d\n", pid));
    }
      break;
    case trace_e::PipelinePart: {
      buf->write(StrFormat("part %d\n", pid));
    }
      break;
    default: {
      assert(0);  // AssertionError
    }
  }
  this->f->write(buf->getvalue());
}

void Tracer::OnProcessEnd(int pid, int status) {
  mylib::BufWriter* buf = nullptr;
  StackRoot _root0(&buf);

  buf = this->_RichTraceBegin(str784);
  if (!buf) {
    return ;
  }
  buf->write(StrFormat("process %d: status %d\n", pid, status));
  this->f->write(buf->getvalue());
}

void Tracer::OnNewProcess(int child_pid) {
  this->val_pid_str->s = StrFormat(" %d", child_pid);
  this->_Inc();
  this->multi_trace->OnNewProcess(child_pid);
}

void Tracer::PushMessage(BigStr* label, List<BigStr*>* argv) {
  mylib::BufWriter* buf = nullptr;
  StackRoot _root0(&label);
  StackRoot _root1(&argv);
  StackRoot _root2(&buf);

  buf = this->_RichTraceBegin(str787);
  if (buf) {
    buf->write(label);
    if (str_equals(label, str788)) {
      _PrintYshArgv(argv, buf);
    }
    else {
      if (str_equals(label, str789)) {
        _PrintYshArgv(argv->slice(1), buf);
      }
      else {
        if (str_equals(label, str790)) {
          _PrintYshArgv(argv->slice(1), buf);
        }
        else {
          buf->write(str791);
        }
      }
    }
    this->f->write(buf->getvalue());
  }
  this->_Inc();
}

void Tracer::PopMessage(BigStr* label, BigStr* arg) {
  mylib::BufWriter* buf = nullptr;
  StackRoot _root0(&label);
  StackRoot _root1(&arg);
  StackRoot _root2(&buf);

  this->_Dec();
  buf = this->_RichTraceBegin(str792);
  if (buf) {
    buf->write(label);
    if (arg != nullptr) {
      buf->write(str793);
      buf->write(j8_lite::MaybeShellEncode(arg));
    }
    buf->write(str794);
    this->f->write(buf->getvalue());
  }
}

void Tracer::OtherMessage(BigStr* message) {
  mylib::BufWriter* buf = nullptr;
  StackRoot _root0(&message);
  StackRoot _root1(&buf);

  buf = this->_RichTraceBegin(str795);
  if (!buf) {
    return ;
  }
  buf->write(message);
  buf->write(str796);
  this->f->write(buf->getvalue());
}

void Tracer::OnExec(List<BigStr*>* argv) {
  mylib::BufWriter* buf = nullptr;
  StackRoot _root0(&argv);
  StackRoot _root1(&buf);

  buf = this->_RichTraceBegin(str797);
  if (!buf) {
    return ;
  }
  buf->write(str798);
  _PrintYshArgv(argv, buf);
  this->f->write(buf->getvalue());
}

void Tracer::OnBuiltin(int builtin_id, List<BigStr*>* argv) {
  mylib::BufWriter* buf = nullptr;
  StackRoot _root0(&argv);
  StackRoot _root1(&buf);

  if ((builtin_id == builtin_i::eval || builtin_id == builtin_i::source || builtin_id == builtin_i::wait)) {
    return ;
  }
  buf = this->_RichTraceBegin(str799);
  if (!buf) {
    return ;
  }
  buf->write(str800);
  _PrintYshArgv(argv, buf);
  this->f->write(buf->getvalue());
}

void Tracer::OnSimpleCommand(List<BigStr*>* argv) {
  mylib::BufWriter* buf = nullptr;
  StackRoot _root0(&argv);
  StackRoot _root1(&buf);

  buf = this->_ShTraceBegin();
  if (!buf) {
    return ;
  }
  if (this->exec_opts->xtrace_rich()) {
    return ;
  }
  PrintShellArgv(argv, buf);
  buf->write(str801);
  this->f->write(buf->getvalue());
}

void Tracer::OnAssignBuiltin(cmd_value::Assign* cmd_val) {
  mylib::BufWriter* buf = nullptr;
  int i;
  StackRoot _root0(&cmd_val);
  StackRoot _root1(&buf);

  buf = this->_ShTraceBegin();
  if (!buf) {
    return ;
  }
  i = 0;
  for (ListIter<BigStr*> it(cmd_val->argv); !it.Done(); it.Next(), ++i) {
    BigStr* arg = it.Value();
    StackRoot _for(&arg  );
    if (i != 0) {
      buf->write(str802);
    }
    buf->write(arg);
  }
  for (ListIter<runtime_asdl::AssignArg*> it(cmd_val->pairs); !it.Done(); it.Next()) {
    runtime_asdl::AssignArg* pair = it.Value();
    StackRoot _for(&pair  );
    buf->write(str803);
    buf->write(pair->var_name);
    buf->write(str804);
    if (pair->rval) {
      _PrintShValue(pair->rval, buf);
    }
  }
  buf->write(str805);
  this->f->write(buf->getvalue());
}

void Tracer::OnShAssignment(value_asdl::sh_lvalue_t* lval, syntax_asdl::assign_op_t op, value_asdl::value_t* val, int flags, runtime_asdl::scope_t which_scopes) {
  mylib::BufWriter* buf = nullptr;
  BigStr* left = nullptr;
  value_asdl::sh_lvalue_t* UP_lval = nullptr;
  StackRoot _root0(&lval);
  StackRoot _root1(&val);
  StackRoot _root2(&buf);
  StackRoot _root3(&left);
  StackRoot _root4(&UP_lval);

  buf = this->_ShTraceBegin();
  if (!buf) {
    return ;
  }
  left = str806;
  UP_lval = lval;
  switch (lval->tag()) {
    case sh_lvalue_e::Var: {
      LeftName* lval = static_cast<LeftName*>(UP_lval);
      left = lval->name;
    }
      break;
    case sh_lvalue_e::Indexed: {
      sh_lvalue::Indexed* lval = static_cast<sh_lvalue::Indexed*>(UP_lval);
      left = StrFormat("%s[%d]", lval->name, lval->index);
    }
      break;
    case sh_lvalue_e::Keyed: {
      sh_lvalue::Keyed* lval = static_cast<sh_lvalue::Keyed*>(UP_lval);
      left = StrFormat("%s[%s]", lval->name, j8_lite::MaybeShellEncode(lval->key));
    }
      break;
  }
  buf->write(left);
  buf->write(op == assign_op_e::PlusEqual ? str809 : str810);
  _PrintShValue(val, buf);
  buf->write(str811);
  this->f->write(buf->getvalue());
}

void Tracer::OnControlFlow(BigStr* keyword, int arg) {
  BigStr* prefix = nullptr;
  mylib::BufWriter* buf = nullptr;
  StackRoot _root0(&keyword);
  StackRoot _root1(&prefix);
  StackRoot _root2(&buf);

  if (!this->exec_opts->xtrace()) {
    return ;
  }
  prefix = this->_EvalPS4(str812);
  buf = Alloc<mylib::BufWriter>();
  buf->write(prefix);
  buf->write(keyword);
  buf->write(str813);
  buf->write(str(arg));
  buf->write(str814);
  this->f->write(buf->getvalue());
}

void Tracer::PrintSourceCode(syntax_asdl::Token* left_tok, syntax_asdl::Token* right_tok, alloc::Arena* arena) {
  mylib::BufWriter* buf = nullptr;
  BigStr* line = nullptr;
  int start;
  int end;
  StackRoot _root0(&left_tok);
  StackRoot _root1(&right_tok);
  StackRoot _root2(&arena);
  StackRoot _root3(&buf);
  StackRoot _root4(&line);

  buf = this->_ShTraceBegin();
  if (!buf) {
    return ;
  }
  line = left_tok->line->content;
  start = left_tok->col;
  if (left_tok->line == right_tok->line) {
    end = (right_tok->col + right_tok->length);
    buf->write(line->slice(start, end));
  }
  else {
    end = line->endswith(str815) ? -1 : len(line);
    buf->write(line->slice(start, end));
    buf->write(str816);
  }
  buf->write(str817);
  this->f->write(buf->getvalue());
}

}  // define namespace dev

namespace error {  // define

using syntax_asdl::loc_e;
using syntax_asdl::loc_t;
using syntax_asdl::loc;
using value_asdl::value;
using value_asdl::value_t;
using value_asdl::value_str;

BigStr* _ValType(value_asdl::value_t* val) {
  StackRoot _root0(&val);

  return value_str(val->tag(), false);
}

_ErrorWithLocation::_ErrorWithLocation(BigStr* msg, syntax_asdl::loc_t* location) {
  this->msg = msg;
  if (location == nullptr) {
    this->location = loc::Missing;
  }
  else {
    this->location = location;
  }
}

bool _ErrorWithLocation::HasLocation() {
  return this->location->tag() != loc_e::Missing;
}

BigStr* _ErrorWithLocation::UserErrorString() {
  return this->msg;
}

Usage::Usage(BigStr* msg, syntax_asdl::loc_t* location) : ::error::_ErrorWithLocation(msg, location) {
}

Parse::Parse(BigStr* msg, syntax_asdl::loc_t* location) : ::error::_ErrorWithLocation(msg, location) {
}

FailGlob::FailGlob(BigStr* msg, syntax_asdl::loc_t* location) : ::error::_ErrorWithLocation(msg, location) {
}

RedirectEval::RedirectEval(BigStr* msg, syntax_asdl::loc_t* location) : ::error::_ErrorWithLocation(msg, location) {
}

FatalRuntime::FatalRuntime(int exit_status, BigStr* msg, syntax_asdl::loc_t* location) : ::error::_ErrorWithLocation(msg, location) {
  this->exit_status = exit_status;
}

int FatalRuntime::ExitStatus() {
  return this->exit_status;
}

Strict::Strict(BigStr* msg, syntax_asdl::loc_t* location) : ::error::FatalRuntime(1, msg, location) {
}

ErrExit::ErrExit(int exit_status, BigStr* msg, syntax_asdl::loc_t* location, bool show_code) : ::error::FatalRuntime(exit_status, msg, location) {
  this->show_code = show_code;
}

Expr::Expr(BigStr* msg, syntax_asdl::loc_t* location) : ::error::FatalRuntime(3, msg, location) {
}

Structured::Structured(int status, BigStr* msg, syntax_asdl::loc_t* location, Dict<BigStr*, value_asdl::value_t*>* properties) : ::error::FatalRuntime(status, msg, location) {
  this->properties = properties;
}

value::Dict* Structured::ToDict() {
  if (this->properties == nullptr) {
    this->properties = Alloc<Dict<BigStr*, value_asdl::value_t*>>();
  }
  this->properties->set(str819, num::ToBig(this->ExitStatus()));
  this->properties->set(str820, Alloc<value::Str>(this->msg));
  return Alloc<value::Dict>(this->properties);
}

AssertionErr::AssertionErr(BigStr* msg, syntax_asdl::loc_t* location) : ::error::Expr(msg, location) {
}

TypeErrVerbose::TypeErrVerbose(BigStr* msg, syntax_asdl::loc_t* location) : ::error::Expr(msg, location) {
}

TypeErr::TypeErr(value_asdl::value_t* actual_val, BigStr* msg, syntax_asdl::loc_t* location) : ::error::TypeErrVerbose(StrFormat("%s, got %s", msg, _ValType(actual_val)), location) {
}

Runtime::Runtime(BigStr* msg) {
  this->msg = msg;
}

BigStr* Runtime::UserErrorString() {
  return this->msg;
}

Decode::Decode(BigStr* msg, BigStr* s, int start_pos, int end_pos, int line_num) {
  this->msg = msg;
  this->s = s;
  this->start_pos = start_pos;
  this->end_pos = end_pos;
  this->line_num = line_num;
}

BigStr* Decode::Message() {
  int start;
  int end;
  BigStr* part = nullptr;
  StackRoot _root0(&part);

  start = max(0, (this->start_pos - 4));
  end = min(len(this->s), (this->end_pos + 4));
  part = this->s->slice(start, end);
  return str_concat(this->msg, StrFormat(" (line %d, offset %d-%d: %r)", this->line_num, this->start_pos, this->end_pos, part));
}

BigStr* Decode::__str__() {
  return this->Message();
}

Encode::Encode(BigStr* msg) {
  this->msg = msg;
}

BigStr* Encode::Message() {
  return this->msg;
}

[[noreturn]] void e_usage(BigStr* msg, syntax_asdl::loc_t* location) {
  StackRoot _root0(&msg);
  StackRoot _root1(&location);

  throw Alloc<Usage>(msg, location);
}

[[noreturn]] void e_strict(BigStr* msg, syntax_asdl::loc_t* location) {
  StackRoot _root0(&msg);
  StackRoot _root1(&location);

  throw Alloc<Strict>(msg, location);
}

[[noreturn]] void p_die(BigStr* msg, syntax_asdl::loc_t* location) {
  StackRoot _root0(&msg);
  StackRoot _root1(&location);

  throw Alloc<Parse>(msg, location);
}

[[noreturn]] void e_die(BigStr* msg, syntax_asdl::loc_t* location) {
  StackRoot _root0(&msg);
  StackRoot _root1(&location);

  throw Alloc<FatalRuntime>(1, msg, location);
}

[[noreturn]] void e_die_status(int status, BigStr* msg, syntax_asdl::loc_t* location) {
  StackRoot _root0(&msg);
  StackRoot _root1(&location);

  throw Alloc<FatalRuntime>(status, msg, location);
}

}  // define namespace error

namespace executor {  // define

using id_kind_asdl::Id;
using option_asdl::builtin_i;
using runtime_asdl::RedirValue;
using runtime_asdl::trace;
using syntax_asdl::command;
using syntax_asdl::command_e;
using syntax_asdl::CommandSub;
using syntax_asdl::CompoundWord;
using syntax_asdl::loc;
using syntax_asdl::loc_t;
using value_asdl::value;
using error::e_die;
using error::e_die_status;

_ProcessSubFrame::_ProcessSubFrame() {
  this->_to_wait = Alloc<List<process::Process*>>();
  this->_to_close = Alloc<List<int>>();
  this->_locs = Alloc<List<syntax_asdl::loc_t*>>();
  this->_modified = false;
}

bool _ProcessSubFrame::WasModified() {
  return this->_modified;
}

void _ProcessSubFrame::Append(process::Process* p, int fd, syntax_asdl::loc_t* status_loc) {
  StackRoot _root0(&p);
  StackRoot _root1(&status_loc);

  this->_modified = true;
  this->_to_wait->append(p);
  this->_to_close->append(fd);
  this->_locs->append(status_loc);
}

void _ProcessSubFrame::MaybeWaitOnProcessSubs(process::Waiter* waiter, runtime_asdl::StatusArray* status_array) {
  List<int>* codes = nullptr;
  List<syntax_asdl::loc_t*>* locs = nullptr;
  int i;
  int st;
  StackRoot _root0(&waiter);
  StackRoot _root1(&status_array);
  StackRoot _root2(&codes);
  StackRoot _root3(&locs);

  for (ListIter<int> it(this->_to_close); !it.Done(); it.Next()) {
    int fd = it.Value();
    posix::close(fd);
  }
  codes = Alloc<List<int>>();
  locs = Alloc<List<syntax_asdl::loc_t*>>();
  i = 0;
  for (ListIter<process::Process*> it(this->_to_wait); !it.Done(); it.Next(), ++i) {
    process::Process* p = it.Value();
    StackRoot _for(&p  );
    st = p->Wait(waiter);
    codes->append(st);
    locs->append(this->_locs->at(i));
  }
  status_array->codes = codes;
  status_array->locs = locs;
}
int DO_FORK = (1 << 1);
int NO_CALL_PROCS = (1 << 2);
int USE_DEFAULT_PATH = (1 << 3);
GLOBAL_LIST(DEFAULT_PATH, BigStr*, 6, {str823 COMMA str824 COMMA str825 COMMA str826 COMMA str827 COMMA str828});

ShellExecutor::ShellExecutor(state::Mem* mem, optview::Exec* exec_opts, state::MutableOpts* mutable_opts, Dict<BigStr*, value::Proc*>* procs, hay_ysh::HayState* hay_state, Dict<int, vm::_Builtin*>* builtins, state::SearchPath* search_path, process::ExternalProgram* ext_prog, process::Waiter* waiter, dev::Tracer* tracer, process::JobControl* job_control, process::JobList* job_list, process::FdState* fd_state, trap_osh::TrapState* trap_state, ui::ErrorFormatter* errfmt) : ::vm::_Executor() {
  this->mem = mem;
  this->exec_opts = exec_opts;
  this->mutable_opts = mutable_opts;
  this->procs = procs;
  this->hay_state = hay_state;
  this->builtins = builtins;
  this->search_path = search_path;
  this->ext_prog = ext_prog;
  this->waiter = waiter;
  this->tracer = tracer;
  this->multi_trace = tracer->multi_trace;
  this->job_control = job_control;
  this->job_list = job_list;
  this->fd_state = fd_state;
  this->trap_state = trap_state;
  this->errfmt = errfmt;
  this->process_sub_stack = Alloc<List<executor::_ProcessSubFrame*>>();
  this->clean_frame_pool = Alloc<List<executor::_ProcessSubFrame*>>();
  this->fg_pipeline = nullptr;
}

void ShellExecutor::CheckCircularDeps() {
}

process::Process* ShellExecutor::_MakeProcess(syntax_asdl::command_t* node, bool inherit_errexit) {
  syntax_asdl::command_t* UP_node = nullptr;
  process::SubProgramThunk* thunk = nullptr;
  process::Process* p = nullptr;
  StackRoot _root0(&node);
  StackRoot _root1(&UP_node);
  StackRoot _root2(&thunk);
  StackRoot _root3(&p);

  UP_node = node;
  if (node->tag() == command_e::ControlFlow) {
    command::ControlFlow* node = static_cast<command::ControlFlow*>(UP_node);
    if (node->keyword->id != Id::ControlFlow_Exit) {
      e_die(StrFormat("Invalid control flow %r in pipeline / subshell / background", lexer::TokenVal(node->keyword)), node->keyword);
    }
  }
  thunk = Alloc<process::SubProgramThunk>(this->cmd_ev, node, this->trap_state, this->multi_trace, inherit_errexit);
  p = Alloc<process::Process>(thunk, this->job_control, this->job_list, this->tracer);
  return p;
}

int ShellExecutor::RunBuiltin(int builtin_id, cmd_value::Argv* cmd_val) {
  vm::_Builtin* builtin_func = nullptr;
  List<IOError_OSError*>* io_errors = nullptr;
  int status;
  BigStr* arg0 = nullptr;
  StackRoot _root0(&cmd_val);
  StackRoot _root1(&builtin_func);
  StackRoot _root2(&io_errors);
  StackRoot _root3(&arg0);

  this->tracer->OnBuiltin(builtin_id, cmd_val->argv);
  builtin_func = this->builtins->at(builtin_id);
  io_errors = Alloc<List<IOError_OSError*>>();
  {  // with
    vm::ctx_FlushStdout ctx{io_errors};

    {  // with
      ui::ctx_Location ctx{this->errfmt, cmd_val->arg_locs->at(0)};

      try {
        status = builtin_func->Run(cmd_val);
      }
      catch (IOError_OSError* e) {
        this->errfmt->PrintMessage(StrFormat("%s builtin I/O error: %s", cmd_val->argv->at(0), pyutil::strerror(e)), cmd_val->arg_locs->at(0));
        return 1;
      }
      catch (error::Usage* e) {
        arg0 = cmd_val->argv->at(0);
        this->errfmt->PrefixPrint(e->msg, StrFormat("%r ", arg0), e->location);
        return 2;
      }
    }
  }
  if (len(io_errors)) {
    this->errfmt->PrintMessage(StrFormat("%s builtin I/O error: %s", cmd_val->argv->at(0), pyutil::strerror(io_errors->at(0))), cmd_val->arg_locs->at(0));
    return 1;
  }
  return status;
}

int ShellExecutor::RunSimpleCommand(cmd_value::Argv* cmd_val, runtime_asdl::CommandStatus* cmd_st, int run_flags) {
  List<BigStr*>* argv = nullptr;
  syntax_asdl::loc_t* arg0_loc = nullptr;
  BigStr* arg0 = nullptr;
  int builtin_id;
  int status;
  bool call_procs;
  value::Proc* proc_node = nullptr;
  syntax_asdl::Token* disabled_tok = nullptr;
  Dict<BigStr*, BigStr*>* environ = nullptr;
  BigStr* argv0_path = nullptr;
  process::ExternalThunk* thunk = nullptr;
  process::Process* p = nullptr;
  int pgid;
  process::SetPgid* change = nullptr;
  StackRoot _root0(&cmd_val);
  StackRoot _root1(&cmd_st);
  StackRoot _root2(&argv);
  StackRoot _root3(&arg0_loc);
  StackRoot _root4(&arg0);
  StackRoot _root5(&proc_node);
  StackRoot _root6(&disabled_tok);
  StackRoot _root7(&environ);
  StackRoot _root8(&argv0_path);
  StackRoot _root9(&thunk);
  StackRoot _root10(&p);
  StackRoot _root11(&change);

  argv = cmd_val->argv;
  if (len(cmd_val->arg_locs)) {
    arg0_loc = cmd_val->arg_locs->at(0);
  }
  else {
    arg0_loc = loc::Missing;
  }
  if (len(argv) == 0) {
    if (this->exec_opts->strict_argv()) {
      e_die(str833, arg0_loc);
    }
    else {
      return 0;
    }
  }
  arg0 = argv->at(0);
  builtin_id = consts::LookupAssignBuiltin(arg0);
  if (builtin_id != consts::NO_INDEX) {
    this->errfmt->Print_(str834, arg0_loc);
    return 1;
  }
  builtin_id = consts::LookupSpecialBuiltin(arg0);
  if (builtin_id != consts::NO_INDEX) {
    cmd_st->show_code = true;
    status = this->RunBuiltin(builtin_id, cmd_val);
    return status;
  }
  call_procs = !(run_flags & NO_CALL_PROCS);
  if (call_procs) {
    proc_node = this->procs->get(arg0);
    if (proc_node != nullptr) {
      if (this->exec_opts->strict_errexit()) {
        disabled_tok = this->mutable_opts->ErrExitDisabledToken();
        if (disabled_tok) {
          this->errfmt->Print_(str835, disabled_tok);
          this->errfmt->StderrLine(str836);
          e_die(str837, arg0_loc);
        }
      }
      {  // with
        dev::ctx_Tracer ctx{this->tracer, str838, argv};

        status = this->cmd_ev->RunProc(proc_node, cmd_val);
      }
      return status;
    }
  }
  if (this->hay_state->Resolve(arg0)) {
    return this->RunBuiltin(builtin_i::haynode, cmd_val);
  }
  builtin_id = consts::LookupNormalBuiltin(arg0);
  if (this->exec_opts->_running_hay()) {
    if ((builtin_id == builtin_i::haynode || builtin_id == builtin_i::use || builtin_id == builtin_i::echo || builtin_id == builtin_i::write)) {
      cmd_st->show_code = true;
      return this->RunBuiltin(builtin_id, cmd_val);
    }
    this->errfmt->Print_(StrFormat("Unknown command %r while running hay", arg0), arg0_loc);
    return 127;
  }
  if (builtin_id != consts::NO_INDEX) {
    cmd_st->show_code = true;
    return this->RunBuiltin(builtin_id, cmd_val);
  }
  environ = this->mem->GetExported();
  if (cmd_val->typed_args) {
    e_die(StrFormat("%r appears to be external. External commands don't accept typed args (OILS-ERR-200)", arg0), cmd_val->typed_args->left);
  }
  if ((run_flags & USE_DEFAULT_PATH)) {
    argv0_path = state::LookupExecutable(arg0, DEFAULT_PATH);
  }
  else {
    argv0_path = this->search_path->CachedLookup(arg0);
  }
  if (argv0_path == nullptr) {
    this->errfmt->Print_(StrFormat("%r not found (OILS-ERR-100)", arg0), arg0_loc);
    return 127;
  }
  if ((run_flags & DO_FORK)) {
    thunk = Alloc<process::ExternalThunk>(this->ext_prog, argv0_path, cmd_val, environ);
    p = Alloc<process::Process>(thunk, this->job_control, this->job_list, this->tracer);
    if (this->job_control->Enabled()) {
      if (this->fg_pipeline != nullptr) {
        pgid = this->fg_pipeline->ProcessGroupId();
        change = Alloc<process::SetPgid>(pgid, this->tracer);
        this->fg_pipeline = nullptr;
      }
      else {
        change = Alloc<process::SetPgid>(process::OWN_LEADER, this->tracer);
      }
      p->AddStateChange(change);
    }
    status = p->RunProcess(this->waiter, Alloc<trace::External>(cmd_val->argv));
    cmd_st->show_code = true;
    return status;
  }
  this->tracer->OnExec(cmd_val->argv);
  this->ext_prog->Exec(argv0_path, cmd_val, environ);
  assert(0);  // AssertionError
}

int ShellExecutor::RunBackgroundJob(syntax_asdl::command_t* node) {
  syntax_asdl::command_t* UP_node = nullptr;
  process::Pipeline* pi = nullptr;
  process::Process* p = nullptr;
  int last_pid;
  int pid;
  StackRoot _root0(&node);
  StackRoot _root1(&UP_node);
  StackRoot _root2(&pi);
  StackRoot _root3(&p);

  UP_node = node;
  if (UP_node->tag() == command_e::Pipeline) {
    command::Pipeline* node = static_cast<command::Pipeline*>(UP_node);
    pi = Alloc<process::Pipeline>(this->exec_opts->sigpipe_status_ok(), this->job_control, this->job_list, this->tracer);
    for (ListIter<syntax_asdl::command_t*> it(node->children); !it.Done(); it.Next()) {
      syntax_asdl::command_t* child = it.Value();
      StackRoot _for(&child    );
      p = this->_MakeProcess(child);
      p->Init_ParentPipeline(pi);
      pi->Add(p);
    }
    pi->StartPipeline(this->waiter);
    pi->SetBackground();
    last_pid = pi->LastPid();
    this->mem->last_bg_pid = last_pid;
    this->job_list->AddJob(pi);
  }
  else {
    p = this->_MakeProcess(node);
    if (this->job_control->Enabled()) {
      p->AddStateChange(Alloc<process::SetPgid>(process::OWN_LEADER, this->tracer));
    }
    p->SetBackground();
    pid = p->StartProcess(trace::Fork);
    this->mem->last_bg_pid = pid;
    this->job_list->AddJob(p);
  }
  return 0;
}

void ShellExecutor::RunPipeline(command::Pipeline* node, runtime_asdl::CommandStatus* status_out) {
  process::Pipeline* pi = nullptr;
  List<syntax_asdl::loc_t*>* pipe_locs = nullptr;
  int n;
  syntax_asdl::command_t* child = nullptr;
  process::Process* p = nullptr;
  syntax_asdl::command_t* last_child = nullptr;
  StackRoot _root0(&node);
  StackRoot _root1(&status_out);
  StackRoot _root2(&pi);
  StackRoot _root3(&pipe_locs);
  StackRoot _root4(&child);
  StackRoot _root5(&p);
  StackRoot _root6(&last_child);

  pi = Alloc<process::Pipeline>(this->exec_opts->sigpipe_status_ok(), this->job_control, this->job_list, this->tracer);
  pipe_locs = Alloc<List<syntax_asdl::loc_t*>>();
  n = len(node->children);
  for (int i = 0; i < (n - 1); ++i) {
    child = node->children->at(i);
    pipe_locs->append(Alloc<loc::Command>(child));
    p = this->_MakeProcess(child);
    p->Init_ParentPipeline(pi);
    pi->Add(p);
  }
  last_child = node->children->at((n - 1));
  pi->AddLast((Alloc<Tuple2<cmd_eval::CommandEvaluator*, syntax_asdl::command_t*>>(this->cmd_ev, last_child)));
  pipe_locs->append(Alloc<loc::Command>(last_child));
  {  // with
    dev::ctx_Tracer ctx{this->tracer, str843, nullptr};

    pi->StartPipeline(this->waiter);
    this->fg_pipeline = pi;
    status_out->pipe_status = pi->RunLastPart(this->waiter, this->fd_state);
    this->fg_pipeline = nullptr;
  }
  status_out->pipe_locs = pipe_locs;
}

int ShellExecutor::RunSubshell(syntax_asdl::command_t* node) {
  process::Process* p = nullptr;
  StackRoot _root0(&node);
  StackRoot _root1(&p);

  p = this->_MakeProcess(node);
  if (this->job_control->Enabled()) {
    p->AddStateChange(Alloc<process::SetPgid>(process::OWN_LEADER, this->tracer));
  }
  return p->RunProcess(this->waiter, trace::ForkWait);
}

BigStr* ShellExecutor::RunCommandSub(syntax_asdl::CommandSub* cs_part) {
  BigStr* why = nullptr;
  syntax_asdl::command_t* node = nullptr;
  command::Redirect* redir_node = nullptr;
  syntax_asdl::Token* tok = nullptr;
  syntax_asdl::CompoundWord* cat_word = nullptr;
  syntax_asdl::Token* blame_tok = nullptr;
  command::Simple* simple = nullptr;
  process::Process* p = nullptr;
  int r;
  int w;
  List<BigStr*>* chunks = nullptr;
  int n;
  int err_num;
  int status;
  BigStr* msg = nullptr;
  StackRoot _root0(&cs_part);
  StackRoot _root1(&why);
  StackRoot _root2(&node);
  StackRoot _root3(&redir_node);
  StackRoot _root4(&tok);
  StackRoot _root5(&cat_word);
  StackRoot _root6(&blame_tok);
  StackRoot _root7(&simple);
  StackRoot _root8(&p);
  StackRoot _root9(&chunks);
  StackRoot _root10(&msg);

  if (!this->exec_opts->_allow_command_sub()) {
    if (!this->exec_opts->_allow_process_sub()) {
      why = str844;
    }
    else {
      why = str845;
    }
    e_die(StrFormat("Command subs not allowed here because %s", why), Alloc<loc::WordPart>(cs_part));
  }
  node = cs_part->child;
  if (node->tag() == command_e::Redirect) {
    redir_node = static_cast<command::Redirect*>(node);
    if ((len(redir_node->redirects) == 1 and (redir_node->redirects->at(0)->op->id == Id::Redir_Less and redir_node->child->tag() == command_e::NoOp))) {
      tok = lexer::DummyToken(Id::Lit_Chars, str847);
      cat_word = Alloc<CompoundWord>(NewList<syntax_asdl::word_part_t*>(std::initializer_list<syntax_asdl::word_part_t*>{tok}));
      blame_tok = redir_node->redirects->at(0)->op;
      simple = Alloc<command::Simple>(blame_tok, Alloc<List<syntax_asdl::EnvPair*>>(), NewList<syntax_asdl::word_t*>(std::initializer_list<syntax_asdl::word_t*>{cat_word}), nullptr, nullptr, true);
      redir_node->child = simple;
    }
  }
  p = this->_MakeProcess(node, this->exec_opts->inherit_errexit());
  Tuple2<int, int> tup0 = posix::pipe();
  r = tup0.at0();
  w = tup0.at1();
  p->AddStateChange(Alloc<process::StdoutToPipe>(r, w));
  p->StartProcess(trace::CommandSub);
  chunks = Alloc<List<BigStr*>>();
  posix::close(w);
  while (true) {
    Tuple2<int, int> tup1 = pyos::Read(r, 4096, chunks);
    n = tup1.at0();
    err_num = tup1.at1();
    if (n < 0) {
      if (err_num == EINTR) {
        ;  // pass
      }
      else {
        e_die_status(2, StrFormat("osh I/O error (read): %s", posix::strerror(err_num)));
      }
    }
    else {
      if (n == 0) {
        break;
      }
    }
  }
  posix::close(r);
  status = p->Wait(this->waiter);
  if (this->exec_opts->command_sub_errexit()) {
    if (status != 0) {
      msg = StrFormat("Command Sub exited with status %d", status);
      throw Alloc<error::ErrExit>(status, msg, Alloc<loc::WordPart>(cs_part));
    }
  }
  else {
    this->cmd_ev->check_command_sub_status = true;
    this->mem->SetLastStatus(status);
  }
  return str850->join(chunks)->rstrip(str851);
}

BigStr* ShellExecutor::RunProcessSub(syntax_asdl::CommandSub* cs_part) {
  loc::WordPart* cs_loc = nullptr;
  process::Process* p = nullptr;
  int r;
  int w;
  int op_id;
  process::ChildStateChange* redir = nullptr;
  executor::_ProcessSubFrame* ps_frame = nullptr;
  StackRoot _root0(&cs_part);
  StackRoot _root1(&cs_loc);
  StackRoot _root2(&p);
  StackRoot _root3(&redir);
  StackRoot _root4(&ps_frame);

  cs_loc = Alloc<loc::WordPart>(cs_part);
  if (!this->exec_opts->_allow_process_sub()) {
    e_die(str852, cs_loc);
  }
  p = this->_MakeProcess(cs_part->child);
  Tuple2<int, int> tup2 = posix::pipe();
  r = tup2.at0();
  w = tup2.at1();
  op_id = cs_part->left_token->id;
  if (op_id == Id::Left_ProcSubIn) {
    redir = Alloc<process::StdoutToPipe>(r, w);
  }
  else {
    if (op_id == Id::Left_ProcSubOut) {
      redir = Alloc<process::StdinFromPipe>(r, w);
    }
    else {
      assert(0);  // AssertionError
    }
  }
  p->AddStateChange(redir);
  if (this->job_control->Enabled()) {
    p->AddStateChange(Alloc<process::SetPgid>(process::OWN_LEADER, this->tracer));
  }
  p->StartProcess(trace::ProcessSub);
  ps_frame = this->process_sub_stack->at(-1);
  if (op_id == Id::Left_ProcSubIn) {
    posix::close(w);
    ps_frame->Append(p, r, cs_loc);
  }
  else {
    if (op_id == Id::Left_ProcSubOut) {
      posix::close(r);
      ps_frame->Append(p, w, cs_loc);
    }
    else {
      assert(0);  // AssertionError
    }
  }
  if (op_id == Id::Left_ProcSubIn) {
    return StrFormat("/dev/fd/%d", r);
  }
  else {
    if (op_id == Id::Left_ProcSubOut) {
      return StrFormat("/dev/fd/%d", w);
    }
    else {
      assert(0);  // AssertionError
    }
  }
}

void ShellExecutor::PushRedirects(List<runtime_asdl::RedirValue*>* redirects, List<IOError_OSError*>* err_out) {
  StackRoot _root0(&redirects);
  StackRoot _root1(&err_out);

  if (len(redirects) == 0) {
    return ;
  }
  this->fd_state->Push(redirects, err_out);
}

void ShellExecutor::PopRedirects(int num_redirects, List<IOError_OSError*>* err_out) {
  StackRoot _root0(&err_out);

  if (num_redirects == 0) {
    return ;
  }
  this->fd_state->Pop(err_out);
}

void ShellExecutor::PushProcessSub() {
  executor::_ProcessSubFrame* new_frame = nullptr;
  StackRoot _root0(&new_frame);

  if (len(this->clean_frame_pool)) {
    new_frame = this->clean_frame_pool->pop();
  }
  else {
    new_frame = Alloc<_ProcessSubFrame>();
  }
  this->process_sub_stack->append(new_frame);
}

void ShellExecutor::PopProcessSub(runtime_asdl::StatusArray* compound_st) {
  executor::_ProcessSubFrame* frame = nullptr;
  StackRoot _root0(&compound_st);
  StackRoot _root1(&frame);

  frame = this->process_sub_stack->pop();
  if (frame->WasModified()) {
    frame->MaybeWaitOnProcessSubs(this->waiter, compound_st);
  }
  else {
    this->clean_frame_pool->append(frame);
  }
}

}  // define namespace executor

namespace main_loop {  // define

using syntax_asdl::command;
using syntax_asdl::command_t;
using syntax_asdl::parse_result;
using syntax_asdl::parse_result_e;
using mylib::print_stderr;

ctx_Descriptors::ctx_Descriptors(List<int>* fds) {
  gHeap.PushRoot(reinterpret_cast<RawObject**>(&(this->fds)));
  this->saved0 = process::SaveFd(0);
  this->saved1 = process::SaveFd(1);
  this->saved2 = process::SaveFd(2);
  posix::dup2(fds->at(0), 0);
  posix::dup2(fds->at(1), 1);
  posix::dup2(fds->at(2), 2);
  this->fds = fds;
}

ctx_Descriptors::~ctx_Descriptors() {
  posix::dup2(this->saved0, 0);
  posix::dup2(this->saved1, 1);
  posix::dup2(this->saved2, 2);
  posix::close(this->saved0);
  posix::close(this->saved1);
  posix::close(this->saved2);
  posix::close(this->fds->at(0));
  posix::close(this->fds->at(1));
  posix::close(this->fds->at(2));
  gHeap.PopRoot();
}

void fanos_log(BigStr* msg) {
  StackRoot _root0(&msg);

  print_stderr(StrFormat("[FANOS] %s", msg));
}

void ShowDescriptorState(BigStr* label) {
  StackRoot _root0(&label);

}

Headless::Headless(cmd_eval::CommandEvaluator* cmd_ev, parse_lib::ParseContext* parse_ctx, ui::ErrorFormatter* errfmt) {
  this->cmd_ev = cmd_ev;
  this->parse_ctx = parse_ctx;
  this->errfmt = errfmt;
}

int Headless::Loop() {
  try {
    return this->_Loop();
  }
  catch (ValueError* e) {
    fanos::send(1, StrFormat("ERROR %s", e));
    return 1;
  }
}

BigStr* Headless::EVAL(BigStr* arg) {
  reader::FileLineReader* line_reader = nullptr;
  cmd_parse::CommandParser* c_parser = nullptr;
  int unused_status;
  StackRoot _root0(&arg);
  StackRoot _root1(&line_reader);
  StackRoot _root2(&c_parser);

  line_reader = reader::StringLineReader(arg, this->parse_ctx->arena);
  c_parser = this->parse_ctx->MakeOshParser(line_reader);
  unused_status = Batch(this->cmd_ev, c_parser, this->errfmt, 0);
  return str857;
}

int Headless::_Loop() {
  List<int>* fd_out = nullptr;
  BigStr* blob = nullptr;
  List<BigStr*>* bs = nullptr;
  BigStr* command = nullptr;
  BigStr* arg = nullptr;
  BigStr* reply = nullptr;
  StackRoot _root0(&fd_out);
  StackRoot _root1(&blob);
  StackRoot _root2(&bs);
  StackRoot _root3(&command);
  StackRoot _root4(&arg);
  StackRoot _root5(&reply);

  fanos_log(str858);
  fd_out = Alloc<List<int>>();
  while (true) {
    try {
      blob = fanos::recv(0, fd_out);
    }
    catch (ValueError* e) {
      fanos_log(StrFormat("protocol error: %s", e));
      throw ;
    }
    if (blob == nullptr) {
      fanos_log(str860);
      break;
    }
    fanos_log(StrFormat("received blob %r", blob));
    if (str_contains(blob, str862)) {
      bs = blob->split(str863, 1);
      command = bs->at(0);
      arg = bs->at(1);
    }
    else {
      command = blob;
      arg = str864;
    }
    if (str_equals(command, str865)) {
      reply = str(posix::getpid());
    }
    else {
      if (str_equals(command, str866)) {
        if (len(fd_out) != 3) {
          throw Alloc<ValueError>(str867);
        }
        for (ListIter<int> it(fd_out); !it.Done(); it.Next()) {
          int fd = it.Value();
          fanos_log(StrFormat("received descriptor %d", fd));
        }
        {  // with
          ctx_Descriptors ctx{fd_out};

          reply = this->EVAL(arg);
        }
      }
      else {
        if (str_equals(command, str869)) {
          reply = str870;
        }
        else {
          fanos_log(StrFormat("Invalid command %r", command));
          throw Alloc<ValueError>(StrFormat("Invalid command %r", command));
        }
      }
    }
    fanos::send(1, StrFormat("OK %s", reply));
    fd_out->clear();
  }
  return 0;
}

int Interactive(arg_types::main* flag, cmd_eval::CommandEvaluator* cmd_ev, cmd_parse::CommandParser* c_parser, comp_ui::_IDisplay* display, prompt::UserPlugin* prompt_plugin, process::Waiter* waiter, ui::ErrorFormatter* errfmt) {
  int status;
  bool done;
  bool quit;
  syntax_asdl::parse_result_t* result = nullptr;
  syntax_asdl::parse_result_t* UP_result = nullptr;
  syntax_asdl::command_t* node = nullptr;
  bool is_return;
  StackRoot _root0(&flag);
  StackRoot _root1(&cmd_ev);
  StackRoot _root2(&c_parser);
  StackRoot _root3(&display);
  StackRoot _root4(&prompt_plugin);
  StackRoot _root5(&waiter);
  StackRoot _root6(&errfmt);
  StackRoot _root7(&result);
  StackRoot _root8(&UP_result);
  StackRoot _root9(&node);

  status = 0;
  done = false;
  while (!done) {
    mylib::MaybeCollect();
    while (true) {
      quit = false;
      prompt_plugin->Run();
      try {
        result = c_parser->ParseInteractiveLine();
        UP_result = result;
        switch (result->tag()) {
          case parse_result_e::EmptyLine: {
            display->EraseLines();
            waiter->PollNotifications();
            quit = true;
          }
            break;
          case parse_result_e::Eof: {
            display->EraseLines();
            done = true;
            quit = true;
          }
            break;
          case parse_result_e::Node: {
            parse_result::Node* result = static_cast<parse_result::Node*>(UP_result);
            node = result->cmd;
          }
            break;
          default: {
            assert(0);  // AssertionError
          }
        }
      }
      catch (util::HistoryError* e) {
        display->EraseLines();
        print(e->UserErrorString());
        quit = true;
      }
      catch (error::Parse* e) {
        display->EraseLines();
        errfmt->PrettyPrintError(e);
        status = 2;
        cmd_ev->mem->SetLastStatus(status);
        quit = true;
      }
      catch (KeyboardInterrupt*) {
        print(str874);
        display->EraseLines();
        quit = true;
      }
      if (quit) {
        break;
      }
      display->EraseLines();
      if (cmd_ev->exec_opts->noexec()) {
        ui::PrintAst(node, flag);
        break;
      }
      try {
        Tuple2<bool, bool> tup0 = cmd_ev->ExecuteAndCatch(node);
        is_return = tup0.at0();
      }
      catch (KeyboardInterrupt*) {
        is_return = false;
        display->EraseLines();
        status = 130;
        cmd_ev->mem->SetLastStatus(status);
        break;
      }
      status = cmd_ev->LastStatus();
      waiter->PollNotifications();
      if (is_return) {
        done = true;
        break;
      }
      break;
    }
    c_parser->arena->DiscardLines();
    cmd_ev->RunPendingTraps();
    c_parser->Reset();
    c_parser->ResetInputObjects();
    display->Reset();
    if (flag->print_status) {
      print(StrFormat("STATUS\t%r", status));
    }
  }
  return status;
}

int Batch(cmd_eval::CommandEvaluator* cmd_ev, cmd_parse::CommandParser* c_parser, ui::ErrorFormatter* errfmt, int cmd_flags) {
  int status;
  syntax_asdl::command_t* node = nullptr;
  bool is_return;
  bool is_fatal;
  StackRoot _root0(&cmd_ev);
  StackRoot _root1(&c_parser);
  StackRoot _root2(&errfmt);
  StackRoot _root3(&node);

  status = 0;
  while (true) {
    DTRACE_PROBE(main_loop, Batch_parse_enter);
    try {
      node = c_parser->ParseLogicalLine();
      if (node == nullptr) {
        c_parser->CheckForPendingHereDocs();
        break;
      }
    }
    catch (error::Parse* e) {
      errfmt->PrettyPrintError(e);
      status = 2;
      break;
    }
    c_parser->arena->DiscardLines();
    if (((cmd_flags & cmd_eval::IsMainProgram) and c_parser->line_reader->LastLineHint())) {
      cmd_flags |= cmd_eval::Optimize;
    }
    DTRACE_PROBE(main_loop, Batch_parse_exit);
    DTRACE_PROBE(main_loop, Batch_execute_enter);
    Tuple2<bool, bool> tup1 = cmd_ev->ExecuteAndCatch(node, cmd_flags);
    is_return = tup1.at0();
    is_fatal = tup1.at1();
    status = cmd_ev->LastStatus();
    if ((is_return or is_fatal)) {
      break;
    }
    DTRACE_PROBE(main_loop, Batch_execute_exit);
    DTRACE_PROBE(main_loop, Batch_collect_enter);
    mylib::MaybeCollect();
    DTRACE_PROBE(main_loop, Batch_collect_exit);
  }
  return status;
}

syntax_asdl::command_t* ParseWholeFile(cmd_parse::CommandParser* c_parser) {
  List<syntax_asdl::command_t*>* children = nullptr;
  syntax_asdl::command_t* node = nullptr;
  StackRoot _root0(&c_parser);
  StackRoot _root1(&children);
  StackRoot _root2(&node);

  children = Alloc<List<syntax_asdl::command_t*>>();
  while (true) {
    node = c_parser->ParseLogicalLine();
    if (node == nullptr) {
      c_parser->CheckForPendingHereDocs();
      break;
    }
    children->append(node);
    mylib::MaybeCollect();
  }
  if (len(children) == 1) {
    return children->at(0);
  }
  else {
    return Alloc<command::CommandList>(children);
  }
}

}  // define namespace main_loop

namespace num {  // define

using value_asdl::value;

value::Int* ToBig(int i) {
  return Alloc<value::Int>(mops::IntWiden(i));
}

mops::BigInt Exponent(mops::BigInt x, mops::BigInt y) {
  int y_int;
  mops::BigInt result;
  y_int = mops::BigTruncate(y);
  result = mops::BigInt(1);
  for (int i = 0; i < y_int; ++i) {
    result = mops::Mul(result, x);
  }
  return result;
}

int Exponent2(int x, int y) {
  return mops::BigTruncate(Exponent(mops::IntWiden(x), mops::IntWiden(y)));
}

mops::BigInt IntDivide(mops::BigInt x, mops::BigInt y) {
  mops::BigInt ZERO;
  int sign;
  mops::BigInt ax;
  mops::BigInt ay;
  ZERO = mops::BigInt(0);
  sign = 1;
  if (mops::Greater(ZERO, x)) {
    ax = mops::Negate(x);
    sign = -1;
  }
  else {
    ax = x;
  }
  if (mops::Greater(ZERO, y)) {
    ay = mops::Negate(y);
    sign = -sign;
  }
  else {
    ay = y;
  }
  return mops::Mul(mops::IntWiden(sign), mops::Div(ax, ay));
}

int IntDivide2(int x, int y) {
  return mops::BigTruncate(IntDivide(mops::IntWiden(x), mops::IntWiden(y)));
}

mops::BigInt IntRemainder(mops::BigInt x, mops::BigInt y) {
  mops::BigInt ZERO;
  mops::BigInt ax;
  int sign;
  mops::BigInt ay;
  ZERO = mops::BigInt(0);
  if (mops::Greater(ZERO, x)) {
    ax = mops::Negate(x);
    sign = -1;
  }
  else {
    ax = x;
    sign = 1;
  }
  if (mops::Greater(ZERO, y)) {
    ay = mops::Negate(y);
  }
  else {
    ay = y;
  }
  return mops::Mul(mops::IntWiden(sign), mops::Rem(ax, ay));
}

int IntRemainder2(int x, int y) {
  return mops::BigTruncate(IntRemainder(mops::IntWiden(x), mops::IntWiden(y)));
}

}  // define namespace num

namespace process {  // define

using id_kind_asdl::Id;
using runtime_asdl::job_state_e;
using runtime_asdl::job_state_t;
using runtime_asdl::job_state_str;
using runtime_asdl::wait_status;
using runtime_asdl::wait_status_t;
using runtime_asdl::RedirValue;
using runtime_asdl::redirect_arg;
using runtime_asdl::redirect_arg_e;
using runtime_asdl::trace;
using runtime_asdl::trace_t;
using syntax_asdl::loc_t;
using syntax_asdl::redir_loc;
using syntax_asdl::redir_loc_e;
using syntax_asdl::redir_loc_t;
using value_asdl::value;
using value_asdl::value_e;
using error::e_die;
using mylib::print_stderr;
int NO_FD = -1;
int _SHELL_MIN_FD = 100;
int STYLE_DEFAULT = 0;
int STYLE_LONG = 1;
int STYLE_PID_ONLY = 2;
GLOBAL_LIST(CURRENT_JOB_SPECS, BigStr*, 4, {str876 COMMA str877 COMMA str878 COMMA str879});

ctx_FileCloser::ctx_FileCloser(mylib::LineReader* f) {
  gHeap.PushRoot(reinterpret_cast<RawObject**>(&(this->f)));
  this->f = f;
}

ctx_FileCloser::~ctx_FileCloser() {
  this->f->close();
  gHeap.PopRoot();
}

void InitInteractiveShell() {
  pyos::Sigaction(SIGQUIT, SIG_IGN);
  pyos::Sigaction(SIGTSTP, SIG_IGN);
  pyos::Sigaction(SIGTTOU, SIG_IGN);
  pyos::Sigaction(SIGTTIN, SIG_IGN);
  pyos::RegisterSignalInterest(SIGWINCH);
}

int SaveFd(int fd) {
  int saved;
  saved = fcntl_::fcntl(fd, F_DUPFD, _SHELL_MIN_FD);
  return saved;
}

_RedirFrame::_RedirFrame(int saved_fd, int orig_fd, bool forget) {
  this->saved_fd = saved_fd;
  this->orig_fd = orig_fd;
  this->forget = forget;
}

_FdFrame::_FdFrame() {
  this->saved = Alloc<List<process::_RedirFrame*>>();
  this->need_wait = Alloc<List<process::Process*>>();
}

void _FdFrame::Forget() {
  for (ReverseListIter<process::_RedirFrame*> it(this->saved); !it.Done(); it.Next()) {
    process::_RedirFrame* rf = it.Value();
    StackRoot _for(&rf  );
    if ((rf->saved_fd != NO_FD and rf->forget)) {
      posix::close(rf->saved_fd);
    }
  }
  this->saved->clear();
  this->need_wait->clear();
}

FdState::FdState(ui::ErrorFormatter* errfmt, process::JobControl* job_control, process::JobList* job_list, state::Mem* mem, dev::Tracer* tracer, process::Waiter* waiter) {
  this->errfmt = errfmt;
  this->job_control = job_control;
  this->job_list = job_list;
  this->cur_frame = Alloc<_FdFrame>();
  this->stack = NewList<process::_FdFrame*>(std::initializer_list<process::_FdFrame*>{this->cur_frame});
  this->mem = mem;
  this->tracer = tracer;
  this->waiter = waiter;
}

mylib::LineReader* FdState::Open(BigStr* path) {
  int fd_mode;
  mylib::File* f = nullptr;
  StackRoot _root0(&path);
  StackRoot _root1(&f);

  fd_mode = O_RDONLY;
  f = this->_Open(path, str881, fd_mode);
  return static_cast<mylib::LineReader*>(f);
}

mylib::Writer* FdState::OpenForWrite(BigStr* path) {
  int fd_mode;
  mylib::File* f = nullptr;
  StackRoot _root0(&path);
  StackRoot _root1(&f);

  fd_mode = (O_CREAT | O_RDWR);
  f = this->_Open(path, str883, fd_mode);
  return reinterpret_cast<mylib::Writer*>(f);
}

mylib::File* FdState::_Open(BigStr* path, BigStr* c_mode, int fd_mode) {
  int fd;
  int new_fd;
  mylib::File* f = nullptr;
  StackRoot _root0(&path);
  StackRoot _root1(&c_mode);
  StackRoot _root2(&f);

  fd = posix::open(path, fd_mode, 438);
  new_fd = SaveFd(fd);
  posix::close(fd);
  f = posix::fdopen(new_fd, c_mode);
  return f;
}

void FdState::_WriteFdToMem(BigStr* fd_name, int fd) {
  StackRoot _root0(&fd_name);

  if (this->mem) {
    state::OshLanguageSetValue(this->mem, location::LName(fd_name), Alloc<value::Str>(str(fd)));
  }
}

int FdState::_ReadFdFromMem(BigStr* fd_name) {
  value_asdl::value_t* val = nullptr;
  StackRoot _root0(&fd_name);
  StackRoot _root1(&val);

  val = this->mem->GetValue(fd_name);
  if (val->tag() == value_e::Str) {
    try {
      return to_int(static_cast<value::Str*>(val)->s);
    }
    catch (ValueError*) {
      return NO_FD;
    }
  }
  return NO_FD;
}

bool FdState::_PushSave(int fd) {
  bool ok;
  int new_fd;
  ok = true;
  try {
    new_fd = SaveFd(fd);
  }
  catch (IOError_OSError* e) {
    ok = false;
    if (e->errno_ != EBADF) {
      throw ;
    }
  }
  if (ok) {
    posix::close(fd);
    fcntl_::fcntl(new_fd, F_SETFD, FD_CLOEXEC);
    this->cur_frame->saved->append(Alloc<_RedirFrame>(new_fd, fd, true));
  }
  else {
    this->_PushClose(fd);
  }
  return ok;
}

int FdState::_PushDup(int fd1, syntax_asdl::redir_loc_t* blame_loc) {
  syntax_asdl::redir_loc_t* UP_loc = nullptr;
  BigStr* fd2_name = nullptr;
  int new_fd;
  int fd2;
  bool need_restore;
  process::_RedirFrame* rf = nullptr;
  StackRoot _root0(&blame_loc);
  StackRoot _root1(&UP_loc);
  StackRoot _root2(&fd2_name);
  StackRoot _root3(&rf);

  UP_loc = blame_loc;
  if (blame_loc->tag() == redir_loc_e::VarName) {
    fd2_name = static_cast<redir_loc::VarName*>(UP_loc)->name;
    try {
      new_fd = fcntl_::fcntl(fd1, F_DUPFD, _SHELL_MIN_FD);
    }
    catch (IOError_OSError* e) {
      if (e->errno_ == EBADF) {
        print_stderr(StrFormat("F_DUPFD fd %d: %s", fd1, pyutil::strerror(e)));
        return NO_FD;
      }
      else {
        throw ;
      }
    }
    this->_WriteFdToMem(fd2_name, new_fd);
  }
  else {
    if (blame_loc->tag() == redir_loc_e::Fd) {
      fd2 = static_cast<redir_loc::Fd*>(UP_loc)->fd;
      if (fd1 == fd2) {
        return NO_FD;
      }
      try {
        fcntl_::fcntl(fd1, F_GETFD);
      }
      catch (IOError_OSError* e) {
        print_stderr(StrFormat("F_GETFD fd %d: %s", fd1, pyutil::strerror(e)));
        throw ;
      }
      need_restore = this->_PushSave(fd2);
      try {
        posix::dup2(fd1, fd2);
      }
      catch (IOError_OSError* e) {
        print_stderr(StrFormat("dup2(%d, %d): %s", fd1, fd2, pyutil::strerror(e)));
        if (need_restore) {
          rf = this->cur_frame->saved->pop();
          posix::dup2(rf->saved_fd, rf->orig_fd);
          posix::close(rf->saved_fd);
        }
        throw ;
      }
      new_fd = fd2;
    }
    else {
      assert(0);  // AssertionError
    }
  }
  return new_fd;
}

bool FdState::_PushCloseFd(syntax_asdl::redir_loc_t* blame_loc) {
  syntax_asdl::redir_loc_t* UP_loc = nullptr;
  BigStr* fd_name = nullptr;
  int fd;
  StackRoot _root0(&blame_loc);
  StackRoot _root1(&UP_loc);
  StackRoot _root2(&fd_name);

  UP_loc = blame_loc;
  if (blame_loc->tag() == redir_loc_e::VarName) {
    fd_name = static_cast<redir_loc::VarName*>(UP_loc)->name;
    fd = this->_ReadFdFromMem(fd_name);
    if (fd == NO_FD) {
      return false;
    }
  }
  else {
    if (blame_loc->tag() == redir_loc_e::Fd) {
      fd = static_cast<redir_loc::Fd*>(UP_loc)->fd;
    }
    else {
      assert(0);  // AssertionError
    }
  }
  this->_PushSave(fd);
  return true;
}

void FdState::_PushClose(int fd) {
  this->cur_frame->saved->append(Alloc<_RedirFrame>(NO_FD, fd, false));
}

void FdState::_PushWait(process::Process* proc) {
  StackRoot _root0(&proc);

  this->cur_frame->need_wait->append(proc);
}

void FdState::_ApplyRedirect(runtime_asdl::RedirValue* r) {
  runtime_asdl::redirect_arg_t* arg = nullptr;
  runtime_asdl::redirect_arg_t* UP_arg = nullptr;
  int mode;
  int open_fd;
  int new_fd;
  syntax_asdl::redir_loc_t* UP_loc = nullptr;
  int fd;
  int read_fd;
  int write_fd;
  process::_HereDocWriterThunk* thunk = nullptr;
  bool start_process;
  process::Process* here_proc = nullptr;
  StackRoot _root0(&r);
  StackRoot _root1(&arg);
  StackRoot _root2(&UP_arg);
  StackRoot _root3(&UP_loc);
  StackRoot _root4(&thunk);
  StackRoot _root5(&here_proc);

  arg = r->arg;
  UP_arg = arg;
  switch (arg->tag()) {
    case redirect_arg_e::Path: {
      redirect_arg::Path* arg = static_cast<redirect_arg::Path*>(UP_arg);
      if ((r->op_id == Id::Redir_Great || r->op_id == Id::Redir_AndGreat)) {
        mode = ((O_CREAT | O_WRONLY) | O_TRUNC);
      }
      else {
        if (r->op_id == Id::Redir_Clobber) {
          mode = ((O_CREAT | O_WRONLY) | O_TRUNC);
        }
        else {
          if ((r->op_id == Id::Redir_DGreat || r->op_id == Id::Redir_AndDGreat)) {
            mode = ((O_CREAT | O_WRONLY) | O_APPEND);
          }
          else {
            if (r->op_id == Id::Redir_Less) {
              mode = O_RDONLY;
            }
            else {
              if (r->op_id == Id::Redir_LessGreat) {
                mode = (O_CREAT | O_RDWR);
              }
              else {
                FAIL(kNotImplemented);  // Python NotImplementedError
              }
            }
          }
        }
      }
      try {
        open_fd = posix::open(arg->filename, mode, 438);
      }
      catch (IOError_OSError* e) {
        this->errfmt->Print_(StrFormat("Can't open %r: %s", arg->filename, pyutil::strerror(e)), r->op_loc);
        throw ;
      }
      new_fd = this->_PushDup(open_fd, r->loc);
      if (new_fd != NO_FD) {
        posix::close(open_fd);
      }
      if ((r->op_id == Id::Redir_AndGreat || r->op_id == Id::Redir_AndDGreat)) {
        this->_PushDup(new_fd, Alloc<redir_loc::Fd>(2));
      }
    }
      break;
    case redirect_arg_e::CopyFd: {
      redirect_arg::CopyFd* arg = static_cast<redirect_arg::CopyFd*>(UP_arg);
      if (r->op_id == Id::Redir_GreatAnd) {
        this->_PushDup(arg->target_fd, r->loc);
      }
      else {
        if (r->op_id == Id::Redir_LessAnd) {
          this->_PushDup(arg->target_fd, r->loc);
        }
        else {
          FAIL(kNotImplemented);  // Python NotImplementedError
        }
      }
    }
      break;
    case redirect_arg_e::MoveFd: {
      redirect_arg::MoveFd* arg = static_cast<redirect_arg::MoveFd*>(UP_arg);
      new_fd = this->_PushDup(arg->target_fd, r->loc);
      if (new_fd != NO_FD) {
        posix::close(arg->target_fd);
        UP_loc = r->loc;
        if (r->loc->tag() == redir_loc_e::Fd) {
          fd = static_cast<redir_loc::Fd*>(UP_loc)->fd;
        }
        else {
          fd = NO_FD;
        }
        this->cur_frame->saved->append(Alloc<_RedirFrame>(new_fd, fd, false));
      }
    }
      break;
    case redirect_arg_e::CloseFd: {
      this->_PushCloseFd(r->loc);
    }
      break;
    case redirect_arg_e::HereDoc: {
      redirect_arg::HereDoc* arg = static_cast<redirect_arg::HereDoc*>(UP_arg);
      Tuple2<int, int> tup0 = posix::pipe();
      read_fd = tup0.at0();
      write_fd = tup0.at1();
      this->_PushDup(read_fd, r->loc);
      this->_PushClose(read_fd);
      thunk = Alloc<_HereDocWriterThunk>(write_fd, arg->body);
      start_process = len(arg->body) > 4096;
      if (start_process) {
        here_proc = Alloc<Process>(thunk, this->job_control, this->job_list, this->tracer);
        here_proc->StartProcess(trace::HereDoc);
        this->_PushWait(here_proc);
        posix::close(write_fd);
      }
      else {
        posix::write(write_fd, arg->body);
        posix::close(write_fd);
      }
    }
      break;
  }
}

void FdState::Push(List<runtime_asdl::RedirValue*>* redirects, List<IOError_OSError*>* err_out) {
  process::_FdFrame* new_frame = nullptr;
  StackRoot _root0(&redirects);
  StackRoot _root1(&err_out);
  StackRoot _root2(&new_frame);

  new_frame = Alloc<_FdFrame>();
  this->stack->append(new_frame);
  this->cur_frame = new_frame;
  for (ListIter<runtime_asdl::RedirValue*> it(redirects); !it.Done(); it.Next()) {
    runtime_asdl::RedirValue* r = it.Value();
    StackRoot _for(&r  );
    {  // with
      ui::ctx_Location ctx{this->errfmt, r->op_loc};

      try {
        this->_ApplyRedirect(r);
      }
      catch (IOError_OSError* e) {
        err_out->append(e);
        this->Pop(err_out);
        return ;
      }
    }
  }
}

bool FdState::PushStdinFromPipe(int r) {
  process::_FdFrame* new_frame = nullptr;
  StackRoot _root0(&new_frame);

  new_frame = Alloc<_FdFrame>();
  this->stack->append(new_frame);
  this->cur_frame = new_frame;
  this->_PushDup(r, Alloc<redir_loc::Fd>(0));
  return true;
}

void FdState::Pop(List<IOError_OSError*>* err_out) {
  process::_FdFrame* frame = nullptr;
  int unused_status;
  StackRoot _root0(&err_out);
  StackRoot _root1(&frame);

  frame = this->stack->pop();
  for (ReverseListIter<process::_RedirFrame*> it(frame->saved); !it.Done(); it.Next()) {
    process::_RedirFrame* rf = it.Value();
    StackRoot _for(&rf  );
    if (rf->saved_fd == NO_FD) {
      try {
        posix::close(rf->orig_fd);
      }
      catch (IOError_OSError* e) {
        err_out->append(e);
        mylib::print_stderr(StrFormat("Error closing descriptor %d: %s", rf->orig_fd, pyutil::strerror(e)));
        return ;
      }
    }
    else {
      try {
        posix::dup2(rf->saved_fd, rf->orig_fd);
      }
      catch (IOError_OSError* e) {
        err_out->append(e);
        mylib::print_stderr(StrFormat("dup2(%d, %d) error: %s", rf->saved_fd, rf->orig_fd, pyutil::strerror(e)));
        return ;
      }
      posix::close(rf->saved_fd);
    }
  }
  for (ListIter<process::Process*> it(frame->need_wait); !it.Done(); it.Next()) {
    process::Process* proc = it.Value();
    StackRoot _for(&proc  );
    unused_status = proc->Wait(this->waiter);
  }
}

void FdState::MakePermanent() {
  this->cur_frame->Forget();
}

ChildStateChange::ChildStateChange() {
  ;  // pass
}

void ChildStateChange::Apply() {
  FAIL(kNotImplemented);  // Python NotImplementedError
}

void ChildStateChange::ApplyFromParent(process::Process* proc) {
  StackRoot _root0(&proc);

  ;  // pass
}

StdinFromPipe::StdinFromPipe(int pipe_read_fd, int w) {
  this->r = pipe_read_fd;
  this->w = w;
}

void StdinFromPipe::Apply() {
  posix::dup2(this->r, 0);
  posix::close(this->r);
  posix::close(this->w);
}

StdoutToPipe::StdoutToPipe(int r, int pipe_write_fd) {
  this->r = r;
  this->w = pipe_write_fd;
}

void StdoutToPipe::Apply() {
  posix::dup2(this->w, 1);
  posix::close(this->w);
  posix::close(this->r);
}
int INVALID_PGID = -1;
int OWN_LEADER = 0;

SetPgid::SetPgid(int pgid, dev::Tracer* tracer) {
  this->pgid = pgid;
  this->tracer = tracer;
}

void SetPgid::Apply() {
  try {
    posix::setpgid(0, this->pgid);
  }
  catch (IOError_OSError* e) {
    this->tracer->OtherMessage(StrFormat("osh: child %d failed to set its process group to %d: %s", posix::getpid(), this->pgid, pyutil::strerror(e)));
  }
}

void SetPgid::ApplyFromParent(process::Process* proc) {
  StackRoot _root0(&proc);

  try {
    posix::setpgid(proc->pid, this->pgid);
  }
  catch (IOError_OSError* e) {
    this->tracer->OtherMessage(StrFormat("osh: parent failed to set process group for PID %d to %d: %s", proc->pid, this->pgid, pyutil::strerror(e)));
  }
}

ExternalProgram::ExternalProgram(BigStr* hijack_shebang, process::FdState* fd_state, ui::ErrorFormatter* errfmt, util::_DebugFile* debug_f) {
  this->hijack_shebang = hijack_shebang;
  this->fd_state = fd_state;
  this->errfmt = errfmt;
  this->debug_f = debug_f;
}

void ExternalProgram::Exec(BigStr* argv0_path, cmd_value::Argv* cmd_val, Dict<BigStr*, BigStr*>* environ) {
  StackRoot _root0(&argv0_path);
  StackRoot _root1(&cmd_val);
  StackRoot _root2(&environ);

  DTRACE_PROBE1(process, ExternalProgram_Exec, argv0_path->data());
  this->_Exec(argv0_path, cmd_val->argv, cmd_val->arg_locs->at(0), environ, true);
}

void ExternalProgram::_Exec(BigStr* argv0_path, List<BigStr*>* argv, syntax_asdl::loc_t* argv0_loc, Dict<BigStr*, BigStr*>* environ, bool should_retry) {
  bool opened;
  mylib::LineReader* f = nullptr;
  BigStr* line = nullptr;
  List<BigStr*>* h_argv = nullptr;
  List<BigStr*>* new_argv = nullptr;
  int status;
  StackRoot _root0(&argv0_path);
  StackRoot _root1(&argv);
  StackRoot _root2(&argv0_loc);
  StackRoot _root3(&environ);
  StackRoot _root4(&f);
  StackRoot _root5(&line);
  StackRoot _root6(&h_argv);
  StackRoot _root7(&new_argv);

  if (len(this->hijack_shebang)) {
    opened = true;
    try {
      f = this->fd_state->Open(argv0_path);
    }
    catch (IOError_OSError* e) {
      opened = false;
    }
    if (opened) {
      {  // with
        ctx_FileCloser ctx{f};

        line = f->readline();
        if (match::ShouldHijack(line)) {
          h_argv = NewList<BigStr*>(std::initializer_list<BigStr*>{this->hijack_shebang, argv0_path});
          h_argv->extend(argv->slice(1));
          argv = h_argv;
          argv0_path = this->hijack_shebang;
          this->debug_f->writeln(StrFormat("Hijacked: %s", argv0_path));
        }
        else {
          ;  // pass
        }
      }
    }
  }
  try {
    posix::execve(argv0_path, argv, environ);
  }
  catch (IOError_OSError* e) {
    if ((e->errno_ == ENOEXEC and should_retry)) {
      new_argv = NewList<BigStr*>(std::initializer_list<BigStr*>{str896, argv0_path});
      new_argv->extend(argv->slice(1));
      this->_Exec(str897, new_argv, argv0_loc, environ, false);
    }
    this->errfmt->Print_(StrFormat("Can't execute %r: %s", argv0_path, pyutil::strerror(e)), argv0_loc);
    if (e->errno_ == EACCES) {
      status = 126;
    }
    else {
      if (e->errno_ == ENOENT) {
        status = 127;
      }
      else {
        status = 127;
      }
    }
    posix::_exit(status);
  }
}

Thunk::Thunk() {
  ;  // pass
}

void Thunk::Run() {
  FAIL(kNotImplemented);  // Python NotImplementedError
}

BigStr* Thunk::UserString() {
  FAIL(kNotImplemented);  // Python NotImplementedError
}

ExternalThunk::ExternalThunk(process::ExternalProgram* ext_prog, BigStr* argv0_path, cmd_value::Argv* cmd_val, Dict<BigStr*, BigStr*>* environ) {
  this->ext_prog = ext_prog;
  this->argv0_path = argv0_path;
  this->cmd_val = cmd_val;
  this->environ = environ;
}

BigStr* ExternalThunk::UserString() {
  List<BigStr*>* tmp = nullptr;
  StackRoot _root0(&tmp);

  tmp = Alloc<List<BigStr*>>();
  for (ListIter<BigStr*> it(this->cmd_val->argv); !it.Done(); it.Next()) {
    BigStr* a = it.Value();
    tmp->append(j8_lite::MaybeShellEncode(a));
  }
  return StrFormat("[process] %s", str900->join(tmp));
}

void ExternalThunk::Run() {
  this->ext_prog->Exec(this->argv0_path, this->cmd_val, this->environ);
}

SubProgramThunk::SubProgramThunk(cmd_eval::CommandEvaluator* cmd_ev, syntax_asdl::command_t* node, trap_osh::TrapState* trap_state, dev::MultiTracer* multi_trace, bool inherit_errexit) {
  this->cmd_ev = cmd_ev;
  this->node = node;
  this->trap_state = trap_state;
  this->multi_trace = multi_trace;
  this->inherit_errexit = inherit_errexit;
}

BigStr* SubProgramThunk::UserString() {
  BigStr* thunk_str = nullptr;
  StackRoot _root0(&thunk_str);

  thunk_str = ui::CommandType(this->node);
  return StrFormat("[subprog] %s", thunk_str);
}

void SubProgramThunk::Run() {
  int status;
  DTRACE_PROBE(process, SubProgramThunk_Run);
  this->trap_state->ClearForSubProgram();
  if (!this->inherit_errexit) {
    this->cmd_ev->mutable_opts->DisableErrExit();
  }
  try {
    this->cmd_ev->ExecuteAndCatch(this->node, cmd_eval::Optimize);
    status = this->cmd_ev->LastStatus();
  }
  catch (util::UserExit* e) {
    status = e->status;
  }
  catch (KeyboardInterrupt*) {
    print(str902);
    status = 130;
  }
  catch (IOError_OSError* e) {
    print_stderr(StrFormat("oils I/O error (subprogram): %s", pyutil::strerror(e)));
    status = 2;
  }
  pyos::FlushStdout();
  this->multi_trace->WriteDumps();
  posix::_exit(status);
}

_HereDocWriterThunk::_HereDocWriterThunk(int w, BigStr* body_str) {
  this->w = w;
  this->body_str = body_str;
}

BigStr* _HereDocWriterThunk::UserString() {
  return str904;
}

void _HereDocWriterThunk::Run() {
  DTRACE_PROBE(process, HereDocWriterThunk_Run);
  posix::write(this->w, this->body_str);
  posix::close(this->w);
  posix::_exit(0);
}

Job::Job() {
  this->state = job_state_e::Running;
  this->job_id = -1;
  this->in_background = false;
}

void Job::DisplayJob(int job_id, mylib::Writer* f, int style) {
  StackRoot _root0(&f);

  FAIL(kNotImplemented);  // Python NotImplementedError
}

runtime_asdl::job_state_t Job::State() {
  return this->state;
}

int Job::ProcessGroupId() {
  FAIL(kNotImplemented);  // Python NotImplementedError
}

runtime_asdl::wait_status_t* Job::JobWait(process::Waiter* waiter) {
  StackRoot _root0(&waiter);

  FAIL(kNotImplemented);  // Python NotImplementedError
}

void Job::SetBackground() {
  this->in_background = true;
}

void Job::SetForeground() {
  this->in_background = false;
}

Process::Process(process::Thunk* thunk, process::JobControl* job_control, process::JobList* job_list, dev::Tracer* tracer) : ::process::Job() {
  this->thunk = thunk;
  this->job_control = job_control;
  this->job_list = job_list;
  this->tracer = tracer;
  this->parent_pipeline = nullptr;
  this->state_changes = Alloc<List<process::ChildStateChange*>>();
  this->close_r = -1;
  this->close_w = -1;
  this->pid = -1;
  this->status = -1;
}

void Process::Init_ParentPipeline(process::Pipeline* pi) {
  StackRoot _root0(&pi);

  this->parent_pipeline = pi;
}

int Process::ProcessGroupId() {
  if (this->parent_pipeline) {
    return this->parent_pipeline->ProcessGroupId();
  }
  return this->pid;
}

void Process::DisplayJob(int job_id, mylib::Writer* f, int style) {
  BigStr* job_id_str = nullptr;
  StackRoot _root0(&f);
  StackRoot _root1(&job_id_str);

  if (job_id == -1) {
    job_id_str = str906;
  }
  else {
    job_id_str = StrFormat("%%%d", job_id);
  }
  if (style == STYLE_PID_ONLY) {
    f->write(StrFormat("%d\n", this->pid));
  }
  else {
    f->write(StrFormat("%s %d %7s ", job_id_str, this->pid, _JobStateStr(this->state)));
    f->write(this->thunk->UserString());
    f->write(str910);
  }
}

void Process::AddStateChange(process::ChildStateChange* s) {
  StackRoot _root0(&s);

  this->state_changes->append(s);
}

void Process::AddPipeToClose(int r, int w) {
  this->close_r = r;
  this->close_w = w;
}

void Process::MaybeClosePipe() {
  if (this->close_r != -1) {
    posix::close(this->close_r);
    posix::close(this->close_w);
  }
}

int Process::StartProcess(runtime_asdl::trace_t* why) {
  int pid;
  StackRoot _root0(&why);

  pid = posix::fork();
  if (pid < 0) {
    e_die(str911);
  }
  else {
    if (pid == 0) {
      for (ListIter<process::ChildStateChange*> it(this->state_changes); !it.Done(); it.Next()) {
        process::ChildStateChange* st = it.Value();
        StackRoot _for(&st      );
        st->Apply();
      }
      pyos::Sigaction(SIGPIPE, SIG_DFL);
      pyos::Sigaction(SIGQUIT, SIG_DFL);
      pid = posix::getpid();
      if ((posix::getpgid(0) == pid and this->parent_pipeline == nullptr)) {
        pyos::Sigaction(SIGTSTP, SIG_DFL);
      }
      pyos::Sigaction(SIGTTOU, SIG_DFL);
      pyos::Sigaction(SIGTTIN, SIG_DFL);
      this->tracer->OnNewProcess(pid);
      this->thunk->Run();
    }
  }
  this->tracer->OnProcessStart(pid, why);
  this->pid = pid;
  for (ListIter<process::ChildStateChange*> it(this->state_changes); !it.Done(); it.Next()) {
    process::ChildStateChange* st = it.Value();
    StackRoot _for(&st  );
    st->ApplyFromParent(this);
  }
  this->job_list->AddChildProcess(pid, this);
  return pid;
}

int Process::Wait(process::Waiter* waiter) {
  StackRoot _root0(&waiter);

  while (this->state == job_state_e::Running) {
    if (waiter->WaitForOne() == W1_ECHILD) {
      break;
    }
  }
  return this->status;
}

runtime_asdl::wait_status_t* Process::JobWait(process::Waiter* waiter) {
  int result;
  StackRoot _root0(&waiter);

  while (this->state == job_state_e::Running) {
    result = waiter->WaitForOne();
    if (result >= 0) {
      return Alloc<wait_status::Cancelled>(result);
    }
    if (result == W1_ECHILD) {
      break;
    }
  }
  return Alloc<wait_status::Proc>(this->status);
}

void Process::WhenStopped(int stop_sig) {
  this->status = (128 + stop_sig);
  this->state = job_state_e::Stopped;
  if (this->job_id == -1) {
    this->job_list->AddJob(this);
  }
  if (!this->in_background) {
    this->job_control->MaybeTakeTerminal();
    this->SetBackground();
  }
}

void Process::WhenDone(int pid, int status) {
  this->status = status;
  this->state = job_state_e::Done;
  if (this->parent_pipeline) {
    this->parent_pipeline->WhenDone(pid, status);
  }
  else {
    if (this->job_id != -1) {
      if (this->in_background) {
        print_stderr(StrFormat("[%d] Done PID %d", this->job_id, this->pid));
      }
      this->job_list->RemoveJob(this->job_id);
    }
    this->job_list->RemoveChildProcess(this->pid);
    if (!this->in_background) {
      this->job_control->MaybeTakeTerminal();
    }
  }
}

int Process::RunProcess(process::Waiter* waiter, runtime_asdl::trace_t* why) {
  StackRoot _root0(&waiter);
  StackRoot _root1(&why);

  this->StartProcess(why);
  if (this->parent_pipeline == nullptr) {
    this->job_control->MaybeGiveTerminal(posix::getpgid(this->pid));
  }
  return this->Wait(waiter);
}

ctx_Pipe::ctx_Pipe(process::FdState* fd_state, int fd, List<IOError_OSError*>* err_out) {
  gHeap.PushRoot(reinterpret_cast<RawObject**>(&(this->err_out)));
  gHeap.PushRoot(reinterpret_cast<RawObject**>(&(this->fd_state)));
  fd_state->PushStdinFromPipe(fd);
  this->fd_state = fd_state;
  this->err_out = err_out;
}

ctx_Pipe::~ctx_Pipe() {
  this->fd_state->Pop(this->err_out);
  gHeap.PopRoot();
  gHeap.PopRoot();
}

Pipeline::Pipeline(bool sigpipe_status_ok, process::JobControl* job_control, process::JobList* job_list, dev::Tracer* tracer) : ::process::Job() {
  this->job_control = job_control;
  this->job_list = job_list;
  this->tracer = tracer;
  this->procs = Alloc<List<process::Process*>>();
  this->pids = Alloc<List<int>>();
  this->pipe_status = Alloc<List<int>>();
  this->status = -1;
  this->pgid = INVALID_PGID;
  this->last_thunk = nullptr;
  this->last_pipe = nullptr;
  this->sigpipe_status_ok = sigpipe_status_ok;
}

int Pipeline::ProcessGroupId() {
  return this->pgid;
}

void Pipeline::DisplayJob(int job_id, mylib::Writer* f, int style) {
  int i;
  BigStr* job_id_str = nullptr;
  StackRoot _root0(&f);
  StackRoot _root1(&job_id_str);

  if (style == STYLE_PID_ONLY) {
    f->write(StrFormat("%d\n", this->procs->at(0)->pid));
  }
  else {
    i = 0;
    for (ListIter<process::Process*> it(this->procs); !it.Done(); it.Next(), ++i) {
      process::Process* proc = it.Value();
      StackRoot _for(&proc    );
      if (i == 0) {
        job_id_str = StrFormat("%%%d", job_id);
      }
      else {
        job_id_str = str915;
        f->write(StrFormat("%s %d %7s ", job_id_str, proc->pid, _JobStateStr(proc->state)));
        f->write(proc->thunk->UserString());
        f->write(str917);
      }
    }
  }
}

void Pipeline::DebugPrint() {
  print(StrFormat("Pipeline in state %s", _JobStateStr(this->state)));
}

void Pipeline::Add(process::Process* p) {
  int r;
  int w;
  process::Process* prev = nullptr;
  StackRoot _root0(&p);
  StackRoot _root1(&prev);

  if (len(this->procs) == 0) {
    this->procs->append(p);
    return ;
  }
  Tuple2<int, int> tup1 = posix::pipe();
  r = tup1.at0();
  w = tup1.at1();
  prev = this->procs->at(-1);
  prev->AddStateChange(Alloc<StdoutToPipe>(r, w));
  p->AddStateChange(Alloc<StdinFromPipe>(r, w));
  p->AddPipeToClose(r, w);
  this->procs->append(p);
}

void Pipeline::AddLast(Tuple2<cmd_eval::CommandEvaluator*, syntax_asdl::command_t*>* thunk) {
  int r;
  int w;
  process::Process* prev = nullptr;
  StackRoot _root0(&thunk);
  StackRoot _root1(&prev);

  this->last_thunk = thunk;
  Tuple2<int, int> tup2 = posix::pipe();
  r = tup2.at0();
  w = tup2.at1();
  prev = this->procs->at(-1);
  prev->AddStateChange(Alloc<StdoutToPipe>(r, w));
  this->last_pipe = (Alloc<Tuple2<int, int>>(r, w));
}

void Pipeline::StartPipeline(process::Waiter* waiter) {
  int i;
  int pid;
  StackRoot _root0(&waiter);

  if (this->job_control->Enabled()) {
    this->pgid = OWN_LEADER;
  }
  i = 0;
  for (ListIter<process::Process*> it(this->procs); !it.Done(); it.Next(), ++i) {
    process::Process* proc = it.Value();
    StackRoot _for(&proc  );
    if (this->pgid != INVALID_PGID) {
      proc->AddStateChange(Alloc<SetPgid>(this->pgid, this->tracer));
    }
    pid = proc->StartProcess(trace::PipelinePart);
    if ((i == 0 and this->pgid != INVALID_PGID)) {
      this->pgid = pid;
    }
    this->pids->append(pid);
    this->pipe_status->append(-1);
    proc->MaybeClosePipe();
  }
  if (this->last_thunk) {
    this->pipe_status->append(-1);
  }
}

int Pipeline::LastPid() {
  return this->pids->at(-1);
}

List<int>* Pipeline::Wait(process::Waiter* waiter) {
  StackRoot _root0(&waiter);

  while (this->state == job_state_e::Running) {
    if (waiter->WaitForOne() == W1_ECHILD) {
      break;
    }
  }
  return this->pipe_status;
}

runtime_asdl::wait_status_t* Pipeline::JobWait(process::Waiter* waiter) {
  int result;
  StackRoot _root0(&waiter);

  while (this->state == job_state_e::Running) {
    result = waiter->WaitForOne();
    if (result >= 0) {
      return Alloc<wait_status::Cancelled>(result);
    }
    if (result == W1_ECHILD) {
      break;
    }
  }
  return Alloc<wait_status::Pipeline>(this->pipe_status);
}

List<int>* Pipeline::RunLastPart(process::Waiter* waiter, process::FdState* fd_state) {
  cmd_eval::CommandEvaluator* cmd_ev = nullptr;
  syntax_asdl::command_t* last_node = nullptr;
  int r;
  int w;
  int cmd_flags;
  List<IOError_OSError*>* io_errors = nullptr;
  StackRoot _root0(&waiter);
  StackRoot _root1(&fd_state);
  StackRoot _root2(&cmd_ev);
  StackRoot _root3(&last_node);
  StackRoot _root4(&io_errors);

  this->job_control->MaybeGiveTerminal(this->pgid);
  Tuple2<cmd_eval::CommandEvaluator*, syntax_asdl::command_t*>* tup3 = this->last_thunk;
  cmd_ev = tup3->at0();
  last_node = tup3->at1();
  Tuple2<int, int>* tup4 = this->last_pipe;
  r = tup4->at0();
  w = tup4->at1();
  posix::close(w);
  cmd_flags = this->job_control->Enabled() ? cmd_eval::NoDebugTrap : 0;
  cmd_flags |= cmd_eval::NoErrTrap;
  io_errors = Alloc<List<IOError_OSError*>>();
  {  // with
    ctx_Pipe ctx{fd_state, r, io_errors};

    cmd_ev->ExecuteAndCatch(last_node, cmd_flags);
  }
  if (len(io_errors)) {
    e_die(StrFormat("Error setting up last part of pipeline: %s", pyutil::strerror(io_errors->at(0))));
  }
  posix::close(r);
  this->pipe_status->set(-1, cmd_ev->LastStatus());
  if (this->AllDone()) {
    this->state = job_state_e::Done;
  }
  return this->Wait(waiter);
}

bool Pipeline::AllDone() {
  for (ListIter<int> it(this->pipe_status); !it.Done(); it.Next()) {
    int status = it.Value();
    if (status == -1) {
      return false;
    }
  }
  return true;
}

void Pipeline::WhenDone(int pid, int status) {
  int i;
  i = this->pids->index(pid);
  if ((status == 141 and this->sigpipe_status_ok)) {
    status = 0;
  }
  this->job_list->RemoveChildProcess(pid);
  this->pipe_status->set(i, status);
  if (this->AllDone()) {
    if (this->job_id != -1) {
      if (this->in_background) {
        print_stderr(StrFormat("[%d] Done PGID %d", this->job_id, this->pids->at(0)));
      }
      this->job_list->RemoveJob(this->job_id);
    }
    this->status = this->pipe_status->at(-1);
    this->state = job_state_e::Done;
    if (!this->in_background) {
      this->job_control->MaybeTakeTerminal();
    }
  }
}

BigStr* _JobStateStr(runtime_asdl::job_state_t i) {
  return job_state_str(i)->slice(10);
}

int _GetTtyFd() {
  try {
    return posix::open(str921, ((O_NONBLOCK | O_NOCTTY) | O_RDWR), 438);
  }
  catch (IOError_OSError* e) {
    return -1;
  }
}

ctx_TerminalControl::ctx_TerminalControl(process::JobControl* job_control, ui::ErrorFormatter* errfmt) {
  gHeap.PushRoot(reinterpret_cast<RawObject**>(&(this->errfmt)));
  gHeap.PushRoot(reinterpret_cast<RawObject**>(&(this->job_control)));
  job_control->InitJobControl();
  this->job_control = job_control;
  this->errfmt = errfmt;
}

ctx_TerminalControl::~ctx_TerminalControl() {
  try {
    this->job_control->MaybeReturnTerminal();
  }
  catch (error::FatalRuntime* e) {
    this->errfmt->PrettyPrintError(e);
  }
  gHeap.PopRoot();
  gHeap.PopRoot();
}

JobControl::JobControl() {
  this->shell_pid = -1;
  this->shell_pgid = -1;
  this->shell_tty_fd = -1;
  this->original_tty_pgid = -1;
}

void JobControl::InitJobControl() {
  int orig_shell_pgid;
  this->shell_pid = posix::getpid();
  orig_shell_pgid = posix::getpgid(0);
  this->shell_pgid = orig_shell_pgid;
  this->shell_tty_fd = _GetTtyFd();
  if (this->shell_pgid != this->shell_pid) {
    try {
      posix::setpgid(this->shell_pid, this->shell_pid);
      this->shell_pgid = this->shell_pid;
    }
    catch (IOError_OSError* e) {
      this->shell_tty_fd = -1;
    }
  }
  if (this->shell_tty_fd != -1) {
    this->original_tty_pgid = posix::tcgetpgrp(this->shell_tty_fd);
    try {
      posix::tcsetpgrp(this->shell_tty_fd, this->shell_pgid);
    }
    catch (IOError_OSError* e) {
      this->shell_tty_fd = -1;
      this->shell_pgid = orig_shell_pgid;
      posix::setpgid(this->shell_pid, this->shell_pgid);
    }
  }
}

bool JobControl::Enabled() {
  int curr_pid;
  curr_pid = posix::getpid();
  return (curr_pid == this->shell_pid and this->shell_tty_fd != -1);
}

void JobControl::MaybeGiveTerminal(int pgid) {
  if (!this->Enabled()) {
    return ;
  }
  try {
    posix::tcsetpgrp(this->shell_tty_fd, pgid);
  }
  catch (IOError_OSError* e) {
    e_die(StrFormat("osh: Failed to move process group %d to foreground: %s", pgid, pyutil::strerror(e)));
  }
}

void JobControl::MaybeTakeTerminal() {
  this->MaybeGiveTerminal(this->shell_pgid);
}

void JobControl::MaybeReturnTerminal() {
  this->MaybeGiveTerminal(this->original_tty_pgid);
}

JobList::JobList() {
  this->jobs = Alloc<Dict<int, process::Job*>>();
  this->child_procs = Alloc<Dict<int, process::Process*>>();
  this->debug_pipelines = Alloc<List<process::Pipeline*>>();
  this->job_id = 1;
}

int JobList::AddJob(process::Job* job) {
  int job_id;
  StackRoot _root0(&job);

  job_id = this->job_id;
  this->jobs->set(job_id, job);
  job->job_id = job_id;
  this->job_id += 1;
  return job_id;
}

void JobList::RemoveJob(int job_id) {
  mylib::dict_erase(this->jobs, job_id);
  if (len(this->jobs) == 0) {
    this->job_id = 1;
  }
}

void JobList::AddChildProcess(int pid, process::Process* proc) {
  StackRoot _root0(&proc);

  this->child_procs->set(pid, proc);
}

void JobList::RemoveChildProcess(int pid) {
  mylib::dict_erase(this->child_procs, pid);
}

process::Process* JobList::ProcessFromPid(int pid) {
  return this->child_procs->get(pid);
}

Tuple2<process::Job*, process::Job*> JobList::GetCurrentAndPreviousJobs() {
  List<process::Job*>* stopped_jobs = nullptr;
  List<process::Job*>* running_jobs = nullptr;
  process::Job* job = nullptr;
  process::Job* current = nullptr;
  process::Job* previous = nullptr;
  StackRoot _root0(&stopped_jobs);
  StackRoot _root1(&running_jobs);
  StackRoot _root2(&job);
  StackRoot _root3(&current);
  StackRoot _root4(&previous);

  stopped_jobs = Alloc<List<process::Job*>>();
  running_jobs = Alloc<List<process::Job*>>();
  for (int i = 0; i < this->job_id; ++i) {
    job = this->jobs->get(i, nullptr);
    if (!job) {
      continue;
    }
    if (job->state == job_state_e::Stopped) {
      stopped_jobs->append(job);
    }
    else {
      if (job->state == job_state_e::Running) {
        running_jobs->append(job);
      }
    }
  }
  current = nullptr;
  previous = nullptr;
  if (len(stopped_jobs) > 0) {
    current = stopped_jobs->pop();
  }
  if (len(stopped_jobs) > 0) {
    previous = stopped_jobs->pop();
  }
  if ((len(running_jobs) > 0 and !current)) {
    current = running_jobs->pop();
  }
  if ((len(running_jobs) > 0 and !previous)) {
    previous = running_jobs->pop();
  }
  if (!previous) {
    previous = current;
  }
  return Tuple2<process::Job*, process::Job*>(current, previous);
}

process::Job* JobList::GetJobWithSpec(BigStr* job_spec) {
  process::Job* current = nullptr;
  process::Job* previous = nullptr;
  List<BigStr*>* m = nullptr;
  int job_id;
  StackRoot _root0(&job_spec);
  StackRoot _root1(&current);
  StackRoot _root2(&previous);
  StackRoot _root3(&m);

  if (list_contains(CURRENT_JOB_SPECS, job_spec)) {
    Tuple2<process::Job*, process::Job*> tup5 = this->GetCurrentAndPreviousJobs();
    current = tup5.at0();
    return current;
  }
  if (str_equals(job_spec, str923)) {
    Tuple2<process::Job*, process::Job*> tup6 = this->GetCurrentAndPreviousJobs();
    previous = tup6.at1();
    return previous;
  }
  m = util::RegexSearch(str924, job_spec);
  if (m != nullptr) {
    job_id = to_int(m->at(1));
    if (dict_contains(this->jobs, job_id)) {
      return this->jobs->at(job_id);
    }
  }
  return nullptr;
}

void JobList::DisplayJobs(int style) {
  mylib::Writer* f = nullptr;
  StackRoot _root0(&f);

  f = mylib::Stdout();
  for (DictIter<int, process::Job*> it(this->jobs); !it.Done(); it.Next()) {
    int job_id = it.Key();
    process::Job* job = it.Value();
    job->DisplayJob(job_id, f, style);
  }
}

void JobList::DebugPrint() {
  mylib::Writer* f = nullptr;
  StackRoot _root0(&f);

  f = mylib::Stdout();
  f->write(str925);
  f->write(str926);
  for (DictIter<int, process::Process*> it(this->child_procs); !it.Done(); it.Next()) {
    int pid = it.Key();
    process::Process* proc = it.Value();
    proc->DisplayJob(-1, f, STYLE_DEFAULT);
  }
  if (len(this->debug_pipelines)) {
    f->write(str927);
    f->write(str928);
    for (ListIter<process::Pipeline*> it(this->debug_pipelines); !it.Done(); it.Next()) {
      process::Pipeline* pi = it.Value();
      StackRoot _for(&pi    );
      pi->DebugPrint();
    }
  }
}

void JobList::ListRecent() {
  ;  // pass
}

int JobList::NumRunning() {
  int count;
  count = 0;
  for (DictIter<int, process::Job*> it(this->jobs); !it.Done(); it.Next()) {
    int _ = it.Key();
    process::Job* job = it.Value();
    if (job->State() == job_state_e::Running) {
      count += 1;
    }
  }
  return count;
}
int W1_OK = -2;
int W1_ECHILD = -3;
int W1_AGAIN = -4;

Waiter::Waiter(process::JobList* job_list, optview::Exec* exec_opts, pyos::SignalSafe* signal_safe, dev::Tracer* tracer) {
  this->job_list = job_list;
  this->exec_opts = exec_opts;
  this->signal_safe = signal_safe;
  this->tracer = tracer;
  this->last_status = 127;
}

int Waiter::WaitForOne(int waitpid_options) {
  int pid;
  int status;
  int err_num;
  process::Process* proc = nullptr;
  int term_sig;
  int stop_sig;
  StackRoot _root0(&proc);

  Tuple2<int, int> tup7 = pyos::WaitPid(waitpid_options);
  pid = tup7.at0();
  status = tup7.at1();
  if (pid == 0) {
    return W1_AGAIN;
  }
  else {
    if (pid < 0) {
      err_num = status;
      if (err_num == ECHILD) {
        return W1_ECHILD;
      }
      else {
        if (err_num == EINTR) {
          return this->signal_safe->LastSignal();
        }
        else {
          assert(0);  // AssertionError
        }
      }
    }
  }
  if (!dict_contains(this->job_list->child_procs, pid)) {
    print_stderr(StrFormat("osh: PID %d stopped, but osh didn't start it", pid));
    return W1_OK;
  }
  proc = this->job_list->child_procs->at(pid);
  if (WIFSIGNALED(status)) {
    term_sig = WTERMSIG(status);
    status = (128 + term_sig);
    if (term_sig == SIGINT) {
      print(str930);
    }
    proc->WhenDone(pid, status);
  }
  else {
    if (WIFEXITED(status)) {
      status = WEXITSTATUS(status);
      proc->WhenDone(pid, status);
    }
    else {
      if (WIFSTOPPED(status)) {
        stop_sig = WSTOPSIG(status);
        print_stderr(str931);
        print_stderr(StrFormat("[PID %d] Stopped with signal %d", pid, stop_sig));
        proc->WhenStopped(stop_sig);
      }
      else {
        assert(0);  // AssertionError
      }
    }
  }
  this->last_status = status;
  this->tracer->OnProcessEnd(pid, status);
  return W1_OK;
}

void Waiter::PollNotifications() {
  while (this->WaitForOne(WNOHANG) == W1_OK) {
    continue;
  }
}

}  // define namespace process

namespace state {  // define

using id_kind_asdl::Id;
using option_asdl::option_i;
using runtime_asdl::scope_e;
using runtime_asdl::scope_t;
using runtime_asdl::Cell;
using syntax_asdl::loc;
using syntax_asdl::loc_t;
using syntax_asdl::Token;
using syntax_asdl::debug_frame;
using syntax_asdl::debug_frame_e;
using syntax_asdl::debug_frame_t;
using types_asdl::opt_group_i;
using value_asdl::value;
using value_asdl::value_e;
using value_asdl::value_t;
using value_asdl::sh_lvalue;
using value_asdl::sh_lvalue_e;
using value_asdl::sh_lvalue_t;
using value_asdl::LeftName;
using value_asdl::y_lvalue_e;
using value_asdl::regex_match;
using value_asdl::regex_match_e;
using value_asdl::regex_match_t;
using value_asdl::RegexMatch;
using error::e_usage;
using error::e_die;
using mylib::print_stderr;
BigStr* _READLINE_DELIMS = str933;
int SetReadOnly = (1 << 0);
int ClearReadOnly = (1 << 1);
int SetExport = (1 << 2);
int ClearExport = (1 << 3);
int SetNameref = (1 << 4);
int ClearNameref = (1 << 5);

BigStr* LookupExecutable(BigStr* name, List<BigStr*>* path_dirs, bool exec_required) {
  BigStr* full_path = nullptr;
  bool found;
  StackRoot _root0(&name);
  StackRoot _root1(&path_dirs);
  StackRoot _root2(&full_path);

  if (len(name) == 0) {
    return nullptr;
  }
  if (str_contains(name, str934)) {
    return path_stat::exists(name) ? name : nullptr;
  }
  for (ListIter<BigStr*> it(path_dirs); !it.Done(); it.Next()) {
    BigStr* path_dir = it.Value();
    StackRoot _for(&path_dir  );
    full_path = os_path::join(path_dir, name);
    if (exec_required) {
      found = posix::access(full_path, X_OK);
    }
    else {
      found = path_stat::exists(full_path);
    }
    if (found) {
      return full_path;
    }
  }
  return nullptr;
}

SearchPath::SearchPath(state::Mem* mem) {
  this->mem = mem;
  this->cache = Alloc<Dict<BigStr*, BigStr*>>();
}

List<BigStr*>* SearchPath::_GetPath() {
  value_asdl::value_t* val = nullptr;
  value_asdl::value_t* UP_val = nullptr;
  StackRoot _root0(&val);
  StackRoot _root1(&UP_val);

  val = this->mem->GetValue(str935);
  UP_val = val;
  if (val->tag() == value_e::Str) {
    value::Str* val = static_cast<value::Str*>(UP_val);
    return val->s->split(str936);
  }
  else {
    return Alloc<List<BigStr*>>();
  }
}

BigStr* SearchPath::LookupOne(BigStr* name, bool exec_required) {
  StackRoot _root0(&name);

  return LookupExecutable(name, this->_GetPath(), exec_required);
}

List<BigStr*>* SearchPath::LookupReflect(BigStr* name, bool do_all) {
  List<BigStr*>* results = nullptr;
  BigStr* full_path = nullptr;
  StackRoot _root0(&name);
  StackRoot _root1(&results);
  StackRoot _root2(&full_path);

  if (len(name) == 0) {
    return Alloc<List<BigStr*>>();
  }
  if (str_contains(name, str937)) {
    if (path_stat::exists(name)) {
      return NewList<BigStr*>(std::initializer_list<BigStr*>{name});
    }
    else {
      return Alloc<List<BigStr*>>();
    }
  }
  results = Alloc<List<BigStr*>>();
  for (ListIter<BigStr*> it(this->_GetPath()); !it.Done(); it.Next()) {
    BigStr* path_dir = it.Value();
    StackRoot _for(&path_dir  );
    full_path = os_path::join(path_dir, name);
    if (path_stat::exists(full_path)) {
      results->append(full_path);
      if (!do_all) {
        return results;
      }
    }
  }
  return results;
}

BigStr* SearchPath::CachedLookup(BigStr* name) {
  BigStr* full_path = nullptr;
  StackRoot _root0(&name);
  StackRoot _root1(&full_path);

  if (dict_contains(this->cache, name)) {
    return this->cache->at(name);
  }
  full_path = this->LookupOne(name);
  if (full_path != nullptr) {
    this->cache->set(name, full_path);
  }
  return full_path;
}

void SearchPath::MaybeRemoveEntry(BigStr* name) {
  StackRoot _root0(&name);

  mylib::dict_erase(this->cache, name);
}

void SearchPath::ClearCache() {
  this->cache->clear();
}

List<BigStr*>* SearchPath::CachedCommands() {
  return this->cache->values();
}

ctx_Source::ctx_Source(state::Mem* mem, BigStr* source_name, List<BigStr*>* argv) {
  gHeap.PushRoot(reinterpret_cast<RawObject**>(&(this->argv)));
  gHeap.PushRoot(reinterpret_cast<RawObject**>(&(this->mem)));
  mem->PushSource(source_name, argv);
  this->mem = mem;
  this->argv = argv;
  this->to_restore = this->mem->is_main;
  this->mem->is_main = false;
}

ctx_Source::~ctx_Source() {
  this->mem->PopSource(this->argv);
  this->mem->is_main = this->to_restore;
  gHeap.PopRoot();
  gHeap.PopRoot();
}

ctx_DebugTrap::ctx_DebugTrap(state::Mem* mem) {
  gHeap.PushRoot(reinterpret_cast<RawObject**>(&(this->mem)));
  mem->running_debug_trap = true;
  this->mem = mem;
}

ctx_DebugTrap::~ctx_DebugTrap() {
  this->mem->running_debug_trap = false;
  gHeap.PopRoot();
}

ctx_ErrTrap::ctx_ErrTrap(state::Mem* mem) {
  gHeap.PushRoot(reinterpret_cast<RawObject**>(&(this->mem)));
  mem->running_err_trap = true;
  this->mem = mem;
}

ctx_ErrTrap::~ctx_ErrTrap() {
  this->mem->running_err_trap = false;
  gHeap.PopRoot();
}

ctx_Option::ctx_Option(state::MutableOpts* mutable_opts, List<int>* opt_nums, bool b) {
  gHeap.PushRoot(reinterpret_cast<RawObject**>(&(this->mutable_opts)));
  gHeap.PushRoot(reinterpret_cast<RawObject**>(&(this->opt_nums)));
  for (ListIter<int> it(opt_nums); !it.Done(); it.Next()) {
    int opt_num = it.Value();
    mutable_opts->Push(opt_num, b);
    if (opt_num == option_i::errexit) {
      mutable_opts->errexit_disabled_tok->append(nullptr);
    }
  }
  this->mutable_opts = mutable_opts;
  this->opt_nums = opt_nums;
}

ctx_Option::~ctx_Option() {
  for (ListIter<int> it(this->opt_nums); !it.Done(); it.Next()) {
    int opt_num = it.Value();
    if (opt_num == option_i::errexit) {
      this->mutable_opts->errexit_disabled_tok->pop();
    }
    this->mutable_opts->Pop(opt_num);
  }
  gHeap.PopRoot();
  gHeap.PopRoot();
}

ctx_AssignBuiltin::ctx_AssignBuiltin(state::MutableOpts* mutable_opts) {
  gHeap.PushRoot(reinterpret_cast<RawObject**>(&(this->mutable_opts)));
  this->strict = false;
  if (mutable_opts->Get(option_i::strict_errexit)) {
    mutable_opts->Push(option_i::_allow_command_sub, false);
    mutable_opts->Push(option_i::_allow_process_sub, false);
    this->strict = true;
  }
  this->mutable_opts = mutable_opts;
}

ctx_AssignBuiltin::~ctx_AssignBuiltin() {
  if (this->strict) {
    this->mutable_opts->Pop(option_i::_allow_command_sub);
    this->mutable_opts->Pop(option_i::_allow_process_sub);
  }
  gHeap.PopRoot();
}

ctx_YshExpr::ctx_YshExpr(state::MutableOpts* mutable_opts) {
  gHeap.PushRoot(reinterpret_cast<RawObject**>(&(this->mutable_opts)));
  mutable_opts->Push(option_i::command_sub_errexit, true);
  this->mutable_opts = mutable_opts;
}

ctx_YshExpr::~ctx_YshExpr() {
  this->mutable_opts->Pop(option_i::command_sub_errexit);
  gHeap.PopRoot();
}

ctx_ErrExit::ctx_ErrExit(state::MutableOpts* mutable_opts, bool b, syntax_asdl::Token* disabled_tok) {
  gHeap.PushRoot(reinterpret_cast<RawObject**>(&(this->mutable_opts)));
  mutable_opts->Push(option_i::errexit, b);
  mutable_opts->errexit_disabled_tok->append(disabled_tok);
  this->strict = false;
  if (mutable_opts->Get(option_i::strict_errexit)) {
    mutable_opts->Push(option_i::_allow_command_sub, false);
    mutable_opts->Push(option_i::_allow_process_sub, false);
    this->strict = true;
  }
  this->mutable_opts = mutable_opts;
}

ctx_ErrExit::~ctx_ErrExit() {
  this->mutable_opts->errexit_disabled_tok->pop();
  this->mutable_opts->Pop(option_i::errexit);
  if (this->strict) {
    this->mutable_opts->Pop(option_i::_allow_command_sub);
    this->mutable_opts->Pop(option_i::_allow_process_sub);
  }
  gHeap.PopRoot();
}

OptHook::OptHook() {
  ;  // pass
}

bool OptHook::OnChange(List<bool>* opt0_array, BigStr* opt_name, bool b) {
  StackRoot _root0(&opt0_array);
  StackRoot _root1(&opt_name);

  return true;
}

List<bool>* InitOpts() {
  List<bool>* opt0_array = nullptr;
  StackRoot _root0(&opt0_array);

  opt0_array = list_repeat(false, option_i::ARRAY_SIZE);
  for (ListIter<int> it(consts::DEFAULT_TRUE); !it.Done(); it.Next()) {
    int opt_num = it.Value();
    opt0_array->set(opt_num, true);
  }
  return opt0_array;
}

Tuple3<optview::Parse*, optview::Exec*, state::MutableOpts*> MakeOpts(state::Mem* mem, state::OptHook* opt_hook) {
  List<bool>* opt0_array = nullptr;
  List<bool>* no_stack = nullptr;
  List<List<bool>*>* opt_stacks = nullptr;
  optview::Parse* parse_opts = nullptr;
  optview::Exec* exec_opts = nullptr;
  state::MutableOpts* mutable_opts = nullptr;
  StackRoot _root0(&mem);
  StackRoot _root1(&opt_hook);
  StackRoot _root2(&opt0_array);
  StackRoot _root3(&no_stack);
  StackRoot _root4(&opt_stacks);
  StackRoot _root5(&parse_opts);
  StackRoot _root6(&exec_opts);
  StackRoot _root7(&mutable_opts);

  opt0_array = InitOpts();
  no_stack = nullptr;
  opt_stacks = list_repeat(no_stack, option_i::ARRAY_SIZE);
  parse_opts = Alloc<optview::Parse>(opt0_array, opt_stacks);
  exec_opts = Alloc<optview::Exec>(opt0_array, opt_stacks);
  mutable_opts = Alloc<MutableOpts>(mem, opt0_array, opt_stacks, opt_hook);
  return Tuple3<optview::Parse*, optview::Exec*, state::MutableOpts*>(parse_opts, exec_opts, mutable_opts);
}

void _SetGroup(List<bool>* opt0_array, List<int>* opt_nums, bool b) {
  bool b2;
  StackRoot _root0(&opt0_array);
  StackRoot _root1(&opt_nums);

  for (ListIter<int> it(opt_nums); !it.Done(); it.Next()) {
    int opt_num = it.Value();
    b2 = list_contains(consts::DEFAULT_TRUE, opt_num) ? !b : b;
    opt0_array->set(opt_num, b2);
  }
}

optview::Parse* MakeOilOpts() {
  List<bool>* opt0_array = nullptr;
  List<bool>* no_stack = nullptr;
  List<List<bool>*>* opt_stacks = nullptr;
  optview::Parse* parse_opts = nullptr;
  StackRoot _root0(&opt0_array);
  StackRoot _root1(&no_stack);
  StackRoot _root2(&opt_stacks);
  StackRoot _root3(&parse_opts);

  opt0_array = InitOpts();
  _SetGroup(opt0_array, consts::YSH_ALL, true);
  no_stack = nullptr;
  opt_stacks = list_repeat(no_stack, option_i::ARRAY_SIZE);
  parse_opts = Alloc<optview::Parse>(opt0_array, opt_stacks);
  return parse_opts;
}

int _AnyOptionNum(BigStr* opt_name) {
  int opt_num;
  StackRoot _root0(&opt_name);

  opt_num = consts::OptionNum(opt_name);
  if (opt_num == 0) {
    e_usage(StrFormat("got invalid option %r", opt_name), loc::Missing);
  }
  return opt_num;
}

int _SetOptionNum(BigStr* opt_name) {
  int opt_num;
  StackRoot _root0(&opt_name);

  opt_num = consts::OptionNum(opt_name);
  if (opt_num == 0) {
    e_usage(StrFormat("got invalid option %r", opt_name), loc::Missing);
  }
  if (!list_contains(consts::SET_OPTION_NUMS, opt_num)) {
    e_usage(StrFormat("invalid option %r (try shopt)", opt_name), loc::Missing);
  }
  return opt_num;
}

MutableOpts::MutableOpts(state::Mem* mem, List<bool>* opt0_array, List<List<bool>*>* opt_stacks, state::OptHook* opt_hook) {
  this->mem = mem;
  this->opt0_array = opt0_array;
  this->opt_stacks = opt_stacks;
  this->errexit_disabled_tok = Alloc<List<syntax_asdl::Token*>>();
  this->opt_hook = opt_hook;
}

void MutableOpts::Init() {
  value_asdl::value_t* UP_shellopts = nullptr;
  StackRoot _root0(&UP_shellopts);

  UP_shellopts = this->mem->GetValue(str941);
  if (UP_shellopts->tag() == value_e::Str) {
    value::Str* shellopts = static_cast<value::Str*>(UP_shellopts);
    this->_InitOptionsFromEnv(shellopts->s);
  }
}

void MutableOpts::_InitOptionsFromEnv(BigStr* shellopts) {
  List<BigStr*>* lookup = nullptr;
  BigStr* name = nullptr;
  StackRoot _root0(&shellopts);
  StackRoot _root1(&lookup);
  StackRoot _root2(&name);

  lookup = shellopts->split(str942);
  for (ListIter<int> it(consts::SET_OPTION_NUMS); !it.Done(); it.Next()) {
    int opt_num = it.Value();
    name = consts::OptionName(opt_num);
    if (list_contains(lookup, name)) {
      this->_SetOldOption(name, true);
    }
  }
}

void MutableOpts::Push(int opt_num, bool b) {
  List<bool>* overlay = nullptr;
  StackRoot _root0(&overlay);

  overlay = this->opt_stacks->at(opt_num);
  if ((overlay == nullptr or len(overlay) == 0)) {
    this->opt_stacks->set(opt_num, NewList<bool>(std::initializer_list<bool>{b}));
  }
  else {
    overlay->append(b);
  }
}

bool MutableOpts::Pop(int opt_num) {
  List<bool>* overlay = nullptr;
  StackRoot _root0(&overlay);

  overlay = this->opt_stacks->at(opt_num);
  return overlay->pop();
}

void MutableOpts::PushDynamicScope(bool b) {
  if (!this->Get(option_i::dynamic_scope)) {
    b = false;
  }
  this->Push(option_i::dynamic_scope, b);
}

void MutableOpts::PopDynamicScope() {
  this->Pop(option_i::dynamic_scope);
}

bool MutableOpts::Get(int opt_num) {
  List<bool>* overlay = nullptr;
  StackRoot _root0(&overlay);

  overlay = this->opt_stacks->at(opt_num);
  if ((overlay == nullptr or len(overlay) == 0)) {
    return this->opt0_array->at(opt_num);
  }
  else {
    return overlay->at(-1);
  }
}

void MutableOpts::_Set(int opt_num, bool b) {
  List<bool>* overlay = nullptr;
  StackRoot _root0(&overlay);

  overlay = this->opt_stacks->at(opt_num);
  if ((overlay == nullptr or len(overlay) == 0)) {
    this->opt0_array->set(opt_num, b);
  }
  else {
    overlay->set(-1, b);
  }
}

void MutableOpts::set_interactive() {
  this->_Set(option_i::interactive, true);
}

void MutableOpts::set_redefine_proc_func() {
  this->_Set(option_i::redefine_proc_func, true);
}

void MutableOpts::set_redefine_module() {
  this->_Set(option_i::redefine_module, true);
}

void MutableOpts::set_emacs() {
  this->_Set(option_i::emacs, true);
}

void MutableOpts::set_xtrace(bool b) {
  this->_Set(option_i::xtrace, b);
}

void MutableOpts::_SetArrayByNum(int opt_num, bool b) {
  if ((list_contains(consts::PARSE_OPTION_NUMS, opt_num) and !this->mem->ParsingChangesAllowed())) {
    e_die(str943);
  }
  this->_Set(opt_num, b);
}

void MutableOpts::SetDeferredErrExit(bool b) {
  this->opt0_array->set(option_i::errexit, b);
}

void MutableOpts::DisableErrExit() {
  this->_Set(option_i::errexit, false);
}

syntax_asdl::Token* MutableOpts::ErrExitDisabledToken() {
  if (this->Get(option_i::_running_trap)) {
    return nullptr;
  }
  if (len(this->errexit_disabled_tok) == 0) {
    return nullptr;
  }
  return this->errexit_disabled_tok->at(-1);
}

bool MutableOpts::ErrExitIsDisabled() {
  if (len(this->errexit_disabled_tok) == 0) {
    return false;
  }
  return this->errexit_disabled_tok->at(-1) != nullptr;
}

void MutableOpts::_SetOldOption(BigStr* opt_name, bool b) {
  int opt_num;
  bool success;
  StackRoot _root0(&opt_name);

  opt_num = consts::OptionNum(opt_name);
  if (opt_num == option_i::errexit) {
    this->SetDeferredErrExit(b);
  }
  else {
    if ((opt_num == option_i::verbose and b)) {
      print_stderr(str944);
    }
    this->_SetArrayByNum(opt_num, b);
  }
  success = this->opt_hook->OnChange(this->opt0_array, opt_name, b);
}

void MutableOpts::SetOldOption(BigStr* opt_name, bool b) {
  int unused;
  value_asdl::value_t* UP_val = nullptr;
  BigStr* shellopts = nullptr;
  value::Str* new_val = nullptr;
  List<BigStr*>* names = nullptr;
  StackRoot _root0(&opt_name);
  StackRoot _root1(&UP_val);
  StackRoot _root2(&shellopts);
  StackRoot _root3(&new_val);
  StackRoot _root4(&names);

  unused = _SetOptionNum(opt_name);
  this->_SetOldOption(opt_name, b);
  UP_val = this->mem->GetValue(str945);
  value::Str* val = static_cast<value::Str*>(UP_val);
  shellopts = val->s;
  if (b) {
    if (!str_contains(shellopts, opt_name)) {
      new_val = Alloc<value::Str>(StrFormat("%s:%s", shellopts, opt_name));
      this->mem->InternalSetGlobal(str947, new_val);
    }
  }
  else {
    if (str_contains(shellopts, opt_name)) {
      names = Alloc<List<BigStr*>>();
      for (ListIter<BigStr*> it(shellopts->split(str948)); !it.Done(); it.Next()) {
        BigStr* n = it.Value();
        if (!(str_equals(n, opt_name))) {
          names->append(n);
        }
      }
      new_val = Alloc<value::Str>(str949->join(names));
      this->mem->InternalSetGlobal(str950, new_val);
    }
  }
}

void MutableOpts::SetAnyOption(BigStr* opt_name, bool b) {
  int opt_group;
  int opt_num;
  StackRoot _root0(&opt_name);

  opt_group = consts::OptionGroupNum(opt_name);
  if (opt_group == opt_group_i::YshUpgrade) {
    _SetGroup(this->opt0_array, consts::YSH_UPGRADE, b);
    this->SetDeferredErrExit(b);
    return ;
  }
  if (opt_group == opt_group_i::YshAll) {
    _SetGroup(this->opt0_array, consts::YSH_ALL, b);
    this->SetDeferredErrExit(b);
    return ;
  }
  if (opt_group == opt_group_i::StrictAll) {
    _SetGroup(this->opt0_array, consts::STRICT_ALL, b);
    return ;
  }
  opt_num = _AnyOptionNum(opt_name);
  if (opt_num == option_i::errexit) {
    this->SetDeferredErrExit(b);
    return ;
  }
  this->_SetArrayByNum(opt_num, b);
}

void MutableOpts::ShowOptions(List<BigStr*>* opt_names) {
  int opt_num;
  bool b;
  StackRoot _root0(&opt_names);

  if (len(opt_names) == 0) {
    opt_names = Alloc<List<BigStr*>>();
    for (ListIter<int> it(consts::SET_OPTION_NUMS); !it.Done(); it.Next()) {
      int i = it.Value();
      opt_names->append(consts::OptionName(i));
    }
  }
  for (ListIter<BigStr*> it(opt_names); !it.Done(); it.Next()) {
    BigStr* opt_name = it.Value();
    StackRoot _for(&opt_name  );
    opt_num = _SetOptionNum(opt_name);
    b = this->Get(opt_num);
    print(StrFormat("set %so %s", b ? str952 : str953, opt_name));
  }
}

void MutableOpts::ShowShoptOptions(List<BigStr*>* opt_names) {
  List<int>* opt_nums = nullptr;
  int opt_group;
  int index;
  bool b;
  StackRoot _root0(&opt_names);
  StackRoot _root1(&opt_nums);

  opt_nums = Alloc<List<int>>();
  for (ListIter<BigStr*> it(opt_names); !it.Done(); it.Next()) {
    BigStr* opt_name = it.Value();
    StackRoot _for(&opt_name  );
    opt_group = consts::OptionGroupNum(opt_name);
    if (opt_group == opt_group_i::YshUpgrade) {
      opt_nums->extend(consts::YSH_UPGRADE);
    }
    else {
      if (opt_group == opt_group_i::YshAll) {
        opt_nums->extend(consts::YSH_ALL);
      }
      else {
        if (opt_group == opt_group_i::StrictAll) {
          opt_nums->extend(consts::STRICT_ALL);
        }
        else {
          index = consts::OptionNum(opt_name);
          if (index == 0) {
            e_usage(StrFormat("got invalid option %r", opt_name), loc::Missing);
          }
          opt_nums->append(index);
        }
      }
    }
  }
  if (len(opt_names) == 0) {
    opt_nums->extend(consts::VISIBLE_SHOPT_NUMS);
  }
  for (ListIter<int> it(opt_nums); !it.Done(); it.Next()) {
    int opt_num = it.Value();
    b = this->Get(opt_num);
    print(StrFormat("shopt -%s %s", b ? str956 : str957, consts::OptionName(opt_num)));
  }
}

_ArgFrame::_ArgFrame(List<BigStr*>* argv) {
  this->argv = argv;
  this->num_shifted = 0;
}

Dict<BigStr*, value_asdl::value_t*>* _ArgFrame::Dump() {
  return Alloc<Dict<BigStr*, value_asdl::value_t*>>(std::initializer_list<BigStr*>{str959, str960}, std::initializer_list<value_asdl::value_t*>{Alloc<value::BashArray>(this->argv), num::ToBig(this->num_shifted)});
}

value_asdl::value_t* _ArgFrame::GetArgNum(int arg_num) {
  int index;
  index = ((this->num_shifted + arg_num) - 1);
  if (index >= len(this->argv)) {
    return value::Undef;
  }
  return Alloc<value::Str>(this->argv->at(index));
}

List<BigStr*>* _ArgFrame::GetArgv() {
  return this->argv->slice(this->num_shifted);
}

int _ArgFrame::GetNumArgs() {
  return (len(this->argv) - this->num_shifted);
}

void _ArgFrame::SetArgv(List<BigStr*>* argv) {
  StackRoot _root0(&argv);

  this->argv = argv;
  this->num_shifted = 0;
}

Dict<BigStr*, value_asdl::value_t*>* _DumpVarFrame(Dict<BigStr*, runtime_asdl::Cell*>* frame) {
  Dict<BigStr*, value_asdl::value_t*>* vars_json = nullptr;
  Dict<BigStr*, value_asdl::value_t*>* cell_json = nullptr;
  mylib::BufWriter* buf = nullptr;
  BigStr* flags = nullptr;
  StackRoot _root0(&frame);
  StackRoot _root1(&vars_json);
  StackRoot _root2(&cell_json);
  StackRoot _root3(&buf);
  StackRoot _root4(&flags);

  vars_json = Alloc<Dict<BigStr*, value_asdl::value_t*>>();
  for (DictIter<BigStr*, runtime_asdl::Cell*> it(frame); !it.Done(); it.Next()) {
    BigStr* name = it.Key();
    runtime_asdl::Cell* cell = it.Value();
    cell_json = Alloc<Dict<BigStr*, value_asdl::value_t*>>();
    buf = Alloc<mylib::BufWriter>();
    if (cell->exported) {
      buf->write(str961);
    }
    if (cell->readonly) {
      buf->write(str962);
    }
    flags = buf->getvalue();
    if (len(flags)) {
      cell_json->set(str963, Alloc<value::Str>(flags));
    }
    switch (cell->val->tag()) {
      case value_e::Undef: {
        cell_json->set(str964, Alloc<value::Str>(str965));
      }
        break;
      case value_e::Str: {
        cell_json->set(str966, Alloc<value::Str>(str967));
        cell_json->set(str968, cell->val);
      }
        break;
      case value_e::BashArray: {
        cell_json->set(str969, Alloc<value::Str>(str970));
        cell_json->set(str971, cell->val);
      }
        break;
      case value_e::BashAssoc: {
        cell_json->set(str972, Alloc<value::Str>(str973));
        cell_json->set(str974, cell->val);
      }
        break;
      default: {
        ;  // pass
      }
    }
    vars_json->set(name, Alloc<value::Dict>(cell_json));
  }
  return vars_json;
}

BigStr* _GetWorkingDir() {
  try {
    return posix::getcwd();
  }
  catch (IOError_OSError* e) {
    e_die(StrFormat("Can't determine working directory: %s", pyutil::strerror(e)));
  }
}

BigStr* _LineNumber(syntax_asdl::Token* tok) {
  StackRoot _root0(&tok);

  if (tok == nullptr) {
    return str976;
  }
  return str(tok->line->line_num);
}

void _AddCallToken(Dict<BigStr*, value_asdl::value_t*>* d, syntax_asdl::Token* token) {
  StackRoot _root0(&d);
  StackRoot _root1(&token);

  if (token == nullptr) {
    return ;
  }
  d->set(str977, Alloc<value::Str>(ui::GetLineSourceString(token->line)));
  d->set(str978, num::ToBig(token->line->line_num));
  d->set(str979, Alloc<value::Str>(token->line->content));
}

void _InitDefaults(state::Mem* mem) {
  StackRoot _root0(&mem);

  SetGlobalString(mem, str980, split::DEFAULT_IFS);
  SetGlobalString(mem, str981, str(posix::getuid()));
  SetGlobalString(mem, str982, str(posix::geteuid()));
  SetGlobalString(mem, str983, str(posix::getppid()));
  SetGlobalString(mem, str984, libc::gethostname());
  SetGlobalString(mem, str985, pyos::OsType());
  SetGlobalString(mem, str986, str987);
  SetGlobalString(mem, str988, str989);
  SetGlobalString(mem, str990, _READLINE_DELIMS);
}

void _InitVarsFromEnv(state::Mem* mem, Dict<BigStr*, BigStr*>* environ) {
  value_asdl::value_t* val = nullptr;
  StackRoot _root0(&mem);
  StackRoot _root1(&environ);
  StackRoot _root2(&val);

  for (DictIter<BigStr*, BigStr*> it(environ); !it.Done(); it.Next()) {
    BigStr* n = it.Key();
    BigStr* v = it.Value();
    mem->SetNamed(location::LName(n), Alloc<value::Str>(v), scope_e::GlobalOnly, SetExport);
  }
  val = mem->GetValue(str991);
  if (val->tag() == value_e::Undef) {
    SetGlobalString(mem, str992, str993);
  }
  mem->SetNamed(location::LName(str994), nullptr, scope_e::GlobalOnly, SetReadOnly);
  val = mem->GetValue(str995);
  if (val->tag() == value_e::Undef) {
    SetGlobalString(mem, str996, _GetWorkingDir());
  }
  mem->SetNamed(location::LName(str997), nullptr, scope_e::GlobalOnly, SetExport);
  val = mem->GetValue(str998);
  if (val->tag() == value_e::Undef) {
    SetGlobalString(mem, str999, str1000);
  }
}

void InitMem(state::Mem* mem, Dict<BigStr*, BigStr*>* environ, BigStr* version_str) {
  value_asdl::value_t* val = nullptr;
  BigStr* pwd = nullptr;
  StackRoot _root0(&mem);
  StackRoot _root1(&environ);
  StackRoot _root2(&version_str);
  StackRoot _root3(&val);
  StackRoot _root4(&pwd);

  SetGlobalString(mem, str1001, version_str);
  SetGlobalString(mem, str1002, version_str);
  SetGlobalString(mem, str1003, str1004);
  SetGlobalString(mem, str1005, str1006);
  _InitDefaults(mem);
  _InitVarsFromEnv(mem, environ);
  val = mem->GetValue(str1007);
  pwd = static_cast<value::Str*>(val)->s;
  mem->SetPwd(pwd);
}

void InitInteractive(state::Mem* mem) {
  Dict<BigStr*, runtime_asdl::Cell*>* frame = nullptr;
  StackRoot _root0(&mem);
  StackRoot _root1(&frame);

  if (mem->GetValue(str1008)->tag() == value_e::Undef) {
    SetGlobalString(mem, str1009, str1010);
  }
}

ctx_FuncCall::ctx_FuncCall(state::Mem* mem, value::Func* func) {
  gHeap.PushRoot(reinterpret_cast<RawObject**>(&(this->mem)));
  auto* frame = Alloc<Dict<BigStr*, runtime_asdl::Cell*>>();
  mem->var_stack->append(frame);
  mem->PushCall(func->name, func->parsed->name);
  this->mem = mem;
}

ctx_FuncCall::~ctx_FuncCall() {
  this->mem->PopCall();
  this->mem->var_stack->pop();
  gHeap.PopRoot();
}

ctx_ProcCall::ctx_ProcCall(state::Mem* mem, state::MutableOpts* mutable_opts, value::Proc* proc, List<BigStr*>* argv) {
  gHeap.PushRoot(reinterpret_cast<RawObject**>(&(this->mem)));
  gHeap.PushRoot(reinterpret_cast<RawObject**>(&(this->mutable_opts)));
  auto* frame = Alloc<Dict<BigStr*, runtime_asdl::Cell*>>();
  if (proc->sh_compat) {
    mem->argv_stack->append(Alloc<_ArgFrame>(argv));
  }
  else {
    frame->set(str1011, _MakeArgvCell(argv));
  }
  mem->var_stack->append(frame);
  mem->PushCall(proc->name, proc->name_tok);
  mutable_opts->PushDynamicScope(proc->sh_compat);
  this->mem = mem;
  this->mutable_opts = mutable_opts;
  this->sh_compat = proc->sh_compat;
}

ctx_ProcCall::~ctx_ProcCall() {
  this->mutable_opts->PopDynamicScope();
  this->mem->PopCall();
  this->mem->var_stack->pop();
  if (this->sh_compat) {
    this->mem->argv_stack->pop();
  }
  gHeap.PopRoot();
  gHeap.PopRoot();
}

ctx_Temp::ctx_Temp(state::Mem* mem) {
  gHeap.PushRoot(reinterpret_cast<RawObject**>(&(this->mem)));
  mem->PushTemp();
  this->mem = mem;
}

ctx_Temp::~ctx_Temp() {
  this->mem->PopTemp();
  gHeap.PopRoot();
}

ctx_Registers::ctx_Registers(state::Mem* mem) {
  gHeap.PushRoot(reinterpret_cast<RawObject**>(&(this->mem)));
  int last = mem->last_status->at(-1);
  mem->last_status->append(last);
  mem->try_status->append(0);
  mem->try_error->append(Alloc<value::Dict>(Alloc<Dict<BigStr*, value_asdl::value_t*>>()));
  mem->pipe_status->append(Alloc<List<int>>());
  mem->process_sub_status->append(Alloc<List<int>>());
  mem->regex_match->append(regex_match::No);
  this->mem = mem;
}

ctx_Registers::~ctx_Registers() {
  this->mem->regex_match->pop();
  this->mem->process_sub_status->pop();
  this->mem->pipe_status->pop();
  this->mem->try_error->pop();
  this->mem->try_status->pop();
  this->mem->last_status->pop();
  gHeap.PopRoot();
}

ctx_ThisDir::ctx_ThisDir(state::Mem* mem, BigStr* filename) {
  gHeap.PushRoot(reinterpret_cast<RawObject**>(&(this->mem)));
  this->do_pop = false;
  if (filename != nullptr) {
    BigStr* d = os_path::dirname(os_path::abspath(filename));
    mem->this_dir->append(d);
    this->do_pop = true;
  }
  this->mem = mem;
}

ctx_ThisDir::~ctx_ThisDir() {
  if (this->do_pop) {
    this->mem->this_dir->pop();
  }
  gHeap.PopRoot();
}

runtime_asdl::Cell* _MakeArgvCell(List<BigStr*>* argv) {
  List<value_asdl::value_t*>* items = nullptr;
  Dict<BigStr*, runtime_asdl::Cell*>* frame = nullptr;
  StackRoot _root0(&argv);
  StackRoot _root1(&items);
  StackRoot _root2(&frame);

  items = Alloc<List<value_asdl::value_t*>>();
  for (ListIter<BigStr*> it(argv); !it.Done(); it.Next()) {
    BigStr* a = it.Value();
    items->append(Alloc<value::Str>(a));
  }
  return Alloc<Cell>(false, false, false, Alloc<value::List>(items));
}

Mem::Mem(BigStr* dollar0, List<BigStr*>* argv, alloc::Arena* arena, List<syntax_asdl::debug_frame_t*>* debug_stack) {
  this->exec_opts = nullptr;
  this->unsafe_arith = nullptr;
  this->dollar0 = dollar0;
  this->argv_stack = NewList<state::_ArgFrame*>(std::initializer_list<state::_ArgFrame*>{Alloc<_ArgFrame>(argv)});
  auto* frame = Alloc<Dict<BigStr*, runtime_asdl::Cell*>>();
  frame->set(str1012, _MakeArgvCell(argv));
  this->var_stack = NewList<Dict<BigStr*, runtime_asdl::Cell*>*>(std::initializer_list<Dict<BigStr*, runtime_asdl::Cell*>*>{frame});
  this->debug_stack = debug_stack;
  this->pwd = nullptr;
  this->seconds_start = time_::time();
  this->token_for_line = nullptr;
  this->loc_for_expr = loc::Missing;
  this->last_arg = str1013;
  this->line_num = Alloc<value::Str>(str1014);
  this->root_pid = posix::getpid();
  this->last_status = NewList<int>(std::initializer_list<int>{0});
  this->try_status = NewList<int>(std::initializer_list<int>{0});
  this->try_error = NewList<value::Dict*>(std::initializer_list<value::Dict*>{Alloc<value::Dict>(Alloc<Dict<BigStr*, value_asdl::value_t*>>())});
  this->pipe_status = NewList<List<int>*>(std::initializer_list<List<int>*>{Alloc<List<int>>()});
  this->process_sub_status = NewList<List<int>*>(std::initializer_list<List<int>*>{Alloc<List<int>>()});
  this->this_dir = Alloc<List<BigStr*>>();
  this->regex_match = NewList<value_asdl::regex_match_t*>(std::initializer_list<value_asdl::regex_match_t*>{regex_match::No});
  this->last_bg_pid = -1;
  this->running_debug_trap = false;
  this->running_err_trap = false;
  this->is_main = true;
  this->ctx_stack = Alloc<List<Dict<BigStr*, value_asdl::value_t*>*>>();
}

void Mem::SetPwd(BigStr* pwd) {
  StackRoot _root0(&pwd);

  this->pwd = pwd;
}

bool Mem::ParsingChangesAllowed() {
  return (len(this->var_stack) == 1 or len(this->argv_stack) == 1);
}

Tuple3<List<value_asdl::value_t*>*, List<value_asdl::value_t*>*, List<value_asdl::value_t*>*> Mem::Dump() {
  List<value_asdl::value_t*>* var_stack = nullptr;
  List<value_asdl::value_t*>* argv_stack = nullptr;
  List<value_asdl::value_t*>* debug_stack = nullptr;
  value::Str* t_call = nullptr;
  value::Str* t_source = nullptr;
  value::Str* t_main = nullptr;
  syntax_asdl::debug_frame_t* UP_frame = nullptr;
  Dict<BigStr*, value_asdl::value_t*>* d = nullptr;
  StackRoot _root0(&var_stack);
  StackRoot _root1(&argv_stack);
  StackRoot _root2(&debug_stack);
  StackRoot _root3(&t_call);
  StackRoot _root4(&t_source);
  StackRoot _root5(&t_main);
  StackRoot _root6(&UP_frame);
  StackRoot _root7(&d);

  var_stack = Alloc<List<value_asdl::value_t*>>();
  for (ListIter<Dict<BigStr*, runtime_asdl::Cell*>*> it(this->var_stack); !it.Done(); it.Next()) {
    Dict<BigStr*, runtime_asdl::Cell*>* frame = it.Value();
    var_stack->append(Alloc<value::Dict>(_DumpVarFrame(frame)));
  }
  argv_stack = Alloc<List<value_asdl::value_t*>>();
  for (ListIter<state::_ArgFrame*> it(this->argv_stack); !it.Done(); it.Next()) {
    state::_ArgFrame* frame = it.Value();
    argv_stack->append(Alloc<value::Dict>(frame->Dump()));
  }
  debug_stack = Alloc<List<value_asdl::value_t*>>();
  t_call = Alloc<value::Str>(str1021);
  t_source = Alloc<value::Str>(str1022);
  t_main = Alloc<value::Str>(str1023);
  for (ReverseListIter<syntax_asdl::debug_frame_t*> it(this->debug_stack); !it.Done(); it.Next()) {
    syntax_asdl::debug_frame_t* frame = it.Value();
    StackRoot _for(&frame  );
    UP_frame = frame;
    switch (frame->tag()) {
      case debug_frame_e::Call: {
        debug_frame::Call* frame = static_cast<debug_frame::Call*>(UP_frame);
        d = Alloc<Dict<BigStr*, value_asdl::value_t*>>(std::initializer_list<BigStr*>{str1024, str1025}, std::initializer_list<value_asdl::value_t*>{t_call, Alloc<value::Str>(frame->func_name)});
        _AddCallToken(d, frame->call_tok);
      }
        break;
      case debug_frame_e::Source: {
        debug_frame::Source* frame = static_cast<debug_frame::Source*>(UP_frame);
        d = Alloc<Dict<BigStr*, value_asdl::value_t*>>(std::initializer_list<BigStr*>{str1026, str1027}, std::initializer_list<value_asdl::value_t*>{t_source, Alloc<value::Str>(frame->source_name)});
        _AddCallToken(d, frame->call_tok);
      }
        break;
      case debug_frame_e::Main: {
        debug_frame::Main* frame = static_cast<debug_frame::Main*>(UP_frame);
        d = Alloc<Dict<BigStr*, value_asdl::value_t*>>(std::initializer_list<BigStr*>{str1028, str1029}, std::initializer_list<value_asdl::value_t*>{t_main, Alloc<value::Str>(frame->dollar0)});
      }
        break;
    }
    debug_stack->append(Alloc<value::Dict>(d));
  }
  return Tuple3<List<value_asdl::value_t*>*, List<value_asdl::value_t*>*, List<value_asdl::value_t*>*>(var_stack, argv_stack, debug_stack);
}

void Mem::SetLastArgument(BigStr* s) {
  StackRoot _root0(&s);

  this->last_arg = s;
}

void Mem::SetTokenForLine(syntax_asdl::Token* tok) {
  StackRoot _root0(&tok);

  if ((this->running_debug_trap or this->running_err_trap)) {
    return ;
  }
  this->token_for_line = tok;
}

void Mem::SetLocationForExpr(syntax_asdl::loc_t* blame_loc) {
  StackRoot _root0(&blame_loc);

  this->loc_for_expr = blame_loc;
}

syntax_asdl::loc_t* Mem::GetFallbackLocation() {
  if (this->loc_for_expr != loc::Missing) {
    return this->loc_for_expr;
  }
  if (this->token_for_line) {
    return this->token_for_line;
  }
  return loc::Missing;
}

int Mem::LastStatus() {
  return this->last_status->at(-1);
}

int Mem::TryStatus() {
  return this->try_status->at(-1);
}

value::Dict* Mem::TryError() {
  return this->try_error->at(-1);
}

List<int>* Mem::PipeStatus() {
  return this->pipe_status->at(-1);
}

void Mem::SetLastStatus(int x) {
  this->last_status->set(-1, x);
}

void Mem::SetTryStatus(int x) {
  this->try_status->set(-1, x);
}

void Mem::SetTryError(value::Dict* x) {
  StackRoot _root0(&x);

  this->try_error->set(-1, x);
}

void Mem::SetPipeStatus(List<int>* x) {
  StackRoot _root0(&x);

  this->pipe_status->set(-1, x);
}

void Mem::SetSimplePipeStatus(int status) {
  List<int>* top = nullptr;
  StackRoot _root0(&top);

  top = this->pipe_status->at(-1);
  if (len(top) == 1) {
    top->set(0, status);
  }
  else {
    this->pipe_status->set(-1, NewList<int>(std::initializer_list<int>{status}));
  }
}

void Mem::SetProcessSubStatus(List<int>* x) {
  StackRoot _root0(&x);

  this->process_sub_status->set(-1, x);
}

void Mem::PushCall(BigStr* func_name, syntax_asdl::Token* def_tok) {
  StackRoot _root0(&func_name);
  StackRoot _root1(&def_tok);

  this->debug_stack->append(Alloc<debug_frame::Call>(this->token_for_line, def_tok, func_name));
}

void Mem::PopCall() {
  this->debug_stack->pop();
}

bool Mem::ShouldRunDebugTrap() {
  if (this->running_debug_trap) {
    return false;
  }
  if (len(this->var_stack) > 1) {
    return false;
  }
  return true;
}

bool Mem::InsideFunction() {
  return len(this->var_stack) > 1;
}

void Mem::PushSource(BigStr* source_name, List<BigStr*>* argv) {
  StackRoot _root0(&source_name);
  StackRoot _root1(&argv);

  if (len(argv)) {
    this->argv_stack->append(Alloc<_ArgFrame>(argv));
  }
  this->debug_stack->append(Alloc<debug_frame::Source>(this->token_for_line, source_name));
}

void Mem::PopSource(List<BigStr*>* argv) {
  StackRoot _root0(&argv);

  this->debug_stack->pop();
  if (len(argv)) {
    this->argv_stack->pop();
  }
}

void Mem::PushTemp() {
  Dict<BigStr*, runtime_asdl::Cell*>* frame = nullptr;
  StackRoot _root0(&frame);

  frame = Alloc<Dict<BigStr*, runtime_asdl::Cell*>>();
  this->var_stack->append(frame);
}

void Mem::PopTemp() {
  this->var_stack->pop();
}

Dict<BigStr*, runtime_asdl::Cell*>* Mem::TopNamespace() {
  return this->var_stack->at(-1);
}

int Mem::Shift(int n) {
  state::_ArgFrame* frame = nullptr;
  int num_args;
  StackRoot _root0(&frame);

  frame = this->argv_stack->at(-1);
  num_args = len(frame->argv);
  if ((frame->num_shifted + n) <= num_args) {
    frame->num_shifted += n;
    return 0;
  }
  else {
    return 1;
  }
}

value::Str* Mem::GetArg0() {
  return Alloc<value::Str>(this->dollar0);
}

value_asdl::value_t* Mem::GetArgNum(int arg_num) {
  Dict<BigStr*, runtime_asdl::Cell*>* vars = nullptr;
  StackRoot _root0(&vars);

  if (arg_num == 0) {
    vars = this->var_stack->at(-1);
    if ((dict_contains(vars, str1030) and vars->at(str1031)->val->tag() != value_e::Undef)) {
      return vars->at(str1032)->val;
    }
    return Alloc<value::Str>(this->dollar0);
  }
  return this->argv_stack->at(-1)->GetArgNum(arg_num);
}

List<BigStr*>* Mem::GetArgv() {
  return this->argv_stack->at(-1)->GetArgv();
}

void Mem::SetArgv(List<BigStr*>* argv) {
  StackRoot _root0(&argv);

  this->argv_stack->at(-1)->SetArgv(argv);
}

value_asdl::value_t* Mem::GetSpecialVar(int op_id) {
  int n;
  if (op_id == Id::VSub_Bang) {
    n = this->last_bg_pid;
    if (n == -1) {
      return value::Undef;
    }
  }
  else {
    if (op_id == Id::VSub_QMark) {
      n = this->last_status->at(-1);
    }
    else {
      if (op_id == Id::VSub_Pound) {
        n = this->argv_stack->at(-1)->GetNumArgs();
      }
      else {
        if (op_id == Id::VSub_Dollar) {
          n = this->root_pid;
        }
        else {
          FAIL(kNotImplemented);  // Python NotImplementedError
        }
      }
    }
  }
  return Alloc<value::Str>(str(n));
}

Tuple2<runtime_asdl::Cell*, Dict<BigStr*, runtime_asdl::Cell*>*> Mem::_ResolveNameOnly(BigStr* name, runtime_asdl::scope_t which_scopes) {
  Dict<BigStr*, runtime_asdl::Cell*>* name_map = nullptr;
  runtime_asdl::Cell* cell = nullptr;
  runtime_asdl::Cell* no_cell = nullptr;
  StackRoot _root0(&name);
  StackRoot _root1(&name_map);
  StackRoot _root2(&cell);
  StackRoot _root3(&no_cell);

  if (which_scopes == scope_e::Dynamic) {
    for (int i = (len(this->var_stack) - 1); i > -1; i += -1) {
      name_map = this->var_stack->at(i);
      if (dict_contains(name_map, name)) {
        cell = name_map->at(name);
        return Tuple2<runtime_asdl::Cell*, Dict<BigStr*, runtime_asdl::Cell*>*>(cell, name_map);
      }
    }
    no_cell = nullptr;
    return Tuple2<runtime_asdl::Cell*, Dict<BigStr*, runtime_asdl::Cell*>*>(no_cell, this->var_stack->at(0));
  }
  if (which_scopes == scope_e::LocalOnly) {
    name_map = this->var_stack->at(-1);
    return Tuple2<runtime_asdl::Cell*, Dict<BigStr*, runtime_asdl::Cell*>*>(name_map->get(name), name_map);
  }
  if (which_scopes == scope_e::GlobalOnly) {
    name_map = this->var_stack->at(0);
    return Tuple2<runtime_asdl::Cell*, Dict<BigStr*, runtime_asdl::Cell*>*>(name_map->get(name), name_map);
  }
  if (which_scopes == scope_e::LocalOrGlobal) {
    name_map = this->var_stack->at(-1);
    cell = name_map->get(name);
    if (cell) {
      return Tuple2<runtime_asdl::Cell*, Dict<BigStr*, runtime_asdl::Cell*>*>(cell, name_map);
    }
    name_map = this->var_stack->at(0);
    return Tuple2<runtime_asdl::Cell*, Dict<BigStr*, runtime_asdl::Cell*>*>(name_map->get(name), name_map);
  }
  assert(0);  // AssertionError
}

Tuple3<runtime_asdl::Cell*, Dict<BigStr*, runtime_asdl::Cell*>*, BigStr*> Mem::_ResolveNameOrRef(BigStr* name, runtime_asdl::scope_t which_scopes, List<BigStr*>* ref_trail) {
  runtime_asdl::Cell* cell = nullptr;
  Dict<BigStr*, runtime_asdl::Cell*>* name_map = nullptr;
  value_asdl::value_t* val = nullptr;
  value_asdl::value_t* UP_val = nullptr;
  BigStr* new_name = nullptr;
  BigStr* cell_name = nullptr;
  StackRoot _root0(&name);
  StackRoot _root1(&ref_trail);
  StackRoot _root2(&cell);
  StackRoot _root3(&name_map);
  StackRoot _root4(&val);
  StackRoot _root5(&UP_val);
  StackRoot _root6(&new_name);
  StackRoot _root7(&cell_name);

  Tuple2<runtime_asdl::Cell*, Dict<BigStr*, runtime_asdl::Cell*>*> tup0 = this->_ResolveNameOnly(name, which_scopes);
  cell = tup0.at0();
  name_map = tup0.at1();
  if ((cell == nullptr or !cell->nameref)) {
    return Tuple3<runtime_asdl::Cell*, Dict<BigStr*, runtime_asdl::Cell*>*, BigStr*>(cell, name_map, name);
  }
  val = cell->val;
  UP_val = val;
  switch (val->tag()) {
    case value_e::Undef: {
      if (this->exec_opts->strict_nameref()) {
        e_die(StrFormat("nameref %r is undefined", name));
      }
      else {
        return Tuple3<runtime_asdl::Cell*, Dict<BigStr*, runtime_asdl::Cell*>*, BigStr*>(cell, name_map, name);
      }
    }
      break;
    case value_e::Str: {
      value::Str* val = static_cast<value::Str*>(UP_val);
      new_name = val->s;
    }
      break;
    default: {
      assert(0);  // AssertionError
    }
  }
  if (!match::IsValidVarName(new_name)) {
    if (this->exec_opts->strict_nameref()) {
      e_die(StrFormat("nameref %r contains invalid variable name %r", name, new_name));
    }
    else {
      cell->nameref = false;
      return Tuple3<runtime_asdl::Cell*, Dict<BigStr*, runtime_asdl::Cell*>*, BigStr*>(cell, name_map, name);
    }
  }
  if (ref_trail == nullptr) {
    ref_trail = NewList<BigStr*>(std::initializer_list<BigStr*>{name});
  }
  else {
    if (list_contains(ref_trail, new_name)) {
      e_die(StrFormat("Circular nameref %s", str1036->join(ref_trail)));
    }
  }
  ref_trail->append(new_name);
  Tuple3<runtime_asdl::Cell*, Dict<BigStr*, runtime_asdl::Cell*>*, BigStr*> tup1 = this->_ResolveNameOrRef(new_name, scope_e::Dynamic, ref_trail);
  cell = tup1.at0();
  name_map = tup1.at1();
  cell_name = tup1.at2();
  return Tuple3<runtime_asdl::Cell*, Dict<BigStr*, runtime_asdl::Cell*>*, BigStr*>(cell, name_map, cell_name);
}

bool Mem::IsBashAssoc(BigStr* name) {
  runtime_asdl::Cell* cell = nullptr;
  StackRoot _root0(&name);
  StackRoot _root1(&cell);

  Tuple3<runtime_asdl::Cell*, Dict<BigStr*, runtime_asdl::Cell*>*, BigStr*> tup2 = this->_ResolveNameOrRef(name, this->ScopesForReading());
  cell = tup2.at0();
  return (cell != nullptr and cell->val->tag() == value_e::BashAssoc);
}

void Mem::SetPlace(value::Place* place, value_asdl::value_t* val, syntax_asdl::loc_t* blame_loc) {
  value_asdl::y_lvalue_t* yval = nullptr;
  value_asdl::y_lvalue_t* UP_yval = nullptr;
  bool found;
  Dict<BigStr*, runtime_asdl::Cell*>* frame = nullptr;
  runtime_asdl::Cell* cell = nullptr;
  StackRoot _root0(&place);
  StackRoot _root1(&val);
  StackRoot _root2(&blame_loc);
  StackRoot _root3(&yval);
  StackRoot _root4(&UP_yval);
  StackRoot _root5(&frame);
  StackRoot _root6(&cell);

  yval = place->lval;
  UP_yval = yval;
  switch (yval->tag()) {
    case y_lvalue_e::Local: {
      LeftName* yval = static_cast<LeftName*>(UP_yval);
      found = false;
      for (int i = (len(this->var_stack) - 1); i > -1; i += -1) {
        frame = this->var_stack->at(i);
        if (frame == place->frame) {
          found = true;
          break;
        }
      }
      if (!found) {
        e_die(str1037, blame_loc);
      }
      cell = frame->get(yval->name);
      if (cell == nullptr) {
        cell = Alloc<Cell>(false, false, false, val);
        frame->set(yval->name, cell);
      }
      else {
        cell->val = val;
      }
    }
      break;
    case y_lvalue_e::Container: {
      e_die(str1038, blame_loc);
    }
      break;
    default: {
      assert(0);  // AssertionError
    }
  }
}

void Mem::SetLocalName(value_asdl::LeftName* lval, value_asdl::value_t* val) {
  Dict<BigStr*, runtime_asdl::Cell*>* name_map = nullptr;
  runtime_asdl::Cell* cell = nullptr;
  StackRoot _root0(&lval);
  StackRoot _root1(&val);
  StackRoot _root2(&name_map);
  StackRoot _root3(&cell);

  name_map = this->var_stack->at(-1);
  cell = name_map->get(lval->name);
  if (cell) {
    if (cell->readonly) {
      e_die(StrFormat("Can't assign to readonly value %r", lval->name), lval->blame_loc);
    }
    cell->val = val;
  }
  else {
    cell = Alloc<Cell>(false, false, false, val);
    name_map->set(lval->name, cell);
  }
}

void Mem::SetNamed(value_asdl::LeftName* lval, value_asdl::value_t* val, runtime_asdl::scope_t which_scopes, int flags) {
  runtime_asdl::Cell* cell = nullptr;
  Dict<BigStr*, runtime_asdl::Cell*>* name_map = nullptr;
  BigStr* cell_name = nullptr;
  StackRoot _root0(&lval);
  StackRoot _root1(&val);
  StackRoot _root2(&cell);
  StackRoot _root3(&name_map);
  StackRoot _root4(&cell_name);

  if (((flags & SetNameref) or (flags & ClearNameref))) {
    Tuple2<runtime_asdl::Cell*, Dict<BigStr*, runtime_asdl::Cell*>*> tup3 = this->_ResolveNameOnly(lval->name, which_scopes);
    cell = tup3.at0();
    name_map = tup3.at1();
    cell_name = lval->name;
  }
  else {
    Tuple3<runtime_asdl::Cell*, Dict<BigStr*, runtime_asdl::Cell*>*, BigStr*> tup4 = this->_ResolveNameOrRef(lval->name, which_scopes);
    cell = tup4.at0();
    name_map = tup4.at1();
    cell_name = tup4.at2();
  }
  if (cell) {
    if ((flags & ClearExport)) {
      cell->exported = false;
    }
    if ((flags & ClearReadOnly)) {
      cell->readonly = false;
    }
    if ((flags & ClearNameref)) {
      cell->nameref = false;
    }
    if (val != nullptr) {
      if (cell->readonly) {
        e_die(StrFormat("Can't assign to readonly value %r", lval->name), lval->blame_loc);
      }
      cell->val = val;
    }
    if ((flags & SetExport)) {
      cell->exported = true;
    }
    if ((flags & SetReadOnly)) {
      cell->readonly = true;
    }
    if ((flags & SetNameref)) {
      cell->nameref = true;
    }
  }
  else {
    if (val == nullptr) {
      val = value::Undef;
    }
    cell = Alloc<Cell>(to_bool((flags & SetExport)), to_bool((flags & SetReadOnly)), to_bool((flags & SetNameref)), val);
    name_map->set(cell_name, cell);
  }
  if ((cell->val->tag() != value_e::Undef && cell->val->tag() != value_e::Str)) {
    if (cell->exported) {
      if (this->exec_opts->strict_array()) {
        e_die(str1041, lval->blame_loc);
      }
    }
    if (cell->nameref) {
      e_die(str1042, lval->blame_loc);
    }
  }
}

void Mem::SetValue(value_asdl::sh_lvalue_t* lval, value_asdl::value_t* val, runtime_asdl::scope_t which_scopes, int flags) {
  value_asdl::sh_lvalue_t* UP_lval = nullptr;
  value::Str* rval = nullptr;
  syntax_asdl::loc_t* left_loc = nullptr;
  runtime_asdl::Cell* cell = nullptr;
  Dict<BigStr*, runtime_asdl::Cell*>* name_map = nullptr;
  value_asdl::value_t* UP_cell_val = nullptr;
  List<BigStr*>* strs = nullptr;
  int n;
  int index;
  value::BashAssoc* cell_val2 = nullptr;
  StackRoot _root0(&lval);
  StackRoot _root1(&val);
  StackRoot _root2(&UP_lval);
  StackRoot _root3(&rval);
  StackRoot _root4(&left_loc);
  StackRoot _root5(&cell);
  StackRoot _root6(&name_map);
  StackRoot _root7(&UP_cell_val);
  StackRoot _root8(&strs);
  StackRoot _root9(&cell_val2);

  UP_lval = lval;
  switch (lval->tag()) {
    case sh_lvalue_e::Var: {
      LeftName* lval = static_cast<LeftName*>(UP_lval);
      this->SetNamed(lval, val, which_scopes, flags);
    }
      break;
    case sh_lvalue_e::Indexed: {
      sh_lvalue::Indexed* lval = static_cast<sh_lvalue::Indexed*>(UP_lval);
      rval = static_cast<value::Str*>(val);
      left_loc = lval->blame_loc;
      Tuple3<runtime_asdl::Cell*, Dict<BigStr*, runtime_asdl::Cell*>*, BigStr*> tup5 = this->_ResolveNameOrRef(lval->name, which_scopes);
      cell = tup5.at0();
      name_map = tup5.at1();
      if (!cell) {
        this->_BindNewArrayWithEntry(name_map, lval, rval, flags);
        return ;
      }
      if (cell->readonly) {
        e_die(str1043, left_loc);
      }
      UP_cell_val = cell->val;
      switch (UP_cell_val->tag()) {
        case value_e::Undef: {
          this->_BindNewArrayWithEntry(name_map, lval, rval, flags);
          return ;
        }
          break;
        case value_e::Str: {
          e_die(str1044, left_loc);
        }
          break;
        case value_e::BashArray: {
          value::BashArray* cell_val = static_cast<value::BashArray*>(UP_cell_val);
          strs = cell_val->strs;
          n = len(strs);
          index = lval->index;
          if (index < 0) {
            index += n;
          }
          if ((0 <= index and index < n)) {
            strs->set(index, rval->s);
          }
          else {
            n = ((index - len(strs)) + 1);
            for (int i = 0; i < n; ++i) {
              strs->append(nullptr);
            }
            strs->set(lval->index, rval->s);
          }
          return ;
        }
          break;
      }
      e_die(StrFormat("Value of type %s can't be indexed", ui::ValType(cell->val)), left_loc);
    }
      break;
    case sh_lvalue_e::Keyed: {
      sh_lvalue::Keyed* lval = static_cast<sh_lvalue::Keyed*>(UP_lval);
      rval = static_cast<value::Str*>(val);
      left_loc = lval->blame_loc;
      Tuple3<runtime_asdl::Cell*, Dict<BigStr*, runtime_asdl::Cell*>*, BigStr*> tup6 = this->_ResolveNameOrRef(lval->name, which_scopes);
      cell = tup6.at0();
      name_map = tup6.at1();
      if (cell->readonly) {
        e_die(str1046, left_loc);
      }
      cell_val2 = static_cast<value::BashAssoc*>(cell->val);
      cell_val2->d->set(lval->key, rval->s);
    }
      break;
    default: {
      assert(0);  // AssertionError
    }
  }
}

void Mem::_BindNewArrayWithEntry(Dict<BigStr*, runtime_asdl::Cell*>* name_map, sh_lvalue::Indexed* lval, value::Str* val, int flags) {
  BigStr* no_str = nullptr;
  List<BigStr*>* items = nullptr;
  value::BashArray* new_value = nullptr;
  bool readonly;
  StackRoot _root0(&name_map);
  StackRoot _root1(&lval);
  StackRoot _root2(&val);
  StackRoot _root3(&no_str);
  StackRoot _root4(&items);
  StackRoot _root5(&new_value);

  no_str = nullptr;
  items = list_repeat(no_str, lval->index);
  items->append(val->s);
  new_value = Alloc<value::BashArray>(items);
  readonly = to_bool((flags & SetReadOnly));
  name_map->set(lval->name, Alloc<Cell>(false, readonly, false, new_value));
}

void Mem::InternalSetGlobal(BigStr* name, value_asdl::value_t* new_val) {
  runtime_asdl::Cell* cell = nullptr;
  StackRoot _root0(&name);
  StackRoot _root1(&new_val);
  StackRoot _root2(&cell);

  cell = this->var_stack->at(0)->at(name);
  cell->val = new_val;
}

value_asdl::value_t* Mem::GetValue(BigStr* name, runtime_asdl::scope_t which_scopes) {
  List<BigStr*>* strs = nullptr;
  syntax_asdl::debug_frame_t* UP_frame = nullptr;
  List<BigStr*>* strs2 = nullptr;
  BigStr* source_str = nullptr;
  value_asdl::regex_match_t* top_match = nullptr;
  List<BigStr*>* groups = nullptr;
  RegexMatch* m = nullptr;
  List<value_asdl::value_t*>* items = nullptr;
  runtime_asdl::Cell* cell = nullptr;
  StackRoot _root0(&name);
  StackRoot _root1(&strs);
  StackRoot _root2(&UP_frame);
  StackRoot _root3(&strs2);
  StackRoot _root4(&source_str);
  StackRoot _root5(&top_match);
  StackRoot _root6(&groups);
  StackRoot _root7(&m);
  StackRoot _root8(&items);
  StackRoot _root9(&cell);

  if (which_scopes == scope_e::Shopt) {
    which_scopes = this->ScopesForReading();
  }
  switch (len(name)) {
    case 1: {
      if (str_equals_c(name, "_", 1)) {
        return Alloc<value::Str>(this->last_arg);
      }
      else {
        goto str_switch_default;
      }
    }
      break;
    case 6: {
      if (str_equals_c(name, "_error", 6)) {
        return this->TryError();
      }
      else if (str_equals_c(name, "LINENO", 6)) {
        this->line_num->s = str(this->token_for_line->line->line_num);
        return this->line_num;
      }
      else {
        goto str_switch_default;
      }
    }
      break;
    case 7: {
      if (str_equals_c(name, "_status", 7)) {
        return num::ToBig(this->TryStatus());
      }
      else if (str_equals_c(name, "BASHPID", 7)) {
        return Alloc<value::Str>(str(posix::getpid()));
      }
      else if (str_equals_c(name, "SECONDS", 7)) {
        return Alloc<value::Int>(mops::FromFloat((time_::time() - this->seconds_start)));
      }
      else {
        goto str_switch_default;
      }
    }
      break;
    case 8: {
      if (str_equals_c(name, "FUNCNAME", 8)) {
        strs = Alloc<List<BigStr*>>();
        for (ReverseListIter<syntax_asdl::debug_frame_t*> it(this->debug_stack); !it.Done(); it.Next()) {
          syntax_asdl::debug_frame_t* frame = it.Value();
          StackRoot _for(&frame        );
          UP_frame = frame;
          switch (frame->tag()) {
            case debug_frame_e::Call: {
              debug_frame::Call* frame = static_cast<debug_frame::Call*>(UP_frame);
              strs->append(frame->func_name);
            }
              break;
            case debug_frame_e::Source: {
              strs->append(str1055);
            }
              break;
            case debug_frame_e::Main: {
              strs->append(str1056);
            }
              break;
          }
        }
        return Alloc<value::BashArray>(strs);
      }
      else {
        goto str_switch_default;
      }
    }
      break;
    case 9: {
      if (str_equals_c(name, "_this_dir", 9)) {
        if (len(this->this_dir) == 0) {
          return value::Undef;
        }
        else {
          return Alloc<value::Str>(this->this_dir->at(-1));
        }
      }
      else {
        goto str_switch_default;
      }
    }
      break;
    case 10: {
      if (str_equals_c(name, "PIPESTATUS", 10)) {
        strs2 = Alloc<List<BigStr*>>();
        for (ListIter<int> it(this->pipe_status->at(-1)); !it.Done(); it.Next()) {
          int i = it.Value();
          strs2->append(str(i));
        }
        return Alloc<value::BashArray>(strs2);
      }
      else {
        goto str_switch_default;
      }
    }
      break;
    case 11: {
      if (str_equals_c(name, "BASH_SOURCE", 11)) {
        strs = Alloc<List<BigStr*>>();
        for (ReverseListIter<syntax_asdl::debug_frame_t*> it(this->debug_stack); !it.Done(); it.Next()) {
          syntax_asdl::debug_frame_t* frame = it.Value();
          StackRoot _for(&frame        );
          UP_frame = frame;
          switch (frame->tag()) {
            case debug_frame_e::Call: {
              debug_frame::Call* frame = static_cast<debug_frame::Call*>(UP_frame);
              source_str = ui::GetLineSourceString(frame->def_tok->line);
              strs->append(source_str);
            }
              break;
            case debug_frame_e::Source: {
              debug_frame::Source* frame = static_cast<debug_frame::Source*>(UP_frame);
              strs->append(frame->source_name);
            }
              break;
            case debug_frame_e::Main: {
              debug_frame::Main* frame = static_cast<debug_frame::Main*>(UP_frame);
              strs->append(frame->dollar0);
            }
              break;
          }
        }
        return Alloc<value::BashArray>(strs);
      }
      else if (str_equals_c(name, "BASH_LINENO", 11)) {
        strs = Alloc<List<BigStr*>>();
        for (ReverseListIter<syntax_asdl::debug_frame_t*> it(this->debug_stack); !it.Done(); it.Next()) {
          syntax_asdl::debug_frame_t* frame = it.Value();
          StackRoot _for(&frame        );
          UP_frame = frame;
          switch (frame->tag()) {
            case debug_frame_e::Call: {
              debug_frame::Call* frame = static_cast<debug_frame::Call*>(UP_frame);
              strs->append(_LineNumber(frame->call_tok));
            }
              break;
            case debug_frame_e::Source: {
              debug_frame::Source* frame = static_cast<debug_frame::Source*>(UP_frame);
              strs->append(_LineNumber(frame->call_tok));
            }
              break;
            case debug_frame_e::Main: {
              strs->append(str1059);
            }
              break;
          }
        }
        return Alloc<value::BashArray>(strs);
      }
      else {
        goto str_switch_default;
      }
    }
      break;
    case 12: {
      if (str_equals_c(name, "BASH_REMATCH", 12)) {
        top_match = this->regex_match->at(-1);
        switch (top_match->tag()) {
          case regex_match_e::No: {
            groups = Alloc<List<BigStr*>>();
          }
            break;
          case regex_match_e::Yes: {
            m = static_cast<RegexMatch*>(top_match);
            groups = util::RegexGroupStrings(m->s, m->indices);
          }
            break;
        }
        return Alloc<value::BashArray>(groups);
      }
      else {
        goto str_switch_default;
      }
    }
      break;
    case 16: {
      if (str_equals_c(name, "_pipeline_status", 16)) {
        items = Alloc<List<value_asdl::value_t*>>();
        for (ListIter<int> it(this->pipe_status->at(-1)); !it.Done(); it.Next()) {
          int i = it.Value();
          items->append(num::ToBig(i));
        }
        return Alloc<value::List>(items);
      }
      else {
        goto str_switch_default;
      }
    }
      break;
    case 19: {
      if (str_equals_c(name, "_process_sub_status", 19)) {
        items = Alloc<List<value_asdl::value_t*>>();
        for (ListIter<int> it(this->process_sub_status->at(-1)); !it.Done(); it.Next()) {
          int i = it.Value();
          items->append(num::ToBig(i));
        }
        return Alloc<value::List>(items);
      }
      else {
        goto str_switch_default;
      }
    }
      break;

    str_switch_default:
    default: {
      Tuple3<runtime_asdl::Cell*, Dict<BigStr*, runtime_asdl::Cell*>*, BigStr*> tup7 = this->_ResolveNameOrRef(name, which_scopes);
      cell = tup7.at0();
      if (cell) {
        return cell->val;
      }
      return value::Undef;
    }
  }
}

runtime_asdl::Cell* Mem::GetCell(BigStr* name, runtime_asdl::scope_t which_scopes) {
  runtime_asdl::Cell* cell = nullptr;
  StackRoot _root0(&name);
  StackRoot _root1(&cell);

  if (which_scopes == scope_e::Shopt) {
    which_scopes = this->ScopesForReading();
  }
  Tuple2<runtime_asdl::Cell*, Dict<BigStr*, runtime_asdl::Cell*>*> tup8 = this->_ResolveNameOnly(name, which_scopes);
  cell = tup8.at0();
  return cell;
}

bool Mem::Unset(value_asdl::sh_lvalue_t* lval, runtime_asdl::scope_t which_scopes) {
  value_asdl::sh_lvalue_t* UP_lval = nullptr;
  BigStr* var_name = nullptr;
  runtime_asdl::Cell* cell = nullptr;
  Dict<BigStr*, runtime_asdl::Cell*>* name_map = nullptr;
  BigStr* cell_name = nullptr;
  value_asdl::value_t* val = nullptr;
  value_asdl::value_t* UP_val = nullptr;
  List<BigStr*>* strs = nullptr;
  int n;
  int last_index;
  int index;
  StackRoot _root0(&lval);
  StackRoot _root1(&UP_lval);
  StackRoot _root2(&var_name);
  StackRoot _root3(&cell);
  StackRoot _root4(&name_map);
  StackRoot _root5(&cell_name);
  StackRoot _root6(&val);
  StackRoot _root7(&UP_val);
  StackRoot _root8(&strs);

  UP_lval = lval;
  switch (lval->tag()) {
    case sh_lvalue_e::Var: {
      LeftName* lval = static_cast<LeftName*>(UP_lval);
      var_name = lval->name;
    }
      break;
    case sh_lvalue_e::Indexed: {
      sh_lvalue::Indexed* lval = static_cast<sh_lvalue::Indexed*>(UP_lval);
      var_name = lval->name;
    }
      break;
    case sh_lvalue_e::Keyed: {
      sh_lvalue::Keyed* lval = static_cast<sh_lvalue::Keyed*>(UP_lval);
      var_name = lval->name;
    }
      break;
    default: {
      assert(0);  // AssertionError
    }
  }
  if (which_scopes == scope_e::Shopt) {
    which_scopes = this->ScopesForWriting();
  }
  Tuple3<runtime_asdl::Cell*, Dict<BigStr*, runtime_asdl::Cell*>*, BigStr*> tup9 = this->_ResolveNameOrRef(var_name, which_scopes);
  cell = tup9.at0();
  name_map = tup9.at1();
  cell_name = tup9.at2();
  if (!cell) {
    return false;
  }
  if (cell->readonly) {
    throw Alloc<error::Runtime>(StrFormat("Can't unset readonly variable %r", var_name));
  }
  switch (lval->tag()) {
    case sh_lvalue_e::Var: {
      mylib::dict_erase(name_map, cell_name);
    }
      break;
    case sh_lvalue_e::Indexed: {
      sh_lvalue::Indexed* lval = static_cast<sh_lvalue::Indexed*>(UP_lval);
      val = cell->val;
      UP_val = val;
      if (val->tag() != value_e::BashArray) {
        throw Alloc<error::Runtime>(StrFormat("%r isn't an array", var_name));
      }
      value::BashArray* val = static_cast<value::BashArray*>(UP_val);
      strs = val->strs;
      n = len(strs);
      last_index = (n - 1);
      index = lval->index;
      if (index < 0) {
        index += n;
      }
      if (index == last_index) {
        strs->pop();
      }
      else {
        if ((0 <= index and index < last_index)) {
          strs->set(index, nullptr);
        }
        else {
          ;  // pass
        }
      }
    }
      break;
    case sh_lvalue_e::Keyed: {
      sh_lvalue::Keyed* lval = static_cast<sh_lvalue::Keyed*>(UP_lval);
      val = cell->val;
      UP_val = val;
      value::BashAssoc* val = static_cast<value::BashAssoc*>(UP_val);
      mylib::dict_erase(val->d, lval->key);
    }
      break;
    default: {
      assert(0);  // AssertionError
    }
  }
  return true;
}

runtime_asdl::scope_t Mem::ScopesForReading() {
  return this->exec_opts->dynamic_scope() ? scope_e::Dynamic : scope_e::LocalOrGlobal;
}

runtime_asdl::scope_t Mem::ScopesForWriting() {
  return this->exec_opts->dynamic_scope() ? scope_e::Dynamic : scope_e::LocalOnly;
}

bool Mem::ClearFlag(BigStr* name, int flag) {
  runtime_asdl::Cell* cell = nullptr;
  Dict<BigStr*, runtime_asdl::Cell*>* name_map = nullptr;
  StackRoot _root0(&name);
  StackRoot _root1(&cell);
  StackRoot _root2(&name_map);

  Tuple2<runtime_asdl::Cell*, Dict<BigStr*, runtime_asdl::Cell*>*> tup10 = this->_ResolveNameOnly(name, this->ScopesForReading());
  cell = tup10.at0();
  name_map = tup10.at1();
  if (cell) {
    if ((flag & ClearExport)) {
      cell->exported = false;
    }
    if ((flag & ClearNameref)) {
      cell->nameref = false;
    }
    return true;
  }
  else {
    return false;
  }
}

Dict<BigStr*, BigStr*>* Mem::GetExported() {
  Dict<BigStr*, BigStr*>* exported = nullptr;
  value::Str* val = nullptr;
  StackRoot _root0(&exported);
  StackRoot _root1(&val);

  exported = Alloc<Dict<BigStr*, BigStr*>>();
  for (ListIter<Dict<BigStr*, runtime_asdl::Cell*>*> it(this->var_stack); !it.Done(); it.Next()) {
    Dict<BigStr*, runtime_asdl::Cell*>* scope = it.Value();
    StackRoot _for(&scope  );
    for (DictIter<BigStr*, runtime_asdl::Cell*> it(scope); !it.Done(); it.Next()) {
      BigStr* name = it.Key();
      runtime_asdl::Cell* cell = it.Value();
      if ((cell->exported and cell->val->tag() == value_e::Str)) {
        val = static_cast<value::Str*>(cell->val);
        exported->set(name, val->s);
      }
    }
  }
  return exported;
}

List<BigStr*>* Mem::VarNames() {
  List<BigStr*>* ret = nullptr;
  StackRoot _root0(&ret);

  ret = Alloc<List<BigStr*>>();
  for (ListIter<Dict<BigStr*, runtime_asdl::Cell*>*> it(this->var_stack); !it.Done(); it.Next()) {
    Dict<BigStr*, runtime_asdl::Cell*>* scope = it.Value();
    StackRoot _for(&scope  );
    for (DictIter<BigStr*, runtime_asdl::Cell*> it(scope); !it.Done(); it.Next()) {
      BigStr* name = it.Key();
      StackRoot _for(&name    );
      ret->append(name);
    }
  }
  return ret;
}

List<BigStr*>* Mem::VarNamesStartingWith(BigStr* prefix) {
  List<BigStr*>* names = nullptr;
  StackRoot _root0(&prefix);
  StackRoot _root1(&names);

  names = Alloc<List<BigStr*>>();
  for (ListIter<Dict<BigStr*, runtime_asdl::Cell*>*> it(this->var_stack); !it.Done(); it.Next()) {
    Dict<BigStr*, runtime_asdl::Cell*>* scope = it.Value();
    StackRoot _for(&scope  );
    for (DictIter<BigStr*, runtime_asdl::Cell*> it(scope); !it.Done(); it.Next()) {
      BigStr* name = it.Key();
      StackRoot _for(&name    );
      if (name->startswith(prefix)) {
        names->append(name);
      }
    }
  }
  return names;
}

Dict<BigStr*, BigStr*>* Mem::GetAllVars() {
  Dict<BigStr*, BigStr*>* result = nullptr;
  value_asdl::value_t* val = nullptr;
  value::Str* str_val = nullptr;
  StackRoot _root0(&result);
  StackRoot _root1(&val);
  StackRoot _root2(&str_val);

  result = Alloc<Dict<BigStr*, BigStr*>>();
  for (ListIter<Dict<BigStr*, runtime_asdl::Cell*>*> it(this->var_stack); !it.Done(); it.Next()) {
    Dict<BigStr*, runtime_asdl::Cell*>* scope = it.Value();
    StackRoot _for(&scope  );
    for (DictIter<BigStr*, runtime_asdl::Cell*> it(scope); !it.Done(); it.Next()) {
      BigStr* name = it.Key();
      runtime_asdl::Cell* cell = it.Value();
      val = cell->val;
      if (val->tag() == value_e::Str) {
        str_val = static_cast<value::Str*>(val);
        result->set(name, str_val->s);
      }
    }
  }
  return result;
}

Dict<BigStr*, runtime_asdl::Cell*>* Mem::GetAllCells(runtime_asdl::scope_t which_scopes) {
  Dict<BigStr*, runtime_asdl::Cell*>* result = nullptr;
  List<Dict<BigStr*, runtime_asdl::Cell*>*>* scopes = nullptr;
  StackRoot _root0(&result);
  StackRoot _root1(&scopes);

  result = Alloc<Dict<BigStr*, runtime_asdl::Cell*>>();
  if (which_scopes == scope_e::Dynamic) {
    scopes = this->var_stack;
  }
  else {
    if (which_scopes == scope_e::LocalOnly) {
      scopes = this->var_stack->slice(-1);
    }
    else {
      if (which_scopes == scope_e::GlobalOnly) {
        scopes = this->var_stack->slice(0, 1);
      }
      else {
        if (which_scopes == scope_e::LocalOrGlobal) {
          scopes = NewList<Dict<BigStr*, runtime_asdl::Cell*>*>(std::initializer_list<Dict<BigStr*, runtime_asdl::Cell*>*>{this->var_stack->at(0)});
          if (len(this->var_stack) > 1) {
            scopes->append(this->var_stack->at(-1));
          }
        }
        else {
          assert(0);  // AssertionError
        }
      }
    }
  }
  for (ListIter<Dict<BigStr*, runtime_asdl::Cell*>*> it(scopes); !it.Done(); it.Next()) {
    Dict<BigStr*, runtime_asdl::Cell*>* scope = it.Value();
    StackRoot _for(&scope  );
    for (DictIter<BigStr*, runtime_asdl::Cell*> it(scope); !it.Done(); it.Next()) {
      BigStr* name = it.Key();
      runtime_asdl::Cell* cell = it.Value();
      result->set(name, cell);
    }
  }
  return result;
}

bool Mem::IsGlobalScope() {
  return len(this->var_stack) == 1;
}

void Mem::SetRegexMatch(value_asdl::regex_match_t* match) {
  StackRoot _root0(&match);

  this->regex_match->set(-1, match);
}

value_asdl::regex_match_t* Mem::GetRegexMatch() {
  return this->regex_match->at(-1);
}

void Mem::PushContextStack(Dict<BigStr*, value_asdl::value_t*>* context) {
  StackRoot _root0(&context);

  this->ctx_stack->append(context);
}

Dict<BigStr*, value_asdl::value_t*>* Mem::GetContext() {
  if (len(this->ctx_stack)) {
    return this->ctx_stack->at(-1);
  }
  return nullptr;
}

Dict<BigStr*, value_asdl::value_t*>* Mem::PopContextStack() {
  return this->ctx_stack->pop();
}

void OshLanguageSetValue(state::Mem* mem, value_asdl::sh_lvalue_t* lval, value_asdl::value_t* val, int flags) {
  runtime_asdl::scope_t which_scopes;
  StackRoot _root0(&mem);
  StackRoot _root1(&lval);
  StackRoot _root2(&val);

  which_scopes = mem->ScopesForWriting();
  mem->SetValue(lval, val, which_scopes, flags);
}

void BuiltinSetValue(state::Mem* mem, value_asdl::sh_lvalue_t* lval, value_asdl::value_t* val) {
  StackRoot _root0(&mem);
  StackRoot _root1(&lval);
  StackRoot _root2(&val);

  mem->SetValue(lval, val, mem->ScopesForWriting());
}

void BuiltinSetString(state::Mem* mem, BigStr* name, BigStr* s) {
  StackRoot _root0(&mem);
  StackRoot _root1(&name);
  StackRoot _root2(&s);

  BuiltinSetValue(mem, location::LName(name), Alloc<value::Str>(s));
}

void BuiltinSetArray(state::Mem* mem, BigStr* name, List<BigStr*>* a) {
  StackRoot _root0(&mem);
  StackRoot _root1(&name);
  StackRoot _root2(&a);

  BuiltinSetValue(mem, location::LName(name), Alloc<value::BashArray>(a));
}

void SetGlobalString(state::Mem* mem, BigStr* name, BigStr* s) {
  value::Str* val = nullptr;
  StackRoot _root0(&mem);
  StackRoot _root1(&name);
  StackRoot _root2(&s);
  StackRoot _root3(&val);

  val = Alloc<value::Str>(s);
  mem->SetNamed(location::LName(name), val, scope_e::GlobalOnly);
}

void SetGlobalArray(state::Mem* mem, BigStr* name, List<BigStr*>* a) {
  StackRoot _root0(&mem);
  StackRoot _root1(&name);
  StackRoot _root2(&a);

  mem->SetNamed(location::LName(name), Alloc<value::BashArray>(a), scope_e::GlobalOnly);
}

void ExportGlobalString(state::Mem* mem, BigStr* name, BigStr* s) {
  value::Str* val = nullptr;
  StackRoot _root0(&mem);
  StackRoot _root1(&name);
  StackRoot _root2(&s);
  StackRoot _root3(&val);

  val = Alloc<value::Str>(s);
  mem->SetNamed(location::LName(name), val, scope_e::GlobalOnly, SetExport);
}

value_asdl::value_t* DynamicGetVar(state::Mem* mem, BigStr* name, runtime_asdl::scope_t which_scopes) {
  value_asdl::value_t* val = nullptr;
  StackRoot _root0(&mem);
  StackRoot _root1(&name);
  StackRoot _root2(&val);

  val = mem->GetValue(name, which_scopes);
  if (val->tag() == value_e::Undef) {
    return value::Null;
  }
  return val;
}

BigStr* GetString(state::Mem* mem, BigStr* name) {
  value_asdl::value_t* val = nullptr;
  value_asdl::value_t* UP_val = nullptr;
  StackRoot _root0(&mem);
  StackRoot _root1(&name);
  StackRoot _root2(&val);
  StackRoot _root3(&UP_val);

  val = mem->GetValue(name);
  UP_val = val;
  switch (val->tag()) {
    case value_e::Undef: {
      throw Alloc<error::Runtime>(StrFormat("$%s isn't defined", name));
    }
      break;
    case value_e::Str: {
      return static_cast<value::Str*>(UP_val)->s;
    }
      break;
    default: {
      throw Alloc<error::Runtime>(StrFormat("$%s should be a string", name));
    }
  }
}

BigStr* MaybeString(state::Mem* mem, BigStr* name) {
  StackRoot _root0(&mem);
  StackRoot _root1(&name);

  try {
    return GetString(mem, name);
  }
  catch (error::Runtime*) {
    return nullptr;
  }
}

int GetInteger(state::Mem* mem, BigStr* name) {
  value_asdl::value_t* val = nullptr;
  BigStr* s = nullptr;
  int i;
  StackRoot _root0(&mem);
  StackRoot _root1(&name);
  StackRoot _root2(&val);
  StackRoot _root3(&s);

  val = mem->GetValue(name);
  if (val->tag() != value_e::Str) {
    throw Alloc<error::Runtime>(StrFormat("$%s should be a string, got %s", name, ui::ValType(val)));
  }
  s = static_cast<value::Str*>(val)->s;
  try {
    i = to_int(s);
  }
  catch (ValueError*) {
    throw Alloc<error::Runtime>(StrFormat("$%s doesn't look like an integer, got %r", name, s));
  }
  return i;
}

}  // define namespace state

namespace ui {  // define

using id_kind_asdl::Id;
using id_kind_asdl::Id_t;
using id_kind_asdl::Id_str;
using syntax_asdl::Token;
using syntax_asdl::SourceLine;
using syntax_asdl::loc;
using syntax_asdl::loc_e;
using syntax_asdl::loc_t;
using syntax_asdl::command_t;
using syntax_asdl::command_str;
using syntax_asdl::source;
using syntax_asdl::source_e;
using value_asdl::value_t;
using value_asdl::value_str;
namespace fmt = format;
using mylib::print_stderr;

BigStr* ValType(value_asdl::value_t* val) {
  StackRoot _root0(&val);

  return value_str(val->tag(), false);
}

BigStr* CommandType(syntax_asdl::command_t* cmd) {
  StackRoot _root0(&cmd);

  return command_str(cmd->tag());
}

BigStr* PrettyId(int id_) {
  return Id_str(id_);
}

BigStr* PrettyToken(syntax_asdl::Token* tok) {
  BigStr* val = nullptr;
  StackRoot _root0(&tok);
  StackRoot _root1(&val);

  if (tok->id == Id::Eof_Real) {
    return str1070;
  }
  val = tok->line->content->slice(tok->col, (tok->col + tok->length));
  return repr(val);
}

BigStr* PrettyDir(BigStr* dir_name, BigStr* home_dir) {
  StackRoot _root0(&dir_name);
  StackRoot _root1(&home_dir);

  if (home_dir != nullptr) {
    if ((str_equals(dir_name, home_dir) or dir_name->startswith(str_concat(home_dir, str1071)))) {
      return str_concat(str1072, dir_name->slice(len(home_dir)));
    }
  }
  return dir_name;
}

void _PrintCodeExcerpt(BigStr* line, int col, int length, mylib::Writer* f) {
  mylib::BufWriter* buf = nullptr;
  StackRoot _root0(&line);
  StackRoot _root1(&f);
  StackRoot _root2(&buf);

  buf = Alloc<mylib::BufWriter>();
  buf->write(str1073);
  buf->write(line->rstrip());
  buf->write(str1074);
  for (StrIter it(line->slice(0, col)); !it.Done(); it.Next()) {
    BigStr* c = it.Value();
    StackRoot _for(&c  );
    buf->write(str_equals(c, str1075) ? str1076 : str1077);
  }
  buf->write(str1078);
  buf->write(str_repeat(str1079, (length - 1)));
  buf->write(str1080);
  f->write(buf->getvalue());
}

void _PrintTokenTooLong(loc::TokenTooLong* loc_tok, mylib::Writer* f) {
  syntax_asdl::SourceLine* line = nullptr;
  int col;
  mylib::BufWriter* buf = nullptr;
  BigStr* source_str = nullptr;
  StackRoot _root0(&loc_tok);
  StackRoot _root1(&f);
  StackRoot _root2(&line);
  StackRoot _root3(&buf);
  StackRoot _root4(&source_str);

  line = loc_tok->line;
  col = loc_tok->col;
  buf = Alloc<mylib::BufWriter>();
  buf->write(str1081);
  buf->write(line->content->slice(0, (col + 10))->rstrip());
  buf->write(str1082);
  for (StrIter it(line->content->slice(0, col)); !it.Done(); it.Next()) {
    BigStr* c = it.Value();
    StackRoot _for(&c  );
    buf->write(str_equals(c, str1083) ? str1084 : str1085);
  }
  buf->write(str1086);
  source_str = GetLineSourceString(loc_tok->line, true);
  buf->write(StrFormat("%s:%d: Token starting at column %d is too long: %d bytes (%s)\n", source_str, line->line_num, loc_tok->col, loc_tok->length, Id_str(loc_tok->id)));
  f->write(buf->getvalue());
}

BigStr* GetLineSourceString(syntax_asdl::SourceLine* line, bool quote_filename) {
  syntax_asdl::source_t* src = nullptr;
  syntax_asdl::source_t* UP_src = nullptr;
  BigStr* s = nullptr;
  syntax_asdl::Token* blame_tok = nullptr;
  int line_num;
  BigStr* outer_source = nullptr;
  BigStr* var_name = nullptr;
  BigStr* where = nullptr;
  syntax_asdl::Token* orig_tok = nullptr;
  syntax_asdl::Token* span2 = nullptr;
  StackRoot _root0(&line);
  StackRoot _root1(&src);
  StackRoot _root2(&UP_src);
  StackRoot _root3(&s);
  StackRoot _root4(&blame_tok);
  StackRoot _root5(&outer_source);
  StackRoot _root6(&var_name);
  StackRoot _root7(&where);
  StackRoot _root8(&orig_tok);
  StackRoot _root9(&span2);

  src = line->src;
  UP_src = src;
  switch (src->tag()) {
    case source_e::Interactive: {
      s = str1088;
    }
      break;
    case source_e::Headless: {
      s = str1089;
    }
      break;
    case source_e::CFlag: {
      s = str1090;
    }
      break;
    case source_e::Stdin: {
      source::Stdin* src = static_cast<source::Stdin*>(UP_src);
      s = StrFormat("[ stdin%s ]", src->comment);
    }
      break;
    case source_e::MainFile: {
      source::MainFile* src = static_cast<source::MainFile*>(UP_src);
      s = src->path;
      if (quote_filename) {
        s = j8_lite::EncodeString(s, true);
      }
    }
      break;
    case source_e::SourcedFile: {
      source::SourcedFile* src = static_cast<source::SourcedFile*>(UP_src);
      s = src->path;
      if (quote_filename) {
        s = j8_lite::EncodeString(s, true);
      }
    }
      break;
    case source_e::ArgvWord: {
      source::ArgvWord* src = static_cast<source::ArgvWord*>(UP_src);
      blame_tok = location::TokenFor(src->location);
      if (blame_tok == nullptr) {
        s = StrFormat("[ %s word at ? ]", src->what);
      }
      else {
        line = blame_tok->line;
        line_num = line->line_num;
        outer_source = GetLineSourceString(line, quote_filename);
        s = StrFormat("[ %s word at line %d of %s ]", src->what, line_num, outer_source);
      }
    }
      break;
    case source_e::Variable: {
      source::Variable* src = static_cast<source::Variable*>(UP_src);
      if (src->var_name == nullptr) {
        var_name = str1094;
      }
      else {
        var_name = repr(src->var_name);
      }
      if (src->location->tag() == loc_e::Missing) {
        where = str1095;
      }
      else {
        blame_tok = location::TokenFor(src->location);
        line_num = blame_tok->line->line_num;
        outer_source = GetLineSourceString(blame_tok->line, quote_filename);
        where = StrFormat("line %d of %s", line_num, outer_source);
      }
      s = StrFormat("[ var %s at %s ]", var_name, where);
    }
      break;
    case source_e::VarRef: {
      source::VarRef* src = static_cast<source::VarRef*>(UP_src);
      orig_tok = src->orig_tok;
      line_num = orig_tok->line->line_num;
      outer_source = GetLineSourceString(orig_tok->line, quote_filename);
      where = StrFormat("line %d of %s", line_num, outer_source);
      var_name = lexer::TokenVal(orig_tok);
      s = StrFormat("[ contents of var %r at %s ]", var_name, where);
    }
      break;
    case source_e::Alias: {
      source::Alias* src = static_cast<source::Alias*>(UP_src);
      s = StrFormat("[ expansion of alias %r ]", src->argv0);
    }
      break;
    case source_e::Reparsed: {
      source::Reparsed* src = static_cast<source::Reparsed*>(UP_src);
      span2 = src->left_token;
      outer_source = GetLineSourceString(span2->line, quote_filename);
      s = StrFormat("[ %s in %s ]", src->what, outer_source);
    }
      break;
    case source_e::Synthetic: {
      source::Synthetic* src = static_cast<source::Synthetic*>(UP_src);
      s = StrFormat("-- %s", src->s);
    }
      break;
    default: {
      assert(0);  // AssertionError
    }
  }
  return s;
}

void _PrintWithLocation(BigStr* prefix, BigStr* msg, syntax_asdl::loc_t* blame_loc, bool show_code) {
  mylib::Writer* f = nullptr;
  syntax_asdl::Token* blame_tok = nullptr;
  int orig_col;
  syntax_asdl::source_t* src = nullptr;
  BigStr* line = nullptr;
  int line_num;
  syntax_asdl::source_t* UP_src = nullptr;
  syntax_asdl::Token* tok2 = nullptr;
  BigStr* line2 = nullptr;
  int lbracket_col;
  BigStr* source_str = nullptr;
  StackRoot _root0(&prefix);
  StackRoot _root1(&msg);
  StackRoot _root2(&blame_loc);
  StackRoot _root3(&f);
  StackRoot _root4(&blame_tok);
  StackRoot _root5(&src);
  StackRoot _root6(&line);
  StackRoot _root7(&UP_src);
  StackRoot _root8(&tok2);
  StackRoot _root9(&line2);
  StackRoot _root10(&source_str);

  f = mylib::Stderr();
  if (blame_loc->tag() == loc_e::TokenTooLong) {
    _PrintTokenTooLong(static_cast<loc::TokenTooLong*>(blame_loc), f);
    return ;
  }
  blame_tok = location::TokenFor(blame_loc);
  if (blame_tok == nullptr) {
    f->write(StrFormat("[??? no location ???] %s%s\n", prefix, msg));
    return ;
  }
  orig_col = blame_tok->col;
  src = blame_tok->line->src;
  line = blame_tok->line->content;
  line_num = blame_tok->line->line_num;
  if (show_code) {
    UP_src = src;
    switch (src->tag()) {
      case source_e::Reparsed: {
        source::Reparsed* src = static_cast<source::Reparsed*>(UP_src);
        tok2 = src->left_token;
        line_num = tok2->line->line_num;
        line2 = tok2->line->content;
        lbracket_col = (tok2->col + tok2->length);
        _PrintCodeExcerpt(line2, (orig_col + lbracket_col), 1, f);
      }
        break;
      case source_e::ArgvWord: {
        source::ArgvWord* src = static_cast<source::ArgvWord*>(UP_src);
        _PrintCodeExcerpt(line, blame_tok->col, blame_tok->length, f);
        source_str = GetLineSourceString(blame_tok->line, true);
        f->write(StrFormat("%s:%d\n", source_str, line_num));
        f->write(str1105);
        _PrintWithLocation(prefix, msg, src->location, show_code);
        return ;
      }
        break;
      default: {
        _PrintCodeExcerpt(line, blame_tok->col, blame_tok->length, f);
      }
    }
  }
  source_str = GetLineSourceString(blame_tok->line, true);
  f->write(StrFormat("%s:%d: %s%s\n", source_str, line_num, prefix, msg));
}

ctx_Location::ctx_Location(ui::ErrorFormatter* errfmt, syntax_asdl::loc_t* location) {
  gHeap.PushRoot(reinterpret_cast<RawObject**>(&(this->errfmt)));
  errfmt->loc_stack->append(location);
  this->errfmt = errfmt;
}

ctx_Location::~ctx_Location() {
  this->errfmt->loc_stack->pop();
  gHeap.PopRoot();
}

ErrorFormatter::ErrorFormatter() {
  this->loc_stack = Alloc<List<syntax_asdl::loc_t*>>();
  this->one_line_errexit = false;
}

void ErrorFormatter::OneLineErrExit() {
  this->one_line_errexit = true;
}

syntax_asdl::loc_t* ErrorFormatter::_FallbackLocation(syntax_asdl::loc_t* blame_loc) {
  StackRoot _root0(&blame_loc);

  if ((blame_loc == nullptr or blame_loc->tag() == loc_e::Missing)) {
    if (len(this->loc_stack)) {
      return this->loc_stack->at(-1);
    }
    return loc::Missing;
  }
  return blame_loc;
}

void ErrorFormatter::PrefixPrint(BigStr* msg, BigStr* prefix, syntax_asdl::loc_t* blame_loc) {
  StackRoot _root0(&msg);
  StackRoot _root1(&prefix);
  StackRoot _root2(&blame_loc);

  _PrintWithLocation(prefix, msg, this->_FallbackLocation(blame_loc), true);
}

void ErrorFormatter::Print_(BigStr* msg, syntax_asdl::loc_t* blame_loc) {
  StackRoot _root0(&msg);
  StackRoot _root1(&blame_loc);

  _PrintWithLocation(str1107, msg, this->_FallbackLocation(blame_loc), true);
}

void ErrorFormatter::PrintMessage(BigStr* msg, syntax_asdl::loc_t* blame_loc) {
  StackRoot _root0(&msg);
  StackRoot _root1(&blame_loc);

  _PrintWithLocation(str1108, msg, this->_FallbackLocation(blame_loc), false);
}

void ErrorFormatter::StderrLine(BigStr* msg) {
  StackRoot _root0(&msg);

  print_stderr(msg);
}

void ErrorFormatter::PrettyPrintError(error::_ErrorWithLocation* err, BigStr* prefix) {
  StackRoot _root0(&err);
  StackRoot _root1(&prefix);

  _PrintWithLocation(prefix, err->UserErrorString(), err->location, true);
}

void ErrorFormatter::PrintErrExit(error::ErrExit* err, int pid) {
  BigStr* prefix = nullptr;
  StackRoot _root0(&err);
  StackRoot _root1(&prefix);

  prefix = StrFormat("errexit PID %d: ", pid);
  _PrintWithLocation(prefix, err->UserErrorString(), err->location, err->show_code);
}

void PrintAst(syntax_asdl::command_t* node, arg_types::main* flag) {
  mylib::Writer* f = nullptr;
  BigStr* afmt = nullptr;
  format::ColorOutput* ast_f = nullptr;
  hnode_asdl::hnode_t* tree = nullptr;
  StackRoot _root0(&node);
  StackRoot _root1(&flag);
  StackRoot _root2(&f);
  StackRoot _root3(&afmt);
  StackRoot _root4(&ast_f);
  StackRoot _root5(&tree);

  if (maybe_str_equals(flag->ast_format, str1111)) {
    print_stderr(str1112);
  }
  else {
    f = mylib::Stdout();
    afmt = flag->ast_format;
    if ((maybe_str_equals(afmt, str1121) || maybe_str_equals(afmt, str1122))) {
      ast_f = fmt::DetectConsoleOutput(f);
    }
    else {
      if ((maybe_str_equals(afmt, str1123) || maybe_str_equals(afmt, str1124))) {
        ast_f = Alloc<fmt::HtmlOutput>(f);
      }
      else {
        assert(0);  // AssertionError
      }
    }
    if (str_contains(afmt, str1125)) {
      // if not PYTHON
      {
        tree = node->PrettyTree();
      }
      // endif MYCPP
    }
    else {
      tree = node->PrettyTree();
    }
    ast_f->FileHeader();
    fmt::PrintTree(tree, ast_f);
    ast_f->FileFooter();
    ast_f->write(str1126);
  }
}

void PrettyPrintValue(value_asdl::value_t* val, mylib::Writer* f) {
  pretty::PrettyPrinter* printer = nullptr;
  int width;
  mylib::BufWriter* buf = nullptr;
  StackRoot _root0(&val);
  StackRoot _root1(&f);
  StackRoot _root2(&printer);
  StackRoot _root3(&buf);

  printer = Alloc<pretty::PrettyPrinter>();
  printer->SetUseStyles(f->isatty());
  try {
    width = libc::get_terminal_width();
    if (width > 0) {
      printer->SetMaxWidth(width);
    }
  }
  catch (IOError_OSError*) {
    ;  // pass
  }
  buf = Alloc<mylib::BufWriter>();
  printer->PrintValue(val, buf);
  f->write(buf->getvalue());
  f->write(str1127);
}

}  // define namespace ui

namespace util {  // define


List<BigStr*>* RegexGroupStrings(BigStr* s, List<int>* indices) {
  List<BigStr*>* groups = nullptr;
  int n;
  int start;
  int end;
  StackRoot _root0(&s);
  StackRoot _root1(&indices);
  StackRoot _root2(&groups);

  groups = Alloc<List<BigStr*>>();
  n = len(indices);
  for (int i = 0; i < (n / 2); ++i) {
    start = indices->at((2 * i));
    end = indices->at(((2 * i) + 1));
    if (start == -1) {
      groups->append(str1128);
    }
    else {
      groups->append(s->slice(start, end));
    }
  }
  return groups;
}

List<BigStr*>* RegexSearch(BigStr* pat, BigStr* s) {
  List<int>* indices = nullptr;
  StackRoot _root0(&pat);
  StackRoot _root1(&s);
  StackRoot _root2(&indices);

  indices = libc::regex_search(pat, 0, s, 0);
  if (indices == nullptr) {
    return nullptr;
  }
  return RegexGroupStrings(s, indices);
}

UserExit::UserExit(int status) {
  this->status = status;
}

HistoryError::HistoryError(BigStr* msg) {
  this->msg = msg;
}

BigStr* HistoryError::UserErrorString() {
  return StrFormat("history: %s", this->msg);
}

_DebugFile::_DebugFile() {
  ;  // pass
}

void _DebugFile::write(BigStr* s) {
  StackRoot _root0(&s);

  ;  // pass
}

void _DebugFile::writeln(BigStr* s) {
  StackRoot _root0(&s);

  ;  // pass
}

bool _DebugFile::isatty() {
  return false;
}

NullDebugFile::NullDebugFile() : ::util::_DebugFile() {
}

DebugFile::DebugFile(mylib::Writer* f) : ::util::_DebugFile() {
  this->f = f;
}

void DebugFile::write(BigStr* s) {
  StackRoot _root0(&s);

  this->f->write(s);
}

void DebugFile::writeln(BigStr* s) {
  StackRoot _root0(&s);

  this->write(str_concat(s, str1130));
  this->f->flush();
}

bool DebugFile::isatty() {
  return this->f->isatty();
}

void PrintTopicHeader(BigStr* topic_id, mylib::Writer* f) {
  StackRoot _root0(&topic_id);
  StackRoot _root1(&f);

  if (f->isatty()) {
    f->write(StrFormat("%s %s %s\n", ansi::REVERSE, topic_id, ansi::RESET));
  }
  else {
    f->write(StrFormat("~~~ %s ~~~\n", topic_id));
  }
  f->write(str1133);
}

bool PrintEmbeddedHelp(pyutil::_ResourceLoader* loader, BigStr* topic_id, mylib::Writer* f) {
  BigStr* contents = nullptr;
  StackRoot _root0(&loader);
  StackRoot _root1(&topic_id);
  StackRoot _root2(&f);
  StackRoot _root3(&contents);

  try {
    contents = loader->Get(StrFormat("_devbuild/help/%s", topic_id));
  }
  catch (IOError_OSError*) {
    return false;
  }
  PrintTopicHeader(topic_id, f);
  f->write(contents);
  f->write(str1135);
  return true;
}

void _PrintVersionLine(pyutil::_ResourceLoader* loader, mylib::Writer* f) {
  BigStr* v = nullptr;
  StackRoot _root0(&loader);
  StackRoot _root1(&f);
  StackRoot _root2(&v);

  v = pyutil::GetVersion(loader);
  f->write(StrFormat("Oils %s\t\thttps://www.oilshell.org/\n", v));
}

void HelpFlag(pyutil::_ResourceLoader* loader, BigStr* topic_id, mylib::Writer* f) {
  bool found;
  StackRoot _root0(&loader);
  StackRoot _root1(&topic_id);
  StackRoot _root2(&f);

  _PrintVersionLine(loader, f);
  f->write(str1137);
  found = PrintEmbeddedHelp(loader, topic_id, f);
}

void VersionFlag(pyutil::_ResourceLoader* loader, mylib::Writer* f) {
  StackRoot _root0(&loader);
  StackRoot _root1(&f);

  _PrintVersionLine(loader, f);
  f->write(str1138);
  pyutil::PrintVersionDetails(loader);
}

}  // define namespace util

namespace j8 {  // define

using id_kind_asdl::Id;
using id_kind_asdl::Id_t;
using id_kind_asdl::Id_str;
using value_asdl::value;
using value_asdl::value_e;
using value_asdl::value_t;
using value_asdl::value_str;
using nil8_asdl::nvalue;
using nil8_asdl::nvalue_t;
namespace fmt = format;

BigStr* ValType(value_asdl::value_t* val) {
  StackRoot _root0(&val);

  return value_str(val->tag(), false);
}

int ValueId(value_asdl::value_t* val) {
  StackRoot _root0(&val);

  switch (val->tag()) {
    case value_e::Null: 
    case value_e::Bool: 
    case value_e::Int: 
    case value_e::Float: 
    case value_e::Str: {
      return -1;
    }
      break;
    default: {
      return HeapValueId(val);
    }
  }
}

BigStr* ValueIdString(value_asdl::value_t* val) {
  int heap_id;
  StackRoot _root0(&val);

  heap_id = ValueId(val);
  if (heap_id == -1) {
    return str1139;
  }
  else {
    return StrFormat(" 0x%s", mylib::hex_lower(heap_id));
  }
}

BigStr* Utf8Encode(int code) {
  int num_cont_bytes;
  List<int>* bytes_ = nullptr;
  int b;
  List<BigStr*>* tmp = nullptr;
  StackRoot _root0(&bytes_);
  StackRoot _root1(&tmp);

  num_cont_bytes = 0;
  if (code <= 127) {
    return chr((code & 127));
  }
  else {
    if (code <= 2047) {
      num_cont_bytes = 1;
    }
    else {
      if (code <= 65535) {
        num_cont_bytes = 2;
      }
      else {
        num_cont_bytes = 3;
      }
    }
  }
  bytes_ = Alloc<List<int>>();
  for (int _ = 0; _ < num_cont_bytes; ++_) {
    bytes_->append((128 | (code & 63)));
    code >>= 6;
  }
  b = ((30 << (6 - num_cont_bytes)) | (code & (63 >> num_cont_bytes)));
  bytes_->append(b);
  bytes_->reverse();
  tmp = Alloc<List<BigStr*>>();
  for (ListIter<int> it(bytes_); !it.Done(); it.Next()) {
    int b = it.Value();
    tmp->append(chr((b & 255)));
  }
  return str1141->join(tmp);
}
int SHOW_CYCLES = (1 << 1);
int SHOW_NON_DATA = (1 << 2);
int LOSSY_JSON = (1 << 3);

void _Print(value_asdl::value_t* val, mylib::BufWriter* buf, int indent, int options) {
  j8::InstancePrinter* p = nullptr;
  StackRoot _root0(&val);
  StackRoot _root1(&buf);
  StackRoot _root2(&p);

  p = Alloc<InstancePrinter>(buf, indent, options);
  p->Print(val);
}

void PrintMessage(value_asdl::value_t* val, mylib::BufWriter* buf, int indent) {
  StackRoot _root0(&val);
  StackRoot _root1(&buf);

  _Print(val, buf, indent);
}

void PrintJsonMessage(value_asdl::value_t* val, mylib::BufWriter* buf, int indent) {
  StackRoot _root0(&val);
  StackRoot _root1(&buf);

  _Print(val, buf, indent, LOSSY_JSON);
}

void PrintLine(value_asdl::value_t* val, mylib::Writer* f) {
  mylib::BufWriter* buf = nullptr;
  StackRoot _root0(&val);
  StackRoot _root1(&f);
  StackRoot _root2(&buf);

  buf = Alloc<mylib::BufWriter>();
  _Print(val, buf, -1, (SHOW_CYCLES | SHOW_NON_DATA));
  f->write(buf->getvalue());
  f->write(str1142);
}

void EncodeString(BigStr* s, mylib::BufWriter* buf, bool unquoted_ok) {
  StackRoot _root0(&s);
  StackRoot _root1(&buf);

  if ((unquoted_ok and fastfunc::CanOmitQuotes(s))) {
    buf->write(s);
    return ;
  }
  _Print(Alloc<value::Str>(s), buf, -1);
}

BigStr* MaybeEncodeString(BigStr* s) {
  mylib::BufWriter* buf = nullptr;
  StackRoot _root0(&s);
  StackRoot _root1(&buf);

  buf = Alloc<mylib::BufWriter>();
  _Print(Alloc<value::Str>(s), buf, -1);
  return buf->getvalue();
}

BigStr* MaybeEncodeJsonString(BigStr* s) {
  mylib::BufWriter* buf = nullptr;
  StackRoot _root0(&s);
  StackRoot _root1(&buf);

  buf = Alloc<mylib::BufWriter>();
  _Print(Alloc<value::Str>(s), buf, -1, LOSSY_JSON);
  return buf->getvalue();
}
int UNSEEN = 0;
int EXPLORING = 1;
int FINISHED = 2;

InstancePrinter::InstancePrinter(mylib::BufWriter* buf, int indent, int options) {
  this->buf = buf;
  this->indent = indent;
  this->options = options;
  this->visited = Alloc<Dict<int, int>>();
}

void InstancePrinter::_ItemIndent(int level) {
  if (this->indent == -1) {
    return ;
  }
  this->buf->write_spaces(((level + 1) * this->indent));
}

void InstancePrinter::_BracketIndent(int level) {
  if (this->indent == -1) {
    return ;
  }
  this->buf->write_spaces((level * this->indent));
}

void InstancePrinter::_MaybeNewline() {
  if (this->indent == -1) {
    return ;
  }
  this->buf->write(str1143);
}

void InstancePrinter::_MaybeSpace() {
  if (this->indent == -1) {
    return ;
  }
  this->buf->write(str1144);
}

void InstancePrinter::_PrintList(value::List* val, int level) {
  int i;
  StackRoot _root0(&val);

  if (len(val->items) == 0) {
    this->buf->write(str1145);
  }
  else {
    this->buf->write(str1146);
    this->_MaybeNewline();
    i = 0;
    for (ListIter<value_asdl::value_t*> it(val->items); !it.Done(); it.Next(), ++i) {
      value_asdl::value_t* item = it.Value();
      StackRoot _for(&item    );
      if (i != 0) {
        this->buf->write(str1147);
        this->_MaybeNewline();
      }
      this->_ItemIndent(level);
      this->Print(item, (level + 1));
    }
    this->_MaybeNewline();
    this->_BracketIndent(level);
    this->buf->write(str1148);
  }
}

void InstancePrinter::_PrintDict(value::Dict* val, int level) {
  int i;
  StackRoot _root0(&val);

  if (len(val->d) == 0) {
    this->buf->write(str1149);
  }
  else {
    this->buf->write(str1150);
    this->_MaybeNewline();
    i = 0;
    for (DictIter<BigStr*, value_asdl::value_t*> it(val->d); !it.Done(); it.Next()) {
      BigStr* k = it.Key();
      value_asdl::value_t* v = it.Value();
      if (i != 0) {
        this->buf->write(str1151);
        this->_MaybeNewline();
      }
      this->_ItemIndent(level);
      pyj8::WriteString(k, this->options, this->buf);
      this->buf->write(str1152);
      this->_MaybeSpace();
      this->Print(v, (level + 1));
      i += 1;
    }
    this->_MaybeNewline();
    this->_BracketIndent(level);
    this->buf->write(str1153);
  }
}

void InstancePrinter::Print(value_asdl::value_t* val, int level) {
  value_asdl::value_t* UP_val = nullptr;
  int heap_id;
  int node_state;
  int i;
  BigStr* ysh_type = nullptr;
  BigStr* id_str = nullptr;
  StackRoot _root0(&val);
  StackRoot _root1(&UP_val);
  StackRoot _root2(&ysh_type);
  StackRoot _root3(&id_str);

  UP_val = val;
  switch (val->tag()) {
    case value_e::Null: {
      this->buf->write(str1154);
    }
      break;
    case value_e::Bool: {
      value::Bool* val = static_cast<value::Bool*>(UP_val);
      this->buf->write(val->b ? str1155 : str1156);
    }
      break;
    case value_e::Int: {
      value::Int* val = static_cast<value::Int*>(UP_val);
      this->buf->write(mops::ToStr(val->i));
    }
      break;
    case value_e::Float: {
      value::Float* val = static_cast<value::Float*>(UP_val);
      this->buf->write(str(val->f));
    }
      break;
    case value_e::Str: {
      value::Str* val = static_cast<value::Str*>(UP_val);
      pyj8::WriteString(val->s, this->options, this->buf);
    }
      break;
    case value_e::List: {
      value::List* val = static_cast<value::List*>(UP_val);
      heap_id = HeapValueId(val);
      node_state = this->visited->get(heap_id, UNSEEN);
      if (node_state == FINISHED) {
        this->_PrintList(val, level);
        return ;
      }
      if (node_state == EXPLORING) {
        if ((this->options & SHOW_CYCLES)) {
          this->buf->write(StrFormat("[ -->%s ]", ValueIdString(val)));
          return ;
        }
        else {
          throw Alloc<error::Encode>(StrFormat("Can't encode List%s in object cycle", ValueIdString(val)));
        }
      }
      this->visited->set(heap_id, EXPLORING);
      this->_PrintList(val, level);
      this->visited->set(heap_id, FINISHED);
    }
      break;
    case value_e::Dict: {
      value::Dict* val = static_cast<value::Dict*>(UP_val);
      heap_id = HeapValueId(val);
      node_state = this->visited->get(heap_id, UNSEEN);
      if (node_state == FINISHED) {
        this->_PrintDict(val, level);
        return ;
      }
      if (node_state == EXPLORING) {
        if ((this->options & SHOW_CYCLES)) {
          this->buf->write(StrFormat("{ -->%s }", ValueIdString(val)));
          return ;
        }
        else {
          throw Alloc<error::Encode>(StrFormat("Can't encode Dict%s in object cycle", ValueIdString(val)));
        }
      }
      this->visited->set(heap_id, EXPLORING);
      this->_PrintDict(val, level);
      this->visited->set(heap_id, FINISHED);
    }
      break;
    case value_e::BashArray: {
      value::BashArray* val = static_cast<value::BashArray*>(UP_val);
      this->buf->write(str1161);
      this->_MaybeNewline();
      i = 0;
      for (ListIter<BigStr*> it(val->strs); !it.Done(); it.Next(), ++i) {
        BigStr* s = it.Value();
        StackRoot _for(&s      );
        if (i != 0) {
          this->buf->write(str1162);
          this->_MaybeNewline();
        }
        this->_ItemIndent(level);
        if (s == nullptr) {
          this->buf->write(str1163);
        }
        else {
          pyj8::WriteString(s, this->options, this->buf);
        }
      }
      this->_MaybeNewline();
      this->_BracketIndent(level);
      this->buf->write(str1164);
    }
      break;
    case value_e::BashAssoc: {
      value::BashAssoc* val = static_cast<value::BashAssoc*>(UP_val);
      this->buf->write(str1165);
      this->_MaybeNewline();
      i = 0;
      for (DictIter<BigStr*, BigStr*> it(val->d); !it.Done(); it.Next()) {
        BigStr* k2 = it.Key();
        BigStr* v2 = it.Value();
        if (i != 0) {
          this->buf->write(str1166);
          this->_MaybeNewline();
        }
        this->_ItemIndent(level);
        pyj8::WriteString(k2, this->options, this->buf);
        this->buf->write(str1167);
        this->_MaybeSpace();
        pyj8::WriteString(v2, this->options, this->buf);
        i += 1;
      }
      this->_MaybeNewline();
      this->_BracketIndent(level);
      this->buf->write(str1168);
    }
      break;
    default: {
      ;  // pass
      if ((this->options & SHOW_NON_DATA)) {
        ysh_type = ValType(val);
        id_str = ValueIdString(val);
        this->buf->write(StrFormat("<%s%s>", ysh_type, id_str));
      }
      else {
        throw Alloc<error::Encode>(StrFormat("Can't serialize object of type %s", ValType(val)));
      }
    }
  }
}

PrettyPrinter::PrettyPrinter(int max_col) {
  this->max_col = max_col;
  this->ref_count = Alloc<Dict<int, int>>();
}

void PrettyPrinter::PrettyTree(value_asdl::value_t* val, format::ColorOutput* f) {
  StackRoot _root0(&val);
  StackRoot _root1(&f);

  ;  // pass
}

void PrettyPrinter::Print(value_asdl::value_t* val, mylib::BufWriter* buf) {
  format::ColorOutput* f = nullptr;
  StackRoot _root0(&val);
  StackRoot _root1(&buf);
  StackRoot _root2(&f);

  f = fmt::DetectConsoleOutput(mylib::Stdout());
  this->PrettyTree(val, f);
  ;  // pass
}

LexerDecoder::LexerDecoder(BigStr* s, bool is_j8, BigStr* lang_str) {
  this->s = s;
  this->is_j8 = is_j8;
  this->lang_str = lang_str;
  this->pos = 0;
  this->cur_line_num = 1;
  this->decoded = Alloc<mylib::BufWriter>();
}

error::Decode* LexerDecoder::_Error(BigStr* msg, int end_pos) {
  StackRoot _root0(&msg);

  return Alloc<error::Decode>(msg, this->s, this->pos, end_pos, this->cur_line_num);
}

Tuple3<int, int, BigStr*> LexerDecoder::Next() {
  int tok_id;
  int end_pos;
  Tuple2<int, int> tup0 = match::MatchJ8Token(this->s, this->pos);
  tok_id = tup0.at0();
  end_pos = tup0.at1();
  if (!this->is_j8) {
    if ((tok_id == Id::Left_BSingleQuote || tok_id == Id::Left_USingleQuote)) {
      throw this->_Error(str1171, end_pos);
    }
    if (tok_id == Id::Ignored_Comment) {
      throw this->_Error(str1172, end_pos);
    }
  }
  if ((tok_id == Id::Left_DoubleQuote || tok_id == Id::Left_BSingleQuote || tok_id == Id::Left_USingleQuote)) {
    return this->_DecodeString(tok_id, end_pos);
  }
  if (tok_id == Id::Left_JDoubleQuote) {
    if (this->is_j8) {
      return this->_DecodeString(tok_id, end_pos);
    }
    else {
      throw this->_Error(str1173, end_pos);
    }
  }
  if (tok_id == Id::Ignored_Newline) {
    this->cur_line_num += 1;
  }
  this->pos = end_pos;
  return Tuple3<int, int, BigStr*>(tok_id, end_pos, nullptr);
}

Tuple3<int, int, BigStr*> LexerDecoder::NextForLines() {
  int tok_id;
  int end_pos;
  Tuple2<int, int> tup1 = match::MatchJ8LinesToken(this->s, this->pos);
  tok_id = tup1.at0();
  end_pos = tup1.at1();
  if ((tok_id == Id::Left_DoubleQuote || tok_id == Id::Left_JDoubleQuote || tok_id == Id::Left_BSingleQuote || tok_id == Id::Left_USingleQuote)) {
    return this->_DecodeString(tok_id, end_pos);
  }
  if ((tok_id == Id::Lit_Chars and !pyj8::PartIsUtf8(this->s, this->pos, end_pos))) {
    throw this->_Error(StrFormat("Invalid UTF-8 in %s string literal", this->lang_str), end_pos);
  }
  if (tok_id == Id::Char_AsciiControl) {
    throw this->_Error(str1175, end_pos);
  }
  if (tok_id == Id::J8_Newline) {
    this->cur_line_num += 1;
  }
  this->pos = end_pos;
  return Tuple3<int, int, BigStr*>(tok_id, end_pos, nullptr);
}

Tuple3<int, int, BigStr*> LexerDecoder::_DecodeString(int left_id, int str_pos) {
  int tok_id;
  int str_end;
  BigStr* s = nullptr;
  BigStr* part = nullptr;
  BigStr* ch = nullptr;
  BigStr* h = nullptr;
  int i;
  BigStr* h1 = nullptr;
  BigStr* h2 = nullptr;
  int i1;
  int i2;
  int code_point;
  StackRoot _root0(&s);
  StackRoot _root1(&part);
  StackRoot _root2(&ch);
  StackRoot _root3(&h);
  StackRoot _root4(&h1);
  StackRoot _root5(&h2);

  while (true) {
    if ((left_id == Id::Left_DoubleQuote || left_id == Id::Left_JDoubleQuote)) {
      Tuple2<int, int> tup2 = match::MatchJsonStrToken(this->s, str_pos);
      tok_id = tup2.at0();
      str_end = tup2.at1();
    }
    else {
      Tuple2<int, int> tup3 = match::MatchJ8StrToken(this->s, str_pos);
      tok_id = tup3.at0();
      str_end = tup3.at1();
    }
    if (tok_id == Id::Eol_Tok) {
      throw this->_Error(StrFormat("Unexpected EOF while lexing %s string", this->lang_str), str_end);
    }
    if (tok_id == Id::Unknown_Backslash) {
      throw this->_Error(StrFormat("Bad backslash escape in %s string", this->lang_str), str_end);
    }
    if (tok_id == Id::Char_AsciiControl) {
      throw this->_Error(StrFormat("%s strings can't have unescaped ASCII control chars", this->lang_str), str_end);
    }
    if ((tok_id == Id::Right_SingleQuote || tok_id == Id::Right_DoubleQuote)) {
      this->pos = str_end;
      s = this->decoded->getvalue();
      this->decoded->clear();
      return Tuple3<int, int, BigStr*>(Id::J8_String, str_end, s);
    }
    if (tok_id == Id::Lit_Chars) {
      part = this->s->slice(str_pos, str_end);
      if (!pyj8::PartIsUtf8(this->s, str_pos, str_end)) {
        throw this->_Error(StrFormat("Invalid UTF-8 in %s string literal", this->lang_str), str_end);
      }
    }
    else {
      if (tok_id == Id::Char_OneChar) {
        ch = this->s->at((str_pos + 1));
        part = consts::LookupCharC(ch);
      }
      else {
        if (tok_id == Id::Char_UBraced) {
          h = this->s->slice((str_pos + 3), (str_end - 1));
          i = to_int(h, 16);
          if (i > 1114111) {
            throw this->_Error(str1180, str_end);
          }
          if ((55296 <= i and i < 57344)) {
            throw this->_Error(StrFormat("\\u{%s} escape is illegal because it's in the surrogate range", h), str_end);
          }
          part = Utf8Encode(i);
        }
        else {
          if (tok_id == Id::Char_YHex) {
            h = this->s->slice((str_pos + 2), str_end);
            if (left_id != Id::Left_BSingleQuote) {
              throw this->_Error(StrFormat("\\y%s escapes not allowed in u'' strings", h), str_end);
            }
            i = to_int(h, 16);
            part = chr(i);
          }
          else {
            if (tok_id == Id::Char_SurrogatePair) {
              h1 = this->s->slice((str_pos + 2), (str_pos + 6));
              h2 = this->s->slice((str_pos + 8), (str_pos + 12));
              i1 = (to_int(h1, 16) - 55296);
              i2 = (to_int(h2, 16) - 56320);
              code_point = ((65536 + (i1 << 10)) + i2);
              part = Utf8Encode(code_point);
            }
            else {
              if (tok_id == Id::Char_Unicode4) {
                h = this->s->slice((str_pos + 2), str_end);
                i = to_int(h, 16);
                part = Utf8Encode(i);
              }
              else {
                assert(0);  // AssertionError
              }
            }
          }
        }
      }
    }
    this->decoded->write(part);
    str_pos = str_end;
  }
}

_Parser::_Parser(BigStr* s, bool is_j8) {
  this->s = s;
  this->is_j8 = is_j8;
  this->lang_str = is_j8 ? str1183 : str1184;
  this->lexer = Alloc<LexerDecoder>(s, is_j8, this->lang_str);
  this->tok_id = Id::Undefined_Tok;
  this->start_pos = 0;
  this->end_pos = 0;
  this->decoded = str1185;
}

void _Parser::_Next() {
  while (true) {
    this->start_pos = this->end_pos;
    Tuple3<int, int, BigStr*> tup4 = this->lexer->Next();
    this->tok_id = tup4.at0();
    this->end_pos = tup4.at1();
    this->decoded = tup4.at2();
    if ((this->tok_id != Id::Ignored_Space && this->tok_id != Id::Ignored_Newline && this->tok_id != Id::Ignored_Comment)) {
      break;
    }
  }
}

void _Parser::_Eat(int tok_id) {
  if (this->tok_id != tok_id) {
    throw this->_ParseError(StrFormat("Expected %s, got %s", Id_str(tok_id), Id_str(this->tok_id)));
  }
  this->_Next();
}

void _Parser::_NextForLines() {
  this->start_pos = this->end_pos;
  Tuple3<int, int, BigStr*> tup5 = this->lexer->NextForLines();
  this->tok_id = tup5.at0();
  this->end_pos = tup5.at1();
  this->decoded = tup5.at2();
}

error::Decode* _Parser::_ParseError(BigStr* msg) {
  StackRoot _root0(&msg);

  return Alloc<error::Decode>(msg, this->s, this->start_pos, this->end_pos, this->lexer->cur_line_num);
}

Parser::Parser(BigStr* s, bool is_j8) : ::j8::_Parser(s, is_j8) {
}

Tuple2<BigStr*, value_asdl::value_t*> Parser::_ParsePair() {
  BigStr* k = nullptr;
  value_asdl::value_t* v = nullptr;
  StackRoot _root0(&k);
  StackRoot _root1(&v);

  k = this->decoded;
  this->_Eat(Id::J8_String);
  this->_Eat(Id::J8_Colon);
  v = this->_ParseValue();
  return Tuple2<BigStr*, value_asdl::value_t*>(k, v);
}

value_asdl::value_t* Parser::_ParseDict() {
  Dict<BigStr*, value_asdl::value_t*>* d = nullptr;
  BigStr* k = nullptr;
  value_asdl::value_t* v = nullptr;
  StackRoot _root0(&d);
  StackRoot _root1(&k);
  StackRoot _root2(&v);

  d = Alloc<Dict<BigStr*, value_asdl::value_t*>>();
  this->_Next();
  if (this->tok_id == Id::J8_RBrace) {
    this->_Next();
    return Alloc<value::Dict>(d);
  }
  Tuple2<BigStr*, value_asdl::value_t*> tup6 = this->_ParsePair();
  k = tup6.at0();
  v = tup6.at1();
  d->set(k, v);
  while (this->tok_id == Id::J8_Comma) {
    this->_Next();
    Tuple2<BigStr*, value_asdl::value_t*> tup7 = this->_ParsePair();
    k = tup7.at0();
    v = tup7.at1();
    d->set(k, v);
  }
  this->_Eat(Id::J8_RBrace);
  return Alloc<value::Dict>(d);
}

value_asdl::value_t* Parser::_ParseList() {
  List<value_asdl::value_t*>* items = nullptr;
  StackRoot _root0(&items);

  items = Alloc<List<value_asdl::value_t*>>();
  this->_Next();
  if (this->tok_id == Id::J8_RBracket) {
    this->_Next();
    return Alloc<value::List>(items);
  }
  items->append(this->_ParseValue());
  while (this->tok_id == Id::J8_Comma) {
    this->_Next();
    items->append(this->_ParseValue());
  }
  this->_Eat(Id::J8_RBracket);
  return Alloc<value::List>(items);
}

value_asdl::value_t* Parser::_ParseValue() {
  value::Bool* b = nullptr;
  BigStr* part = nullptr;
  value::Str* str_val = nullptr;
  StackRoot _root0(&b);
  StackRoot _root1(&part);
  StackRoot _root2(&str_val);

  if (this->tok_id == Id::J8_LBrace) {
    return this->_ParseDict();
  }
  else {
    if (this->tok_id == Id::J8_LBracket) {
      return this->_ParseList();
    }
    else {
      if (this->tok_id == Id::J8_Null) {
        this->_Next();
        return value::Null;
      }
      else {
        if (this->tok_id == Id::J8_Bool) {
          b = Alloc<value::Bool>(str_equals(this->s->at(this->start_pos), str1187));
          this->_Next();
          return b;
        }
        else {
          if (this->tok_id == Id::J8_Int) {
            part = this->s->slice(this->start_pos, this->end_pos);
            this->_Next();
            return Alloc<value::Int>(mops::FromStr(part));
          }
          else {
            if (this->tok_id == Id::J8_Float) {
              part = this->s->slice(this->start_pos, this->end_pos);
              this->_Next();
              return Alloc<value::Float>(to_float(part));
            }
            else {
              if (this->tok_id == Id::J8_String) {
                str_val = Alloc<value::Str>(this->decoded);
                this->_Next();
                return str_val;
              }
              else {
                if (this->tok_id == Id::Eol_Tok) {
                  throw this->_ParseError(StrFormat("Unexpected EOF while parsing %s", this->lang_str));
                }
                else {
                  throw this->_ParseError(StrFormat("Invalid token while parsing %s: %s", this->lang_str, Id_str(this->tok_id)));
                }
              }
            }
          }
        }
      }
    }
  }
}

value_asdl::value_t* Parser::ParseValue() {
  value_asdl::value_t* obj = nullptr;
  StackRoot _root0(&obj);

  this->_Next();
  obj = this->_ParseValue();
  if (this->tok_id != Id::Eol_Tok) {
    throw this->_ParseError(str1190);
  }
  return obj;
}

Nil8Parser::Nil8Parser(BigStr* s, bool is_j8) : ::j8::_Parser(s, is_j8) {
}

nil8_asdl::nvalue_t* Nil8Parser::_ParseRecord() {
  List<nil8_asdl::nvalue_t*>* items = nullptr;
  StackRoot _root0(&items);

  items = Alloc<List<nil8_asdl::nvalue_t*>>();
  this->_Next();
  if (this->tok_id == Id::J8_RParen) {
    this->_Next();
    return Alloc<nvalue::List>(items);
  }
  while (this->tok_id != Id::J8_RParen) {
    items->append(this->_ParseNil8());
  }
  this->_Eat(Id::J8_RParen);
  return Alloc<nvalue::List>(items);
}

nil8_asdl::nvalue_t* Nil8Parser::_ParseList8() {
  List<nil8_asdl::nvalue_t*>* items = nullptr;
  StackRoot _root0(&items);

  items = Alloc<List<nil8_asdl::nvalue_t*>>();
  this->_Next();
  if (this->tok_id == Id::J8_RBracket) {
    this->_Next();
    return Alloc<nvalue::List>(items);
  }
  while (this->tok_id != Id::J8_RBracket) {
    items->append(this->_ParseNil8());
  }
  this->_Eat(Id::J8_RBracket);
  return Alloc<nvalue::List>(items);
}

nil8_asdl::nvalue_t* Nil8Parser::_ParseNil8() {
  nil8_asdl::nvalue_t* obj = nullptr;
  nvalue::Bool* b = nullptr;
  BigStr* part = nullptr;
  nvalue::Str* str_val = nullptr;
  nvalue::Symbol* op = nullptr;
  nil8_asdl::nvalue_t* operand2 = nullptr;
  nil8_asdl::nvalue_t* infix = nullptr;
  StackRoot _root0(&obj);
  StackRoot _root1(&b);
  StackRoot _root2(&part);
  StackRoot _root3(&str_val);
  StackRoot _root4(&op);
  StackRoot _root5(&operand2);
  StackRoot _root6(&infix);

  if (this->tok_id == Id::J8_LParen) {
    obj = this->_ParseRecord();
  }
  else {
    if (this->tok_id == Id::J8_LBracket) {
      obj = this->_ParseList8();
    }
    else {
      if (this->tok_id == Id::J8_Null) {
        this->_Next();
        obj = nvalue::Null;
      }
      else {
        if (this->tok_id == Id::J8_Bool) {
          b = Alloc<nvalue::Bool>(str_equals(this->s->at(this->start_pos), str1191));
          this->_Next();
          obj = b;
        }
        else {
          if (this->tok_id == Id::J8_Int) {
            part = this->s->slice(this->start_pos, this->end_pos);
            this->_Next();
            obj = Alloc<nvalue::Int>(to_int(part));
          }
          else {
            if (this->tok_id == Id::J8_Float) {
              part = this->s->slice(this->start_pos, this->end_pos);
              this->_Next();
              obj = Alloc<nvalue::Float>(to_float(part));
            }
            else {
              if (this->tok_id == Id::J8_String) {
                str_val = Alloc<nvalue::Str>(this->decoded);
                this->_Next();
                obj = str_val;
              }
              else {
                if ((this->tok_id == Id::J8_Identifier || this->tok_id == Id::J8_Operator || this->tok_id == Id::J8_Colon || this->tok_id == Id::J8_Comma)) {
                  part = this->s->slice(this->start_pos, this->end_pos);
                  this->_Next();
                  obj = Alloc<nvalue::Symbol>(part);
                }
                else {
                  if (this->tok_id == Id::Eol_Tok) {
                    throw this->_ParseError(StrFormat("Unexpected EOF while parsing %s", this->lang_str));
                  }
                  else {
                    throw this->_ParseError(StrFormat("Invalid token while parsing %s: %s", this->lang_str, Id_str(this->tok_id)));
                  }
                }
              }
            }
          }
        }
      }
    }
  }
  if ((this->tok_id == Id::J8_Operator || this->tok_id == Id::J8_Colon || this->tok_id == Id::J8_Comma)) {
    part = this->s->slice(this->start_pos, this->end_pos);
    op = Alloc<nvalue::Symbol>(part);
    this->_Next();
    operand2 = this->_ParseNil8();
    infix = Alloc<nvalue::List>(NewList<nil8_asdl::nvalue_t*>(std::initializer_list<nil8_asdl::nvalue_t*>{op, obj, operand2}));
    return infix;
  }
  return obj;
}

nil8_asdl::nvalue_t* Nil8Parser::ParseNil8() {
  nil8_asdl::nvalue_t* obj = nullptr;
  StackRoot _root0(&obj);

  this->_Next();
  obj = this->_ParseNil8();
  if (this->tok_id != Id::Eol_Tok) {
    throw this->_ParseError(str1194);
  }
  return obj;
}

J8LinesParser::J8LinesParser(BigStr* s) : ::j8::_Parser(s, true) {
}

void J8LinesParser::_Show(BigStr* s) {
  StackRoot _root0(&s);

  mylib::print_stderr(StrFormat("%s tok_id %s %d-%d", s, Id_str(this->tok_id), this->start_pos, this->end_pos));
}

void J8LinesParser::_ParseLine(List<BigStr*>* out) {
  int string_start;
  int prev_id;
  int prev_start;
  int string_end;
  StackRoot _root0(&out);

  if (this->tok_id == Id::WS_Space) {
    this->_NextForLines();
  }
  if ((this->tok_id == Id::J8_Newline || this->tok_id == Id::Eol_Tok)) {
    this->_NextForLines();
    return ;
  }
  if (this->tok_id == Id::J8_String) {
    out->append(this->decoded);
    this->_NextForLines();
    if (this->tok_id == Id::WS_Space) {
      this->_NextForLines();
    }
    if ((this->tok_id != Id::J8_Newline && this->tok_id != Id::Eol_Tok)) {
      throw this->_ParseError(StrFormat("Unexpected text after J8 Line (%s)", Id_str(this->tok_id)));
    }
    this->_NextForLines();
    return ;
  }
  if (this->tok_id == Id::Lit_Chars) {
    string_start = this->start_pos;
    while (true) {
      prev_id = this->tok_id;
      prev_start = this->start_pos;
      this->_NextForLines();
      if ((this->tok_id == Id::J8_Newline || this->tok_id == Id::Eol_Tok)) {
        break;
      }
    }
    if (prev_id == Id::WS_Space) {
      string_end = prev_start;
    }
    else {
      string_end = this->start_pos;
    }
    out->append(this->s->slice(string_start, string_end));
    this->_NextForLines();
    return ;
  }
  assert(0);  // AssertionError
}

List<BigStr*>* J8LinesParser::Parse() {
  List<BigStr*>* lines = nullptr;
  StackRoot _root0(&lines);

  this->_NextForLines();
  lines = Alloc<List<BigStr*>>();
  while (this->tok_id != Id::Eol_Tok) {
    this->_ParseLine(lines);
  }
  if (this->tok_id != Id::Eol_Tok) {
    throw this->_ParseError(str1197);
  }
  return lines;
}

List<BigStr*>* SplitJ8Lines(BigStr* s) {
  j8::J8LinesParser* p = nullptr;
  StackRoot _root0(&s);
  StackRoot _root1(&p);

  p = Alloc<J8LinesParser>(s);
  return p->Parse();
}

}  // define namespace j8

namespace j8_lite {  // define


BigStr* EncodeString(BigStr* s, bool unquoted_ok) {
  StackRoot _root0(&s);

  if ((unquoted_ok and fastfunc::CanOmitQuotes(s))) {
    return s;
  }
  return fastfunc::J8EncodeString(s, 1);
}

BigStr* MaybeShellEncode(BigStr* s) {
  StackRoot _root0(&s);

  if (fastfunc::CanOmitQuotes(s)) {
    return s;
  }
  return fastfunc::ShellEncodeString(s, 0);
}

BigStr* ShellEncode(BigStr* s) {
  StackRoot _root0(&s);

  return fastfunc::ShellEncodeString(s, 0);
}

BigStr* YshEncode(BigStr* s, bool unquoted_ok) {
  StackRoot _root0(&s);

  if ((unquoted_ok and fastfunc::CanOmitQuotes(s))) {
    return s;
  }
  return fastfunc::ShellEncodeString(s, 1);
}

}  // define namespace j8_lite

namespace pretty {  // define

using pretty_asdl::doc;
using pretty_asdl::doc_e;
using pretty_asdl::DocFragment;
using pretty_asdl::Measure;
using pretty_asdl::MeasuredDoc;
using value_asdl::value;
using value_asdl::value_e;
using value_asdl::value_t;
using value_asdl::value_str;
using j8::ValueIdString;
using j8::HeapValueId;
using mylib::BufWriter;

int TryUnicodeWidth(BigStr* s) {
  int width;
  StackRoot _root0(&s);

  try {
    width = libc::wcswidth(s);
  }
  catch (UnicodeError*) {
    width = len(s);
  }
  if (width == -1) {
    return len(s);
  }
  return width;
}

pretty_asdl::Measure* _EmptyMeasure() {
  return Alloc<Measure>(0, -1);
}

pretty_asdl::Measure* _FlattenMeasure(pretty_asdl::Measure* measure) {
  StackRoot _root0(&measure);

  return Alloc<Measure>(measure->flat, -1);
}

pretty_asdl::Measure* _ConcatMeasure(pretty_asdl::Measure* m1, pretty_asdl::Measure* m2) {
  StackRoot _root0(&m1);
  StackRoot _root1(&m2);

  if (m1->nonflat != -1) {
    return Alloc<Measure>((m1->flat + m2->flat), m1->nonflat);
  }
  else {
    if (m2->nonflat != -1) {
      return Alloc<Measure>((m1->flat + m2->flat), (m1->flat + m2->nonflat));
    }
    else {
      return Alloc<Measure>((m1->flat + m2->flat), -1);
    }
  }
}

int _SuffixLen(pretty_asdl::Measure* measure) {
  StackRoot _root0(&measure);

  if (measure->nonflat != -1) {
    return measure->nonflat;
  }
  else {
    return measure->flat;
  }
}

pretty_asdl::MeasuredDoc* _Text(BigStr* string) {
  StackRoot _root0(&string);

  return Alloc<MeasuredDoc>(Alloc<doc::Text>(string), Alloc<Measure>(TryUnicodeWidth(string), -1));
}

pretty_asdl::MeasuredDoc* _Break(BigStr* string) {
  StackRoot _root0(&string);

  return Alloc<MeasuredDoc>(Alloc<doc::Break>(string), Alloc<Measure>(TryUnicodeWidth(string), 0));
}

pretty_asdl::MeasuredDoc* _Indent(int indent, pretty_asdl::MeasuredDoc* mdoc) {
  StackRoot _root0(&mdoc);

  return Alloc<MeasuredDoc>(Alloc<doc::Indent>(indent, mdoc), mdoc->measure);
}

pretty_asdl::MeasuredDoc* _Concat(List<pretty_asdl::MeasuredDoc*>* mdocs) {
  pretty_asdl::Measure* measure = nullptr;
  StackRoot _root0(&mdocs);
  StackRoot _root1(&measure);

  measure = _EmptyMeasure();
  for (ListIter<pretty_asdl::MeasuredDoc*> it(mdocs); !it.Done(); it.Next()) {
    pretty_asdl::MeasuredDoc* mdoc = it.Value();
    StackRoot _for(&mdoc  );
    measure = _ConcatMeasure(measure, mdoc->measure);
  }
  return Alloc<MeasuredDoc>(Alloc<doc::Concat>(mdocs), measure);
}

pretty_asdl::MeasuredDoc* _Group(pretty_asdl::MeasuredDoc* mdoc) {
  StackRoot _root0(&mdoc);

  return Alloc<MeasuredDoc>(Alloc<doc::Group>(mdoc), mdoc->measure);
}

pretty_asdl::MeasuredDoc* _IfFlat(pretty_asdl::MeasuredDoc* flat_mdoc, pretty_asdl::MeasuredDoc* nonflat_mdoc) {
  StackRoot _root0(&flat_mdoc);
  StackRoot _root1(&nonflat_mdoc);

  return Alloc<MeasuredDoc>(Alloc<doc::IfFlat>(flat_mdoc, nonflat_mdoc), Alloc<Measure>(flat_mdoc->measure->flat, nonflat_mdoc->measure->nonflat));
}
int _DEFAULT_MAX_WIDTH = 80;
int _DEFAULT_INDENTATION = 4;
bool _DEFAULT_USE_STYLES = true;
bool _DEFAULT_SHOW_TYPE_PREFIX = true;
int _DEFAULT_MAX_TABULAR_WIDTH = 16;

PrettyPrinter::PrettyPrinter() {
  this->max_width = _DEFAULT_MAX_WIDTH;
  this->indent = _DEFAULT_INDENTATION;
  this->use_styles = _DEFAULT_USE_STYLES;
  this->show_type_prefix = _DEFAULT_SHOW_TYPE_PREFIX;
  this->max_tabular_width = _DEFAULT_MAX_TABULAR_WIDTH;
}

void PrettyPrinter::SetMaxWidth(int max_width) {
  this->max_width = max_width;
}

void PrettyPrinter::SetIndent(int indent) {
  this->indent = indent;
}

void PrettyPrinter::SetUseStyles(bool use_styles) {
  this->use_styles = use_styles;
}

void PrettyPrinter::SetShowTypePrefix(bool show_type_prefix) {
  this->show_type_prefix = show_type_prefix;
}

void PrettyPrinter::SetMaxTabularWidth(int max_tabular_width) {
  this->max_tabular_width = max_tabular_width;
}

void PrettyPrinter::PrintValue(value_asdl::value_t* val, mylib::BufWriter* buf) {
  pretty::_DocConstructor* constructor = nullptr;
  pretty_asdl::MeasuredDoc* document = nullptr;
  StackRoot _root0(&val);
  StackRoot _root1(&buf);
  StackRoot _root2(&constructor);
  StackRoot _root3(&document);

  constructor = Alloc<_DocConstructor>(this->indent, this->use_styles, this->show_type_prefix, this->max_tabular_width);
  document = constructor->Value(val);
  this->_PrintDoc(document, buf);
}

bool PrettyPrinter::_Fits(int prefix_len, doc::Group* group, pretty_asdl::Measure* suffix_measure) {
  pretty_asdl::Measure* measure = nullptr;
  StackRoot _root0(&group);
  StackRoot _root1(&suffix_measure);
  StackRoot _root2(&measure);

  measure = _ConcatMeasure(_FlattenMeasure(group->mdoc->measure), suffix_measure);
  return (prefix_len + _SuffixLen(measure)) <= this->max_width;
}

void PrettyPrinter::_PrintDoc(pretty_asdl::MeasuredDoc* document, mylib::BufWriter* buf) {
  int prefix_len;
  List<pretty_asdl::DocFragment*>* fragments = nullptr;
  pretty_asdl::DocFragment* frag = nullptr;
  doc::Text* text = nullptr;
  BigStr* break_str = nullptr;
  doc::Indent* indented = nullptr;
  doc::Concat* concat = nullptr;
  pretty_asdl::Measure* measure = nullptr;
  doc::Group* group = nullptr;
  bool flat;
  doc::IfFlat* if_flat = nullptr;
  pretty_asdl::MeasuredDoc* subdoc = nullptr;
  StackRoot _root0(&document);
  StackRoot _root1(&buf);
  StackRoot _root2(&fragments);
  StackRoot _root3(&frag);
  StackRoot _root4(&text);
  StackRoot _root5(&break_str);
  StackRoot _root6(&indented);
  StackRoot _root7(&concat);
  StackRoot _root8(&measure);
  StackRoot _root9(&group);
  StackRoot _root10(&if_flat);
  StackRoot _root11(&subdoc);

  prefix_len = 0;
  fragments = NewList<pretty_asdl::DocFragment*>(std::initializer_list<pretty_asdl::DocFragment*>{Alloc<DocFragment>(_Group(document), 0, false, _EmptyMeasure())});
  while (len(fragments) > 0) {
    frag = fragments->pop();
    switch (frag->mdoc->doc->tag()) {
      case doc_e::Text: {
        text = static_cast<doc::Text*>(frag->mdoc->doc);
        buf->write(text->string);
        prefix_len += frag->mdoc->measure->flat;
      }
        break;
      case doc_e::Break: {
        if (frag->is_flat) {
          break_str = static_cast<doc::Break*>(frag->mdoc->doc)->string;
          buf->write(break_str);
          prefix_len += frag->mdoc->measure->flat;
        }
        else {
          buf->write(str1198);
          buf->write_spaces(frag->indent);
          prefix_len = frag->indent;
        }
      }
        break;
      case doc_e::Indent: {
        indented = static_cast<doc::Indent*>(frag->mdoc->doc);
        fragments->append(Alloc<DocFragment>(indented->mdoc, (frag->indent + indented->indent), frag->is_flat, frag->measure));
      }
        break;
      case doc_e::Concat: {
        concat = static_cast<doc::Concat*>(frag->mdoc->doc);
        measure = frag->measure;
        for (ReverseListIter<pretty_asdl::MeasuredDoc*> it(concat->mdocs); !it.Done(); it.Next()) {
          pretty_asdl::MeasuredDoc* mdoc = it.Value();
          StackRoot _for(&mdoc        );
          fragments->append(Alloc<DocFragment>(mdoc, frag->indent, frag->is_flat, measure));
          measure = _ConcatMeasure(mdoc->measure, measure);
        }
      }
        break;
      case doc_e::Group: {
        group = static_cast<doc::Group*>(frag->mdoc->doc);
        flat = this->_Fits(prefix_len, group, frag->measure);
        fragments->append(Alloc<DocFragment>(group->mdoc, frag->indent, flat, frag->measure));
      }
        break;
      case doc_e::IfFlat: {
        if_flat = static_cast<doc::IfFlat*>(frag->mdoc->doc);
        if (frag->is_flat) {
          subdoc = if_flat->flat_mdoc;
        }
        else {
          subdoc = if_flat->nonflat_mdoc;
        }
        fragments->append(Alloc<DocFragment>(subdoc, frag->indent, frag->is_flat, frag->measure));
      }
        break;
    }
  }
}

_DocConstructor::_DocConstructor(int indent, bool use_styles, bool show_type_prefix, int max_tabular_width) {
  this->indent = indent;
  this->use_styles = use_styles;
  this->show_type_prefix = show_type_prefix;
  this->max_tabular_width = max_tabular_width;
  this->visiting = Alloc<Dict<int, bool>>();
  this->number_style = ansi::YELLOW;
  this->null_style = str_concat(ansi::BOLD, ansi::RED);
  this->bool_style = str_concat(ansi::BOLD, ansi::BLUE);
  this->string_style = ansi::GREEN;
  this->cycle_style = str_concat(ansi::BOLD, ansi::MAGENTA);
  this->type_style = ansi::CYAN;
}

pretty_asdl::MeasuredDoc* _DocConstructor::Value(value_asdl::value_t* val) {
  BigStr* ysh_type = nullptr;
  StackRoot _root0(&val);
  StackRoot _root1(&ysh_type);

  this->visiting->clear();
  if (this->show_type_prefix) {
    ysh_type = value_str(val->tag(), false);
    return _Group(_Concat(NewList<pretty_asdl::MeasuredDoc*>(std::initializer_list<pretty_asdl::MeasuredDoc*>{_Text(str_concat(str_concat(str1199, ysh_type), str1200)), _Break(str1201), this->_Value(val)})));
  }
  else {
    return this->_Value(val);
  }
}

pretty_asdl::MeasuredDoc* _DocConstructor::_Styled(BigStr* style, pretty_asdl::MeasuredDoc* mdoc) {
  StackRoot _root0(&style);
  StackRoot _root1(&mdoc);

  if (this->use_styles) {
    return _Concat(NewList<pretty_asdl::MeasuredDoc*>(std::initializer_list<pretty_asdl::MeasuredDoc*>{Alloc<MeasuredDoc>(Alloc<doc::Text>(style), _EmptyMeasure()), mdoc, Alloc<MeasuredDoc>(Alloc<doc::Text>(ansi::RESET), _EmptyMeasure())}));
  }
  else {
    return mdoc;
  }
}

pretty_asdl::MeasuredDoc* _DocConstructor::_Surrounded(BigStr* open, pretty_asdl::MeasuredDoc* mdoc, BigStr* close) {
  StackRoot _root0(&open);
  StackRoot _root1(&mdoc);
  StackRoot _root2(&close);

  return _Group(_Concat(NewList<pretty_asdl::MeasuredDoc*>(std::initializer_list<pretty_asdl::MeasuredDoc*>{_Text(open), _Indent(this->indent, _Concat(NewList<pretty_asdl::MeasuredDoc*>(std::initializer_list<pretty_asdl::MeasuredDoc*>{_Break(str1202), mdoc}))), _Break(str1203), _Text(close)})));
}

pretty_asdl::MeasuredDoc* _DocConstructor::_SurroundedAndPrefixed(BigStr* open, pretty_asdl::MeasuredDoc* prefix, BigStr* sep, pretty_asdl::MeasuredDoc* mdoc, BigStr* close) {
  StackRoot _root0(&open);
  StackRoot _root1(&prefix);
  StackRoot _root2(&sep);
  StackRoot _root3(&mdoc);
  StackRoot _root4(&close);

  return _Group(_Concat(NewList<pretty_asdl::MeasuredDoc*>(std::initializer_list<pretty_asdl::MeasuredDoc*>{_Text(open), prefix, _Indent(this->indent, _Concat(NewList<pretty_asdl::MeasuredDoc*>(std::initializer_list<pretty_asdl::MeasuredDoc*>{_Break(sep), mdoc}))), _Break(str1204), _Text(close)})));
}

pretty_asdl::MeasuredDoc* _DocConstructor::_Join(List<pretty_asdl::MeasuredDoc*>* items, BigStr* sep, BigStr* space) {
  List<pretty_asdl::MeasuredDoc*>* seq = nullptr;
  int i;
  StackRoot _root0(&items);
  StackRoot _root1(&sep);
  StackRoot _root2(&space);
  StackRoot _root3(&seq);

  seq = Alloc<List<pretty_asdl::MeasuredDoc*>>();
  i = 0;
  for (ListIter<pretty_asdl::MeasuredDoc*> it(items); !it.Done(); it.Next(), ++i) {
    pretty_asdl::MeasuredDoc* item = it.Value();
    StackRoot _for(&item  );
    if (i != 0) {
      seq->append(_Text(sep));
      seq->append(_Break(space));
    }
    seq->append(item);
  }
  return _Concat(seq);
}

pretty_asdl::MeasuredDoc* _DocConstructor::_Tabular(List<pretty_asdl::MeasuredDoc*>* items, BigStr* sep) {
  int max_flat_len;
  List<pretty_asdl::MeasuredDoc*>* seq = nullptr;
  int i;
  pretty_asdl::MeasuredDoc* non_tabular = nullptr;
  int sep_width;
  List<pretty_asdl::MeasuredDoc*>* tabular_seq = nullptr;
  int padding;
  pretty_asdl::MeasuredDoc* tabular = nullptr;
  StackRoot _root0(&items);
  StackRoot _root1(&sep);
  StackRoot _root2(&seq);
  StackRoot _root3(&non_tabular);
  StackRoot _root4(&tabular_seq);
  StackRoot _root5(&tabular);

  if (len(items) == 0) {
    return _Text(str1205);
  }
  max_flat_len = 0;
  seq = Alloc<List<pretty_asdl::MeasuredDoc*>>();
  i = 0;
  for (ListIter<pretty_asdl::MeasuredDoc*> it(items); !it.Done(); it.Next(), ++i) {
    pretty_asdl::MeasuredDoc* item = it.Value();
    StackRoot _for(&item  );
    if (i != 0) {
      seq->append(_Text(sep));
      seq->append(_Break(str1206));
    }
    seq->append(item);
    max_flat_len = max(max_flat_len, item->measure->flat);
  }
  non_tabular = _Concat(seq);
  sep_width = TryUnicodeWidth(sep);
  if (((max_flat_len + sep_width) + 1) <= this->max_tabular_width) {
    tabular_seq = Alloc<List<pretty_asdl::MeasuredDoc*>>();
    i = 0;
    for (ListIter<pretty_asdl::MeasuredDoc*> it(items); !it.Done(); it.Next(), ++i) {
      pretty_asdl::MeasuredDoc* item = it.Value();
      StackRoot _for(&item    );
      tabular_seq->append(item);
      if (i != (len(items) - 1)) {
        padding = ((max_flat_len - item->measure->flat) + 1);
        tabular_seq->append(_Text(sep));
        tabular_seq->append(_Group(_Break(str_repeat(str1207, padding))));
      }
    }
    tabular = _Concat(tabular_seq);
    return _Group(_IfFlat(non_tabular, tabular));
  }
  else {
    return non_tabular;
  }
}

pretty_asdl::MeasuredDoc* _DocConstructor::_DictKey(BigStr* s) {
  StackRoot _root0(&s);

  if (match::IsValidVarName(s)) {
    return _Text(s);
  }
  else {
    return _Text(fastfunc::J8EncodeString(s, true));
  }
}

pretty_asdl::MeasuredDoc* _DocConstructor::_StringLiteral(BigStr* s) {
  StackRoot _root0(&s);

  return this->_Styled(this->string_style, _Text(fastfunc::J8EncodeString(s, true)));
}

pretty_asdl::MeasuredDoc* _DocConstructor::_BashStringLiteral(BigStr* s) {
  StackRoot _root0(&s);

  return this->_Styled(this->string_style, _Text(fastfunc::ShellEncodeString(s, 0)));
}

pretty_asdl::MeasuredDoc* _DocConstructor::_YshList(value::List* vlist) {
  List<pretty_asdl::MeasuredDoc*>* mdocs = nullptr;
  StackRoot _root0(&vlist);
  StackRoot _root1(&mdocs);

  if (len(vlist->items) == 0) {
    return _Text(str1208);
  }
  mdocs = Alloc<List<pretty_asdl::MeasuredDoc*>>();
  for (ListIter<value_asdl::value_t*> it(vlist->items); !it.Done(); it.Next()) {
    value_asdl::value_t* item = it.Value();
    mdocs->append(this->_Value(item));
  }
  return this->_Surrounded(str1209, this->_Tabular(mdocs, str1210), str1211);
}

pretty_asdl::MeasuredDoc* _DocConstructor::_YshDict(value::Dict* vdict) {
  List<pretty_asdl::MeasuredDoc*>* mdocs = nullptr;
  StackRoot _root0(&vdict);
  StackRoot _root1(&mdocs);

  if (len(vdict->d) == 0) {
    return _Text(str1212);
  }
  mdocs = Alloc<List<pretty_asdl::MeasuredDoc*>>();
  for (DictIter<BigStr*, value_asdl::value_t*> it(vdict->d); !it.Done(); it.Next()) {
    BigStr* k = it.Key();
    value_asdl::value_t* v = it.Value();
    mdocs->append(_Concat(NewList<pretty_asdl::MeasuredDoc*>(std::initializer_list<pretty_asdl::MeasuredDoc*>{this->_DictKey(k), _Text(str1213), this->_Value(v)})));
  }
  return this->_Surrounded(str1214, this->_Join(mdocs, str1215, str1216), str1217);
}

pretty_asdl::MeasuredDoc* _DocConstructor::_BashArray(value::BashArray* varray) {
  pretty_asdl::MeasuredDoc* type_name = nullptr;
  List<pretty_asdl::MeasuredDoc*>* mdocs = nullptr;
  StackRoot _root0(&varray);
  StackRoot _root1(&type_name);
  StackRoot _root2(&mdocs);

  type_name = this->_Styled(this->type_style, _Text(str1218));
  if (len(varray->strs) == 0) {
    return _Concat(NewList<pretty_asdl::MeasuredDoc*>(std::initializer_list<pretty_asdl::MeasuredDoc*>{_Text(str1219), type_name, _Text(str1220)}));
  }
  mdocs = Alloc<List<pretty_asdl::MeasuredDoc*>>();
  for (ListIter<BigStr*> it(varray->strs); !it.Done(); it.Next()) {
    BigStr* s = it.Value();
    StackRoot _for(&s  );
    if (s == nullptr) {
      mdocs->append(_Text(str1221));
    }
    else {
      mdocs->append(this->_BashStringLiteral(s));
    }
  }
  return this->_SurroundedAndPrefixed(str1222, type_name, str1223, this->_Tabular(mdocs, str1224), str1225);
}

pretty_asdl::MeasuredDoc* _DocConstructor::_BashAssoc(value::BashAssoc* vassoc) {
  pretty_asdl::MeasuredDoc* type_name = nullptr;
  List<pretty_asdl::MeasuredDoc*>* mdocs = nullptr;
  StackRoot _root0(&vassoc);
  StackRoot _root1(&type_name);
  StackRoot _root2(&mdocs);

  type_name = this->_Styled(this->type_style, _Text(str1226));
  if (len(vassoc->d) == 0) {
    return _Concat(NewList<pretty_asdl::MeasuredDoc*>(std::initializer_list<pretty_asdl::MeasuredDoc*>{_Text(str1227), type_name, _Text(str1228)}));
  }
  mdocs = Alloc<List<pretty_asdl::MeasuredDoc*>>();
  for (DictIter<BigStr*, BigStr*> it(vassoc->d); !it.Done(); it.Next()) {
    BigStr* k2 = it.Key();
    BigStr* v2 = it.Value();
    mdocs->append(_Concat(NewList<pretty_asdl::MeasuredDoc*>(std::initializer_list<pretty_asdl::MeasuredDoc*>{_Text(str1229), this->_BashStringLiteral(k2), _Text(str1230), this->_BashStringLiteral(v2)})));
  }
  return this->_SurroundedAndPrefixed(str1231, type_name, str1232, this->_Join(mdocs, str1233, str1234), str1235);
}

pretty_asdl::MeasuredDoc* _DocConstructor::_Value(value_asdl::value_t* val) {
  bool b;
  mops::BigInt i;
  double f;
  BigStr* s = nullptr;
  value::Range* r = nullptr;
  value::List* vlist = nullptr;
  int heap_id;
  pretty_asdl::MeasuredDoc* result = nullptr;
  value::Dict* vdict = nullptr;
  value::BashArray* varray = nullptr;
  value::BashAssoc* vassoc = nullptr;
  BigStr* ysh_type = nullptr;
  BigStr* id_str = nullptr;
  StackRoot _root0(&val);
  StackRoot _root1(&s);
  StackRoot _root2(&r);
  StackRoot _root3(&vlist);
  StackRoot _root4(&result);
  StackRoot _root5(&vdict);
  StackRoot _root6(&varray);
  StackRoot _root7(&vassoc);
  StackRoot _root8(&ysh_type);
  StackRoot _root9(&id_str);

  switch (val->tag()) {
    case value_e::Null: {
      return this->_Styled(this->null_style, _Text(str1236));
    }
      break;
    case value_e::Bool: {
      b = static_cast<value::Bool*>(val)->b;
      return this->_Styled(this->bool_style, _Text(b ? str1237 : str1238));
    }
      break;
    case value_e::Int: {
      i = static_cast<value::Int*>(val)->i;
      return this->_Styled(this->number_style, _Text(mops::ToStr(i)));
    }
      break;
    case value_e::Float: {
      f = static_cast<value::Float*>(val)->f;
      return this->_Styled(this->number_style, _Text(str(f)));
    }
      break;
    case value_e::Str: {
      s = static_cast<value::Str*>(val)->s;
      return this->_StringLiteral(s);
    }
      break;
    case value_e::Range: {
      r = static_cast<value::Range*>(val);
      return this->_Styled(this->number_style, _Concat(NewList<pretty_asdl::MeasuredDoc*>(std::initializer_list<pretty_asdl::MeasuredDoc*>{_Text(str(r->lower)), _Text(str1239), _Text(str(r->upper))})));
    }
      break;
    case value_e::List: {
      vlist = static_cast<value::List*>(val);
      heap_id = HeapValueId(vlist);
      if (this->visiting->get(heap_id, false)) {
        return _Concat(NewList<pretty_asdl::MeasuredDoc*>(std::initializer_list<pretty_asdl::MeasuredDoc*>{_Text(str1240), this->_Styled(this->cycle_style, _Text(str1241)), _Text(str1242)}));
      }
      else {
        this->visiting->set(heap_id, true);
        result = this->_YshList(vlist);
        this->visiting->set(heap_id, false);
        return result;
      }
    }
      break;
    case value_e::Dict: {
      vdict = static_cast<value::Dict*>(val);
      heap_id = HeapValueId(vdict);
      if (this->visiting->get(heap_id, false)) {
        return _Concat(NewList<pretty_asdl::MeasuredDoc*>(std::initializer_list<pretty_asdl::MeasuredDoc*>{_Text(str1243), this->_Styled(this->cycle_style, _Text(str1244)), _Text(str1245)}));
      }
      else {
        this->visiting->set(heap_id, true);
        result = this->_YshDict(vdict);
        this->visiting->set(heap_id, false);
        return result;
      }
    }
      break;
    case value_e::BashArray: {
      varray = static_cast<value::BashArray*>(val);
      return this->_BashArray(varray);
    }
      break;
    case value_e::BashAssoc: {
      vassoc = static_cast<value::BashAssoc*>(val);
      return this->_BashAssoc(vassoc);
    }
      break;
    default: {
      ysh_type = value_str(val->tag(), false);
      id_str = ValueIdString(val);
      return this->_Styled(this->type_style, _Text(str_concat(str_concat(str_concat(str1246, ysh_type), id_str), str1247)));
    }
  }
}

}  // define namespace pretty

namespace args {  // define

using syntax_asdl::loc;
using syntax_asdl::loc_t;
using syntax_asdl::CompoundWord;
using value_asdl::value;
using value_asdl::value_e;
using value_asdl::value_t;
using error::e_usage;
int String = 1;
int Int = 2;
int Float = 3;
int Bool = 4;

_Attributes::_Attributes(Dict<BigStr*, value_asdl::value_t*>* defaults) {
  this->attrs = Alloc<Dict<BigStr*, value_asdl::value_t*>>();
  this->opt_changes = Alloc<List<Tuple2<BigStr*, bool>*>>();
  this->shopt_changes = Alloc<List<Tuple2<BigStr*, bool>*>>();
  this->show_options = false;
  this->actions = Alloc<List<BigStr*>>();
  this->saw_double_dash = false;
  for (DictIter<BigStr*, value_asdl::value_t*> it(defaults); !it.Done(); it.Next()) {
    BigStr* name = it.Key();
    value_asdl::value_t* v = it.Value();
    this->Set(name, v);
  }
}

void _Attributes::SetTrue(BigStr* name) {
  StackRoot _root0(&name);

  this->Set(name, Alloc<value::Bool>(true));
}

void _Attributes::Set(BigStr* name, value_asdl::value_t* val) {
  StackRoot _root0(&name);
  StackRoot _root1(&val);

  name = name->replace(str1248, str1249);
  this->attrs->set(name, val);
}

Reader::Reader(List<BigStr*>* argv, List<syntax_asdl::CompoundWord*>* locs) {
  this->argv = argv;
  this->locs = locs;
  this->n = len(argv);
  this->i = 0;
}

void Reader::Next() {
  this->i += 1;
}

BigStr* Reader::Peek() {
  if (this->i >= this->n) {
    return nullptr;
  }
  else {
    return this->argv->at(this->i);
  }
}

Tuple2<BigStr*, syntax_asdl::loc_t*> Reader::Peek2() {
  if (this->i >= this->n) {
    return Tuple2<BigStr*, syntax_asdl::loc_t*>(nullptr, loc::Missing);
  }
  else {
    return Tuple2<BigStr*, syntax_asdl::loc_t*>(this->argv->at(this->i), this->locs->at(this->i));
  }
}

BigStr* Reader::ReadRequired(BigStr* error_msg) {
  BigStr* arg = nullptr;
  StackRoot _root0(&error_msg);
  StackRoot _root1(&arg);

  arg = this->Peek();
  if (arg == nullptr) {
    e_usage(error_msg, this->_FirstLocation());
  }
  this->Next();
  return arg;
}

Tuple2<BigStr*, syntax_asdl::loc_t*> Reader::ReadRequired2(BigStr* error_msg) {
  BigStr* arg = nullptr;
  syntax_asdl::CompoundWord* location = nullptr;
  StackRoot _root0(&error_msg);
  StackRoot _root1(&arg);
  StackRoot _root2(&location);

  arg = this->Peek();
  if (arg == nullptr) {
    e_usage(error_msg, this->_FirstLocation());
  }
  location = this->locs->at(this->i);
  this->Next();
  return Tuple2<BigStr*, syntax_asdl::loc_t*>(arg, location);
}

List<BigStr*>* Reader::Rest() {
  return this->argv->slice(this->i);
}

Tuple2<List<BigStr*>*, List<syntax_asdl::CompoundWord*>*> Reader::Rest2() {
  return Tuple2<List<BigStr*>*, List<syntax_asdl::CompoundWord*>*>(this->argv->slice(this->i), this->locs->slice(this->i));
}

bool Reader::AtEnd() {
  return this->i >= this->n;
}

void Reader::Done() {
  if (!this->AtEnd()) {
    e_usage(str1252, this->Location());
  }
}

syntax_asdl::loc_t* Reader::_FirstLocation() {
  if ((this->locs != nullptr and this->locs->at(0) != nullptr)) {
    return this->locs->at(0);
  }
  else {
    return loc::Missing;
  }
}

syntax_asdl::loc_t* Reader::Location() {
  int i;
  if (this->locs != nullptr) {
    if (this->i == this->n) {
      i = (this->n - 1);
    }
    else {
      i = this->i;
    }
    if (this->locs->at(i) != nullptr) {
      return this->locs->at(i);
    }
    else {
      return loc::Missing;
    }
  }
  else {
    return loc::Missing;
  }
}

_Action::_Action() {
  ;  // pass
}

bool _Action::OnMatch(BigStr* attached_arg, args::Reader* arg_r, args::_Attributes* out) {
  StackRoot _root0(&attached_arg);
  StackRoot _root1(&arg_r);
  StackRoot _root2(&out);

  FAIL(kNotImplemented);  // Python NotImplementedError
}

_ArgAction::_ArgAction(BigStr* name, bool quit_parsing_flags, List<BigStr*>* valid) {
  this->name = name;
  this->quit_parsing_flags = quit_parsing_flags;
  this->valid = valid;
}

value_asdl::value_t* _ArgAction::_Value(BigStr* arg, syntax_asdl::loc_t* location) {
  StackRoot _root0(&arg);
  StackRoot _root1(&location);

  FAIL(kNotImplemented);  // Python NotImplementedError
}

bool _ArgAction::OnMatch(BigStr* attached_arg, args::Reader* arg_r, args::_Attributes* out) {
  BigStr* arg = nullptr;
  value_asdl::value_t* val = nullptr;
  StackRoot _root0(&attached_arg);
  StackRoot _root1(&arg_r);
  StackRoot _root2(&out);
  StackRoot _root3(&arg);
  StackRoot _root4(&val);

  if (attached_arg != nullptr) {
    arg = attached_arg;
  }
  else {
    arg_r->Next();
    arg = arg_r->Peek();
    if (arg == nullptr) {
      e_usage(StrFormat("expected argument to %r", str_concat(str1254, this->name)), arg_r->Location());
    }
  }
  val = this->_Value(arg, arg_r->Location());
  out->Set(this->name, val);
  return this->quit_parsing_flags;
}

SetToInt::SetToInt(BigStr* name) : ::args::_ArgAction(name, false, nullptr) {
}

value_asdl::value_t* SetToInt::_Value(BigStr* arg, syntax_asdl::loc_t* location) {
  mops::BigInt i;
  StackRoot _root0(&arg);
  StackRoot _root1(&location);

  try {
    i = mops::FromStr(arg);
  }
  catch (ValueError*) {
    e_usage(StrFormat("expected integer after %s, got %r", str_concat(str1256, this->name), arg), location);
  }
  if (mops::Greater(mops::BigInt(0), i)) {
    e_usage(StrFormat("got invalid integer for %s: %s", str_concat(str1258, this->name), arg), location);
  }
  return Alloc<value::Int>(i);
}

SetToFloat::SetToFloat(BigStr* name) : ::args::_ArgAction(name, false, nullptr) {
}

value_asdl::value_t* SetToFloat::_Value(BigStr* arg, syntax_asdl::loc_t* location) {
  double f;
  StackRoot _root0(&arg);
  StackRoot _root1(&location);

  try {
    f = to_float(arg);
  }
  catch (ValueError*) {
    e_usage(StrFormat("expected number after %r, got %r", str_concat(str1260, this->name), arg), location);
  }
  if (f < 0) {
    e_usage(StrFormat("got invalid float for %s: %s", str_concat(str1262, this->name), arg), location);
  }
  return Alloc<value::Float>(f);
}

SetToString::SetToString(BigStr* name, bool quit_parsing_flags, List<BigStr*>* valid) : ::args::_ArgAction(name, quit_parsing_flags, valid) {
}

value_asdl::value_t* SetToString::_Value(BigStr* arg, syntax_asdl::loc_t* location) {
  StackRoot _root0(&arg);
  StackRoot _root1(&location);

  if ((this->valid != nullptr and !list_contains(this->valid, arg))) {
    e_usage(StrFormat("got invalid argument %r to %r, expected one of: %s", arg, str_concat(str1264, this->name), str1265->join(this->valid)), location);
  }
  return Alloc<value::Str>(arg);
}

SetAttachedBool::SetAttachedBool(BigStr* name) {
  this->name = name;
}

bool SetAttachedBool::OnMatch(BigStr* attached_arg, args::Reader* arg_r, args::_Attributes* out) {
  bool b;
  StackRoot _root0(&attached_arg);
  StackRoot _root1(&arg_r);
  StackRoot _root2(&out);

  if (attached_arg != nullptr) {
    if ((str_equals(attached_arg, str1266) || str_equals(attached_arg, str1267) || str_equals(attached_arg, str1268) || str_equals(attached_arg, str1269))) {
      b = false;
    }
    else {
      if ((str_equals(attached_arg, str1270) || str_equals(attached_arg, str1271) || str_equals(attached_arg, str1272) || str_equals(attached_arg, str1273))) {
        b = true;
      }
      else {
        e_usage(StrFormat("got invalid argument to boolean flag: %r", attached_arg), loc::Missing);
      }
    }
  }
  else {
    b = true;
  }
  out->Set(this->name, Alloc<value::Bool>(b));
  return false;
}

SetToTrue::SetToTrue(BigStr* name) {
  this->name = name;
}

bool SetToTrue::OnMatch(BigStr* attached_arg, args::Reader* arg_r, args::_Attributes* out) {
  StackRoot _root0(&attached_arg);
  StackRoot _root1(&arg_r);
  StackRoot _root2(&out);

  out->SetTrue(this->name);
  return false;
}

SetOption::SetOption(BigStr* name) {
  this->name = name;
}

bool SetOption::OnMatch(BigStr* attached_arg, args::Reader* arg_r, args::_Attributes* out) {
  bool b;
  StackRoot _root0(&attached_arg);
  StackRoot _root1(&arg_r);
  StackRoot _root2(&out);

  b = maybe_str_equals(attached_arg, str1275);
  out->opt_changes->append((Alloc<Tuple2<BigStr*, bool>>(this->name, b)));
  return false;
}

SetNamedOption::SetNamedOption(bool shopt) {
  this->names = Alloc<List<BigStr*>>();
  this->shopt = shopt;
}

void SetNamedOption::ArgName(BigStr* name) {
  StackRoot _root0(&name);

  this->names->append(name);
}

bool SetNamedOption::OnMatch(BigStr* attached_arg, args::Reader* arg_r, args::_Attributes* out) {
  bool b;
  BigStr* arg = nullptr;
  BigStr* attr_name = nullptr;
  List<Tuple2<BigStr*, bool>*>* changes = nullptr;
  StackRoot _root0(&attached_arg);
  StackRoot _root1(&arg_r);
  StackRoot _root2(&out);
  StackRoot _root3(&arg);
  StackRoot _root4(&attr_name);
  StackRoot _root5(&changes);

  b = maybe_str_equals(attached_arg, str1276);
  arg_r->Next();
  arg = arg_r->Peek();
  if (arg == nullptr) {
    out->show_options = true;
    return true;
  }
  attr_name = arg;
  if ((len(this->names) and !list_contains(this->names, attr_name))) {
    e_usage(StrFormat("Invalid option %r", arg), loc::Missing);
  }
  changes = this->shopt ? out->shopt_changes : out->opt_changes;
  changes->append((Alloc<Tuple2<BigStr*, bool>>(attr_name, b)));
  return false;
}

SetAction::SetAction(BigStr* name) {
  this->name = name;
}

bool SetAction::OnMatch(BigStr* attached_arg, args::Reader* arg_r, args::_Attributes* out) {
  StackRoot _root0(&attached_arg);
  StackRoot _root1(&arg_r);
  StackRoot _root2(&out);

  out->actions->append(this->name);
  return false;
}

SetNamedAction::SetNamedAction() {
  this->names = Alloc<List<BigStr*>>();
}

void SetNamedAction::ArgName(BigStr* name) {
  StackRoot _root0(&name);

  this->names->append(name);
}

bool SetNamedAction::OnMatch(BigStr* attached_arg, args::Reader* arg_r, args::_Attributes* out) {
  BigStr* arg = nullptr;
  BigStr* attr_name = nullptr;
  StackRoot _root0(&attached_arg);
  StackRoot _root1(&arg_r);
  StackRoot _root2(&out);
  StackRoot _root3(&arg);
  StackRoot _root4(&attr_name);

  arg_r->Next();
  arg = arg_r->Peek();
  if (arg == nullptr) {
    e_usage(str1278, loc::Missing);
  }
  attr_name = arg;
  if ((len(this->names) and !list_contains(this->names, attr_name))) {
    e_usage(StrFormat("Invalid action name %r", arg), loc::Missing);
  }
  out->actions->append(attr_name);
  return false;
}

args::_Attributes* Parse(flag_spec::_FlagSpec* spec, args::Reader* arg_r) {
  args::_Attributes* out = nullptr;
  BigStr* arg = nullptr;
  int pos;
  BigStr* suffix = nullptr;
  BigStr* flag_name = nullptr;
  args::_Action* action = nullptr;
  int n;
  BigStr* ch = nullptr;
  BigStr* attached_arg = nullptr;
  StackRoot _root0(&spec);
  StackRoot _root1(&arg_r);
  StackRoot _root2(&out);
  StackRoot _root3(&arg);
  StackRoot _root4(&suffix);
  StackRoot _root5(&flag_name);
  StackRoot _root6(&action);
  StackRoot _root7(&ch);
  StackRoot _root8(&attached_arg);

  out = Alloc<_Attributes>(spec->defaults);
  while (!arg_r->AtEnd()) {
    arg = arg_r->Peek();
    if (maybe_str_equals(arg, str1280)) {
      out->saw_double_dash = true;
      arg_r->Next();
      break;
    }
    if ((len(spec->actions_long) and arg->startswith(str1281))) {
      pos = arg->find(str1282, 2);
      if (pos == -1) {
        suffix = nullptr;
        flag_name = arg->slice(2);
      }
      else {
        suffix = arg->slice((pos + 1));
        flag_name = arg->slice(2, pos);
      }
      action = spec->actions_long->get(flag_name);
      if (action == nullptr) {
        e_usage(StrFormat("got invalid flag %r", arg), arg_r->Location());
      }
      action->OnMatch(suffix, arg_r, out);
      arg_r->Next();
      continue;
    }
    else {
      if ((arg->startswith(str1284) and len(arg) > 1)) {
        n = len(arg);
        for (int i = 1; i < n; ++i) {
          ch = arg->at(i);
          if (str_equals(ch, str1285)) {
            ch = str1286;
          }
          if (list_contains(spec->plus_flags, ch)) {
            out->Set(ch, Alloc<value::Str>(str1287));
            continue;
          }
          if (list_contains(spec->arity0, ch)) {
            out->SetTrue(ch);
            continue;
          }
          if (dict_contains(spec->arity1, ch)) {
            action = spec->arity1->at(ch);
            attached_arg = i < (n - 1) ? arg->slice((i + 1)) : nullptr;
            action->OnMatch(attached_arg, arg_r, out);
            break;
          }
          e_usage(StrFormat("doesn't accept flag %s", str_concat(str1289, ch)), arg_r->Location());
        }
        arg_r->Next();
      }
      else {
        if ((len(spec->plus_flags) and (arg->startswith(str1290) and len(arg) > 1))) {
          n = len(arg);
          for (int i = 1; i < n; ++i) {
            ch = arg->at(i);
            if (list_contains(spec->plus_flags, ch)) {
              out->Set(ch, Alloc<value::Str>(str1291));
              continue;
            }
            e_usage(StrFormat("doesn't accept option %s", str_concat(str1293, ch)), arg_r->Location());
          }
          arg_r->Next();
        }
        else {
          break;
        }
      }
    }
  }
  return out;
}

args::_Attributes* ParseLikeEcho(flag_spec::_FlagSpec* spec, args::Reader* arg_r) {
  args::_Attributes* out = nullptr;
  BigStr* arg = nullptr;
  BigStr* chars = nullptr;
  bool done;
  StackRoot _root0(&spec);
  StackRoot _root1(&arg_r);
  StackRoot _root2(&out);
  StackRoot _root3(&arg);
  StackRoot _root4(&chars);

  out = Alloc<_Attributes>(spec->defaults);
  while (!arg_r->AtEnd()) {
    arg = arg_r->Peek();
    chars = arg->slice(1);
    if ((arg->startswith(str1294) and len(chars))) {
      done = false;
      for (StrIter it(chars); !it.Done(); it.Next()) {
        BigStr* c = it.Value();
        StackRoot _for(&c      );
        if (!list_contains(spec->arity0, c)) {
          done = true;
          break;
        }
      }
      if (done) {
        break;
      }
      for (StrIter it(chars); !it.Done(); it.Next()) {
        BigStr* ch = it.Value();
        StackRoot _for(&ch      );
        out->SetTrue(ch);
      }
    }
    else {
      break;
    }
    arg_r->Next();
  }
  return out;
}

args::_Attributes* ParseMore(flag_spec::_FlagSpecAndMore* spec, args::Reader* arg_r) {
  args::_Attributes* out = nullptr;
  bool quit;
  BigStr* arg = nullptr;
  args::_Action* action = nullptr;
  BigStr* char0 = nullptr;
  BigStr* attached_arg = nullptr;
  StackRoot _root0(&spec);
  StackRoot _root1(&arg_r);
  StackRoot _root2(&out);
  StackRoot _root3(&arg);
  StackRoot _root4(&action);
  StackRoot _root5(&char0);
  StackRoot _root6(&attached_arg);

  out = Alloc<_Attributes>(spec->defaults);
  quit = false;
  while (!arg_r->AtEnd()) {
    arg = arg_r->Peek();
    if (maybe_str_equals(arg, str1295)) {
      out->saw_double_dash = true;
      arg_r->Next();
      break;
    }
    if (arg->startswith(str1296)) {
      action = spec->actions_long->get(arg->slice(2));
      if (action == nullptr) {
        e_usage(StrFormat("got invalid flag %r", arg), arg_r->Location());
      }
      action->OnMatch(nullptr, arg_r, out);
      arg_r->Next();
      continue;
    }
    if (((arg->startswith(str1298) or arg->startswith(str1299)) and len(arg) > 1)) {
      char0 = arg->at(0);
      for (StrIter it(arg->slice(1)); !it.Done(); it.Next()) {
        BigStr* ch = it.Value();
        StackRoot _for(&ch      );
        action = spec->actions_short->get(ch);
        if (action == nullptr) {
          e_usage(StrFormat("got invalid flag %r", str_concat(str1301, ch)), arg_r->Location());
        }
        attached_arg = list_contains(spec->plus_flags, ch) ? char0 : nullptr;
        quit = action->OnMatch(attached_arg, arg_r, out);
      }
      arg_r->Next();
      if (quit) {
        break;
      }
      else {
        continue;
      }
    }
    break;
  }
  return out;
}

}  // define namespace args

namespace flag_util {  // define

using runtime_asdl::cmd_value;
using syntax_asdl::ArgList;
using error::e_usage;

void _DoesNotAccept(syntax_asdl::ArgList* arg_list) {
  StackRoot _root0(&arg_list);

  if (arg_list != nullptr) {
    e_usage(str1302, arg_list->left);
  }
}

Tuple2<args::_Attributes*, args::Reader*> ParseCmdVal(BigStr* spec_name, cmd_value::Argv* cmd_val, bool accept_typed_args) {
  args::Reader* arg_r = nullptr;
  flag_spec::_FlagSpec* spec = nullptr;
  StackRoot _root0(&spec_name);
  StackRoot _root1(&cmd_val);
  StackRoot _root2(&arg_r);
  StackRoot _root3(&spec);

  if (!accept_typed_args) {
    _DoesNotAccept(cmd_val->typed_args);
  }
  arg_r = Alloc<args::Reader>(cmd_val->argv, cmd_val->arg_locs);
  arg_r->Next();
  spec = LookupFlagSpec(spec_name);
  return Tuple2<args::_Attributes*, args::Reader*>(args::Parse(spec, arg_r), arg_r);
}

Tuple2<args::_Attributes*, args::Reader*> ParseLikeEcho(BigStr* spec_name, cmd_value::Argv* cmd_val) {
  args::Reader* arg_r = nullptr;
  flag_spec::_FlagSpec* spec = nullptr;
  StackRoot _root0(&spec_name);
  StackRoot _root1(&cmd_val);
  StackRoot _root2(&arg_r);
  StackRoot _root3(&spec);

  _DoesNotAccept(cmd_val->typed_args);
  arg_r = Alloc<args::Reader>(cmd_val->argv, cmd_val->arg_locs);
  arg_r->Next();
  spec = LookupFlagSpec(spec_name);
  return Tuple2<args::_Attributes*, args::Reader*>(args::ParseLikeEcho(spec, arg_r), arg_r);
}

args::_Attributes* Parse(BigStr* spec_name, args::Reader* arg_r) {
  flag_spec::_FlagSpec* spec = nullptr;
  StackRoot _root0(&spec_name);
  StackRoot _root1(&arg_r);
  StackRoot _root2(&spec);

  spec = LookupFlagSpec(spec_name);
  return args::Parse(spec, arg_r);
}

args::_Attributes* ParseMore(BigStr* spec_name, args::Reader* arg_r) {
  flag_spec::_FlagSpecAndMore* spec = nullptr;
  StackRoot _root0(&spec_name);
  StackRoot _root1(&arg_r);
  StackRoot _root2(&spec);

  spec = LookupFlagSpec2(spec_name);
  return args::ParseMore(spec, arg_r);
}

}  // define namespace flag_util

namespace lexer {  // define

using syntax_asdl::Token;
using syntax_asdl::SourceLine;
using types_asdl::lex_mode_t;
using types_asdl::lex_mode_e;
using id_kind_asdl::Id_t;
using id_kind_asdl::Id;
using id_kind_asdl::Id_str;

bool IsPlusEquals(syntax_asdl::Token* tok) {
  int i;
  StackRoot _root0(&tok);

  i = ((tok->col + tok->length) - 2);
  return tok->line->content->find(str1303, i, (i + 1)) != -1;
}

bool TokenContains(syntax_asdl::Token* tok, BigStr* substr) {
  StackRoot _root0(&tok);
  StackRoot _root1(&substr);

  return tok->line->content->find(substr, tok->col, (tok->col + tok->length)) != -1;
}

bool TokenEquals(syntax_asdl::Token* tok, BigStr* s) {
  StackRoot _root0(&tok);
  StackRoot _root1(&s);

  if (len(s) != tok->length) {
    return false;
  }
  return TokenContains(tok, s);
}

bool TokenStartsWith(syntax_asdl::Token* tok, BigStr* s) {
  StackRoot _root0(&tok);
  StackRoot _root1(&s);

  return tok->line->content->find(s, tok->col, (tok->col + len(s))) != -1;
}

bool TokenEndsWith(syntax_asdl::Token* tok, BigStr* s) {
  int end;
  StackRoot _root0(&tok);
  StackRoot _root1(&s);

  end = (tok->col + tok->length);
  return tok->line->content->find(s, (end - len(s)), end) != -1;
}

BigStr* TokenVal(syntax_asdl::Token* tok) {
  StackRoot _root0(&tok);

  return tok->line->content->slice(tok->col, (tok->col + tok->length));
}

BigStr* TokenSliceLeft(syntax_asdl::Token* tok, int left_index) {
  int start;
  StackRoot _root0(&tok);

  start = (tok->col + left_index);
  return tok->line->content->slice(start, (tok->col + tok->length));
}

BigStr* TokenSliceRight(syntax_asdl::Token* tok, int right_index) {
  int end;
  StackRoot _root0(&tok);

  end = ((tok->col + tok->length) + right_index);
  return tok->line->content->slice(tok->col, end);
}

BigStr* TokenSlice(syntax_asdl::Token* tok, int left, int right) {
  int start;
  int end;
  StackRoot _root0(&tok);

  start = (tok->col + left);
  end = ((tok->col + tok->length) + right);
  return tok->line->content->slice(start, end);
}

BigStr* LazyStr(syntax_asdl::Token* tok) {
  StackRoot _root0(&tok);

  if (tok->tval == nullptr) {
    if ((tok->id == Id::VSub_DollarName || tok->id == Id::VSub_Number)) {
      tok->tval = TokenSliceLeft(tok, 1);
    }
    else {
      tok->tval = TokenVal(tok);
    }
  }
  return tok->tval;
}

syntax_asdl::Token* DummyToken(int id_, BigStr* val) {
  int col;
  int length;
  StackRoot _root0(&val);

  col = -1;
  length = -1;
  return Alloc<Token>(id_, length, col, nullptr, val);
}

LineLexer::LineLexer(alloc::Arena* arena) {
  this->arena = arena;
  this->replace_last_token = false;
  this->eol_tok = DummyToken(Id::Eol_Tok, str1304);
  this->Reset(nullptr, 0);
}

void LineLexer::Reset(syntax_asdl::SourceLine* src_line, int line_pos) {
  StackRoot _root0(&src_line);

  this->src_line = src_line;
  this->line_pos = line_pos;
}

bool LineLexer::MaybeUnreadOne() {
  if (this->line_pos == 0) {
    return false;
  }
  else {
    this->line_pos -= 1;
    this->replace_last_token = true;
    return true;
  }
}

syntax_asdl::Token* LineLexer::GetEofToken(int id_) {
  syntax_asdl::SourceLine* src_line = nullptr;
  StackRoot _root0(&src_line);

  if (this->src_line == nullptr) {
    src_line = this->arena->AddLine(str1306, 0);
  }
  else {
    src_line = this->src_line;
  }
  return this->arena->NewToken(id_, this->line_pos, 0, src_line);
}

int LineLexer::LookAheadOne(types_asdl::lex_mode_t lex_mode) {
  int pos;
  BigStr* line_str = nullptr;
  int n;
  int tok_type;
  StackRoot _root0(&line_str);

  pos = this->line_pos;
  line_str = this->src_line->content;
  n = len(line_str);
  if (pos == n) {
    return Id::Unknown_Tok;
  }
  else {
    Tuple2<int, int> tup0 = match::OneToken(lex_mode, line_str, pos);
    tok_type = tup0.at0();
    return tok_type;
  }
}

void LineLexer::AssertAtEndOfLine() {
}

int LineLexer::LookPastSpace(types_asdl::lex_mode_t lex_mode) {
  int pos;
  BigStr* line_str = nullptr;
  int n;
  int tok_type;
  int end_pos;
  StackRoot _root0(&line_str);

  pos = this->line_pos;
  line_str = this->src_line->content;
  n = len(line_str);
  while (true) {
    if (pos == n) {
      return Id::Unknown_Tok;
    }
    Tuple2<int, int> tup1 = match::OneToken(lex_mode, line_str, pos);
    tok_type = tup1.at0();
    end_pos = tup1.at1();
    if ((tok_type != Id::WS_Space and tok_type != Id::Ignored_Space)) {
      break;
    }
    pos = end_pos;
  }
  return tok_type;
}

bool LineLexer::LookAheadFuncParens(int unread) {
  int pos;
  int tok_type;
  pos = (this->line_pos - unread);
  Tuple2<int, int> tup2 = match::OneToken(lex_mode_e::FuncParens, this->src_line->content, pos);
  tok_type = tup2.at0();
  return tok_type == Id::LookAhead_FuncParens;
}

BigStr* LineLexer::ByteLookAhead() {
  int pos;
  pos = this->line_pos;
  if (pos == len(this->src_line->content)) {
    return str1307;
  }
  else {
    return this->src_line->content->at(pos);
  }
}

int LineLexer::ByteLookBack() {
  int pos;
  pos = (this->line_pos - 2);
  if (pos < 0) {
    return -1;
  }
  else {
    return ord(this->src_line->content->at(pos));
  }
}

syntax_asdl::Token* LineLexer::Read(types_asdl::lex_mode_t lex_mode) {
  BigStr* line_str = nullptr;
  int line_pos;
  int tok_type;
  int end_pos;
  int tok_len;
  syntax_asdl::Token* t = nullptr;
  StackRoot _root0(&line_str);
  StackRoot _root1(&t);

  if (this->src_line) {
    line_str = this->src_line->content;
  }
  else {
    line_str = str1308;
  }
  line_pos = this->line_pos;
  Tuple2<int, int> tup3 = match::OneToken(lex_mode, line_str, line_pos);
  tok_type = tup3.at0();
  end_pos = tup3.at1();
  if (tok_type == Id::Eol_Tok) {
    return this->eol_tok;
  }
  if (this->replace_last_token) {
    this->arena->UnreadOne();
    this->replace_last_token = false;
  }
  tok_len = (end_pos - line_pos);
  t = this->arena->NewToken(tok_type, line_pos, tok_len, this->src_line);
  this->line_pos = end_pos;
  return t;
}

Lexer::Lexer(lexer::LineLexer* line_lexer, reader::_Reader* line_reader) {
  this->line_lexer = line_lexer;
  this->line_reader = line_reader;
  this->line_id = -1;
  this->translation_stack = Alloc<List<Tuple2<int, int>*>>();
  this->emit_comp_dummy = false;
}

void Lexer::ResetInputObjects() {
  this->line_lexer->Reset(nullptr, 0);
}

bool Lexer::MaybeUnreadOne() {
  return this->line_lexer->MaybeUnreadOne();
}

int Lexer::LookAheadOne(types_asdl::lex_mode_t lex_mode) {
  return this->line_lexer->LookAheadOne(lex_mode);
}

int Lexer::LookPastSpace(types_asdl::lex_mode_t lex_mode) {
  return this->line_lexer->LookPastSpace(lex_mode);
}

bool Lexer::LookAheadFuncParens(int unread) {
  return this->line_lexer->LookAheadFuncParens(unread);
}

BigStr* Lexer::ByteLookAhead() {
  return this->line_lexer->ByteLookAhead();
}

int Lexer::ByteLookBack() {
  return this->line_lexer->ByteLookBack();
}

void Lexer::EmitCompDummy() {
  this->emit_comp_dummy = true;
}

void Lexer::PushHint(int old_id, int new_id) {
  this->translation_stack->append((Alloc<Tuple2<int, int>>(old_id, new_id)));
}

void Lexer::MoveToNextLine() {
  syntax_asdl::SourceLine* src_line = nullptr;
  int line_pos;
  StackRoot _root0(&src_line);

  this->line_lexer->AssertAtEndOfLine();
  Tuple2<syntax_asdl::SourceLine*, int> tup4 = this->line_reader->GetLine();
  src_line = tup4.at0();
  line_pos = tup4.at1();
  this->line_lexer->Reset(src_line, line_pos);
}

syntax_asdl::Token* Lexer::_Read(types_asdl::lex_mode_t lex_mode) {
  syntax_asdl::Token* t = nullptr;
  syntax_asdl::SourceLine* src_line = nullptr;
  int line_pos;
  int id_;
  int old_id;
  int new_id;
  StackRoot _root0(&t);
  StackRoot _root1(&src_line);

  t = this->line_lexer->Read(lex_mode);
  if (t->id == Id::Eol_Tok) {
    Tuple2<syntax_asdl::SourceLine*, int> tup5 = this->line_reader->GetLine();
    src_line = tup5.at0();
    line_pos = tup5.at1();
    if (src_line == nullptr) {
      if (this->emit_comp_dummy) {
        id_ = Id::Lit_CompDummy;
        this->emit_comp_dummy = false;
      }
      else {
        id_ = Id::Eof_Real;
      }
      return this->line_lexer->GetEofToken(id_);
    }
    this->line_lexer->Reset(src_line, line_pos);
    t = this->line_lexer->Read(lex_mode);
  }
  if (len(this->translation_stack)) {
    Tuple2<int, int>* tup6 = this->translation_stack->at(-1);
    old_id = tup6->at0();
    new_id = tup6->at1();
    if (t->id == old_id) {
      this->translation_stack->pop();
      t->id = new_id;
    }
  }
  return t;
}

syntax_asdl::Token* Lexer::Read(types_asdl::lex_mode_t lex_mode) {
  syntax_asdl::Token* t = nullptr;
  StackRoot _root0(&t);

  while (true) {
    t = this->_Read(lex_mode);
    if (t->id != Id::Ignored_LineCont) {
      break;
    }
  }
  return t;
}

}  // define namespace lexer

namespace location {  // define

using syntax_asdl::expr;
using syntax_asdl::expr_t;
using syntax_asdl::expr_e;
using syntax_asdl::loc;
using syntax_asdl::loc_t;
using syntax_asdl::loc_e;
using syntax_asdl::command;
using syntax_asdl::command_e;
using syntax_asdl::command_t;
using syntax_asdl::sh_lhs;
using syntax_asdl::sh_lhs_e;
using syntax_asdl::sh_lhs_t;
using syntax_asdl::word;
using syntax_asdl::word_e;
using syntax_asdl::word_t;
using syntax_asdl::word_part;
using syntax_asdl::word_part_e;
using syntax_asdl::word_part_t;
using syntax_asdl::CompoundWord;
using syntax_asdl::Token;
using syntax_asdl::SimpleVarSub;
using syntax_asdl::ShArrayLiteral;
using syntax_asdl::SingleQuoted;
using syntax_asdl::DoubleQuoted;
using syntax_asdl::CommandSub;
using syntax_asdl::BracedVarSub;
using syntax_asdl::BraceGroup;
using syntax_asdl::Subscript;
using syntax_asdl::Attribute;
using syntax_asdl::arith_expr;
using syntax_asdl::arith_expr_e;
using syntax_asdl::arith_expr_t;
using syntax_asdl::Eggex;
using value_asdl::LeftName;

value_asdl::LeftName* LName(BigStr* name) {
  StackRoot _root0(&name);

  return Alloc<LeftName>(name, loc::Missing);
}

syntax_asdl::Token* TokenFor(syntax_asdl::loc_t* loc_) {
  syntax_asdl::loc_t* UP_location = nullptr;
  StackRoot _root0(&loc_);
  StackRoot _root1(&UP_location);

  UP_location = loc_;
  switch (loc_->tag()) {
    case loc_e::Missing: {
      return nullptr;
    }
      break;
    case loc_e::Token: {
      Token* tok = static_cast<Token*>(UP_location);
      if (tok) {
        return tok;
      }
      else {
        return nullptr;
      }
    }
      break;
    case loc_e::ArgWord: {
      CompoundWord* w = static_cast<CompoundWord*>(UP_location);
      return LeftTokenForWord(w);
    }
      break;
    case loc_e::WordPart: {
      loc::WordPart* loc_ = static_cast<loc::WordPart*>(UP_location);
      if (loc_->p) {
        return LeftTokenForWordPart(loc_->p);
      }
      else {
        return nullptr;
      }
    }
      break;
    case loc_e::Word: {
      loc::Word* loc_ = static_cast<loc::Word*>(UP_location);
      if (loc_->w) {
        return LeftTokenForWord(loc_->w);
      }
      else {
        return nullptr;
      }
    }
      break;
    case loc_e::Command: {
      loc::Command* loc_ = static_cast<loc::Command*>(UP_location);
      if (loc_->c) {
        return TokenForCommand(loc_->c);
      }
      else {
        return nullptr;
      }
    }
      break;
    case loc_e::Arith: {
      loc::Arith* loc_ = static_cast<loc::Arith*>(UP_location);
      if (loc_->a) {
        return TokenForArith(loc_->a);
      }
      else {
        return nullptr;
      }
    }
      break;
    default: {
      assert(0);  // AssertionError
    }
  }
  assert(0);  // AssertionError
}

syntax_asdl::Token* TokenForCommand(syntax_asdl::command_t* node) {
  syntax_asdl::command_t* UP_node = nullptr;
  int tag;
  StackRoot _root0(&node);
  StackRoot _root1(&UP_node);

  UP_node = node;
  tag = node->tag();
  if (tag == command_e::Sentence) {
    command::Sentence* node = static_cast<command::Sentence*>(UP_node);
    return node->terminator;
  }
  if (tag == command_e::Simple) {
    command::Simple* node = static_cast<command::Simple*>(UP_node);
    return node->blame_tok;
  }
  if (tag == command_e::ShAssignment) {
    command::ShAssignment* node = static_cast<command::ShAssignment*>(UP_node);
    return node->left;
  }
  if (tag == command_e::Pipeline) {
    command::Pipeline* node = static_cast<command::Pipeline*>(UP_node);
    if (len(node->ops)) {
      return node->ops->at(0);
    }
    else {
      return node->negated;
    }
  }
  if (tag == command_e::AndOr) {
    command::AndOr* node = static_cast<command::AndOr*>(UP_node);
    return node->ops->at(0);
  }
  if (tag == command_e::DoGroup) {
    command::DoGroup* node = static_cast<command::DoGroup*>(UP_node);
    return node->left;
  }
  if (tag == command_e::BraceGroup) {
    BraceGroup* node = static_cast<BraceGroup*>(UP_node);
    return node->left;
  }
  if (tag == command_e::Subshell) {
    command::Subshell* node = static_cast<command::Subshell*>(UP_node);
    return node->left;
  }
  if (tag == command_e::WhileUntil) {
    command::WhileUntil* node = static_cast<command::WhileUntil*>(UP_node);
    return node->keyword;
  }
  if (tag == command_e::If) {
    command::If* node = static_cast<command::If*>(UP_node);
    return node->if_kw;
  }
  if (tag == command_e::Case) {
    command::Case* node = static_cast<command::Case*>(UP_node);
    return node->case_kw;
  }
  if (tag == command_e::TimeBlock) {
    command::TimeBlock* node = static_cast<command::TimeBlock*>(UP_node);
    return node->keyword;
  }
  return nullptr;
}

syntax_asdl::Token* TokenForArith(syntax_asdl::arith_expr_t* node) {
  syntax_asdl::arith_expr_t* UP_node = nullptr;
  StackRoot _root0(&node);
  StackRoot _root1(&UP_node);

  UP_node = node;
  switch (node->tag()) {
    case arith_expr_e::VarSub: {
      Token* vsub = static_cast<Token*>(UP_node);
      return vsub;
    }
      break;
    case arith_expr_e::Word: {
      CompoundWord* w = static_cast<CompoundWord*>(UP_node);
      return LeftTokenForWord(w);
    }
      break;
    case arith_expr_e::Unary: {
      arith_expr::Unary* node = static_cast<arith_expr::Unary*>(UP_node);
      return TokenForArith(node->child);
    }
      break;
    case arith_expr_e::Binary: {
      arith_expr::Binary* node = static_cast<arith_expr::Binary*>(UP_node);
      return TokenForArith(node->op);
    }
      break;
    case arith_expr_e::TernaryOp: {
      arith_expr::TernaryOp* node = static_cast<arith_expr::TernaryOp*>(UP_node);
      return TokenForArith(node->cond);
    }
      break;
  }
  return nullptr;
}

syntax_asdl::Token* LeftTokenForWordPart(syntax_asdl::word_part_t* part) {
  syntax_asdl::word_part_t* UP_part = nullptr;
  StackRoot _root0(&part);
  StackRoot _root1(&UP_part);

  UP_part = part;
  switch (part->tag()) {
    case word_part_e::ShArrayLiteral: {
      ShArrayLiteral* part = static_cast<ShArrayLiteral*>(UP_part);
      return part->left;
    }
      break;
    case word_part_e::BashAssocLiteral: {
      word_part::BashAssocLiteral* part = static_cast<word_part::BashAssocLiteral*>(UP_part);
      return part->left;
    }
      break;
    case word_part_e::Literal: {
      Token* tok = static_cast<Token*>(UP_part);
      return tok;
    }
      break;
    case word_part_e::EscapedLiteral: {
      word_part::EscapedLiteral* part = static_cast<word_part::EscapedLiteral*>(UP_part);
      return part->token;
    }
      break;
    case word_part_e::SingleQuoted: {
      SingleQuoted* part = static_cast<SingleQuoted*>(UP_part);
      return part->left;
    }
      break;
    case word_part_e::DoubleQuoted: {
      DoubleQuoted* part = static_cast<DoubleQuoted*>(UP_part);
      return part->left;
    }
      break;
    case word_part_e::SimpleVarSub: {
      SimpleVarSub* part = static_cast<SimpleVarSub*>(UP_part);
      return part->tok;
    }
      break;
    case word_part_e::BracedVarSub: {
      BracedVarSub* part = static_cast<BracedVarSub*>(UP_part);
      return part->left;
    }
      break;
    case word_part_e::CommandSub: {
      CommandSub* part = static_cast<CommandSub*>(UP_part);
      return part->left_token;
    }
      break;
    case word_part_e::TildeSub: {
      word_part::TildeSub* part = static_cast<word_part::TildeSub*>(UP_part);
      return part->left;
    }
      break;
    case word_part_e::ArithSub: {
      word_part::ArithSub* part = static_cast<word_part::ArithSub*>(UP_part);
      return part->left;
    }
      break;
    case word_part_e::ExtGlob: {
      word_part::ExtGlob* part = static_cast<word_part::ExtGlob*>(UP_part);
      return part->op;
    }
      break;
    case word_part_e::BracedRange: {
      word_part::BracedRange* part = static_cast<word_part::BracedRange*>(UP_part);
      return part->blame_tok;
    }
      break;
    case word_part_e::BracedTuple: {
      word_part::BracedTuple* part = static_cast<word_part::BracedTuple*>(UP_part);
      return nullptr;
    }
      break;
    case word_part_e::Splice: {
      word_part::Splice* part = static_cast<word_part::Splice*>(UP_part);
      return part->blame_tok;
    }
      break;
    case word_part_e::ExprSub: {
      word_part::ExprSub* part = static_cast<word_part::ExprSub*>(UP_part);
      return part->left;
    }
      break;
    default: {
      assert(0);  // AssertionError
    }
  }
}

syntax_asdl::Token* _RightTokenForWordPart(syntax_asdl::word_part_t* part) {
  syntax_asdl::word_part_t* UP_part = nullptr;
  StackRoot _root0(&part);
  StackRoot _root1(&UP_part);

  UP_part = part;
  switch (part->tag()) {
    case word_part_e::ShArrayLiteral: {
      ShArrayLiteral* part = static_cast<ShArrayLiteral*>(UP_part);
      return part->right;
    }
      break;
    case word_part_e::BashAssocLiteral: {
      word_part::BashAssocLiteral* part = static_cast<word_part::BashAssocLiteral*>(UP_part);
      return part->right;
    }
      break;
    case word_part_e::Literal: {
      Token* tok = static_cast<Token*>(UP_part);
      return tok;
    }
      break;
    case word_part_e::EscapedLiteral: {
      word_part::EscapedLiteral* part = static_cast<word_part::EscapedLiteral*>(UP_part);
      return part->token;
    }
      break;
    case word_part_e::SingleQuoted: {
      SingleQuoted* part = static_cast<SingleQuoted*>(UP_part);
      return part->right;
    }
      break;
    case word_part_e::DoubleQuoted: {
      DoubleQuoted* part = static_cast<DoubleQuoted*>(UP_part);
      return part->right;
    }
      break;
    case word_part_e::SimpleVarSub: {
      SimpleVarSub* part = static_cast<SimpleVarSub*>(UP_part);
      return part->tok;
    }
      break;
    case word_part_e::BracedVarSub: {
      BracedVarSub* part = static_cast<BracedVarSub*>(UP_part);
      return part->right;
    }
      break;
    case word_part_e::CommandSub: {
      CommandSub* part = static_cast<CommandSub*>(UP_part);
      return part->right;
    }
      break;
    case word_part_e::TildeSub: {
      word_part::TildeSub* part = static_cast<word_part::TildeSub*>(UP_part);
      if (part->name != nullptr) {
        return part->name;
      }
      else {
        return part->left;
      }
    }
      break;
    case word_part_e::ArithSub: {
      word_part::ArithSub* part = static_cast<word_part::ArithSub*>(UP_part);
      return part->right;
    }
      break;
    case word_part_e::ExtGlob: {
      word_part::ExtGlob* part = static_cast<word_part::ExtGlob*>(UP_part);
      return part->right;
    }
      break;
    case word_part_e::BracedRange: {
      word_part::BracedRange* part = static_cast<word_part::BracedRange*>(UP_part);
      return part->blame_tok;
    }
      break;
    case word_part_e::BracedTuple: {
      word_part::BracedTuple* part = static_cast<word_part::BracedTuple*>(UP_part);
      return nullptr;
    }
      break;
    case word_part_e::Splice: {
      word_part::Splice* part = static_cast<word_part::Splice*>(UP_part);
      return part->blame_tok;
    }
      break;
    case word_part_e::ExprSub: {
      word_part::ExprSub* part = static_cast<word_part::ExprSub*>(UP_part);
      return part->right;
    }
      break;
    default: {
      assert(0);  // AssertionError
    }
  }
}

syntax_asdl::Token* LeftTokenForCompoundWord(syntax_asdl::CompoundWord* w) {
  StackRoot _root0(&w);

  if (len(w->parts)) {
    return LeftTokenForWordPart(w->parts->at(0));
  }
  else {
    return nullptr;
  }
}

syntax_asdl::Token* LeftTokenForWord(syntax_asdl::word_t* w) {
  syntax_asdl::word_t* UP_w = nullptr;
  StackRoot _root0(&w);
  StackRoot _root1(&UP_w);

  if (w == nullptr) {
    return nullptr;
  }
  UP_w = w;
  switch (w->tag()) {
    case word_e::Compound: {
      CompoundWord* w = static_cast<CompoundWord*>(UP_w);
      return LeftTokenForCompoundWord(w);
    }
      break;
    case word_e::Operator: {
      Token* tok = static_cast<Token*>(UP_w);
      return tok;
    }
      break;
    case word_e::BracedTree: {
      word::BracedTree* w = static_cast<word::BracedTree*>(UP_w);
      return LeftTokenForWordPart(w->parts->at(0));
    }
      break;
    case word_e::String: {
      word::String* w = static_cast<word::String*>(UP_w);
      return LeftTokenForWord(w->blame_loc);
    }
      break;
    default: {
      assert(0);  // AssertionError
    }
  }
  assert(0);  // AssertionError
}

syntax_asdl::Token* RightTokenForWord(syntax_asdl::word_t* w) {
  syntax_asdl::word_t* UP_w = nullptr;
  syntax_asdl::word_part_t* end = nullptr;
  StackRoot _root0(&w);
  StackRoot _root1(&UP_w);
  StackRoot _root2(&end);

  UP_w = w;
  switch (w->tag()) {
    case word_e::Compound: {
      CompoundWord* w = static_cast<CompoundWord*>(UP_w);
      if (len(w->parts)) {
        end = w->parts->at(-1);
        return _RightTokenForWordPart(end);
      }
      else {
        return nullptr;
      }
    }
      break;
    case word_e::Operator: {
      Token* tok = static_cast<Token*>(UP_w);
      return tok;
    }
      break;
    case word_e::BracedTree: {
      word::BracedTree* w = static_cast<word::BracedTree*>(UP_w);
      return _RightTokenForWordPart(w->parts->at(-1));
    }
      break;
    case word_e::String: {
      word::String* w = static_cast<word::String*>(UP_w);
      return RightTokenForWord(w->blame_loc);
    }
      break;
    default: {
      assert(0);  // AssertionError
    }
  }
  assert(0);  // AssertionError
}

syntax_asdl::Token* TokenForLhsExpr(syntax_asdl::sh_lhs_t* node) {
  syntax_asdl::sh_lhs_t* UP_node = nullptr;
  StackRoot _root0(&node);
  StackRoot _root1(&UP_node);

  UP_node = node;
  switch (node->tag()) {
    case sh_lhs_e::Name: {
      sh_lhs::Name* node = static_cast<sh_lhs::Name*>(UP_node);
      return node->left;
    }
      break;
    case sh_lhs_e::IndexedName: {
      sh_lhs::IndexedName* node = static_cast<sh_lhs::IndexedName*>(UP_node);
      return node->left;
    }
      break;
    default: {
      assert(0);  // AssertionError
    }
  }
  assert(0);  // AssertionError
}

syntax_asdl::loc_t* TokenForExpr(syntax_asdl::expr_t* node) {
  syntax_asdl::expr_t* UP_node = nullptr;
  StackRoot _root0(&node);
  StackRoot _root1(&UP_node);

  UP_node = node;
  switch (node->tag()) {
    case expr_e::Const: {
      expr::Const* node = static_cast<expr::Const*>(UP_node);
      return node->c;
    }
      break;
    case expr_e::Var: {
      expr::Var* node = static_cast<expr::Var*>(UP_node);
      return node->left;
    }
      break;
    case expr_e::Place: {
      expr::Place* node = static_cast<expr::Place*>(UP_node);
      return node->blame_tok;
    }
      break;
    case expr_e::CommandSub: {
      CommandSub* node = static_cast<CommandSub*>(UP_node);
      return node->left_token;
    }
      break;
    case expr_e::ShArrayLiteral: {
      ShArrayLiteral* node = static_cast<ShArrayLiteral*>(UP_node);
      return node->left;
    }
      break;
    case expr_e::DoubleQuoted: {
      DoubleQuoted* node = static_cast<DoubleQuoted*>(UP_node);
      return node->left;
    }
      break;
    case expr_e::SingleQuoted: {
      SingleQuoted* node = static_cast<SingleQuoted*>(UP_node);
      return node->left;
    }
      break;
    case expr_e::BracedVarSub: {
      BracedVarSub* node = static_cast<BracedVarSub*>(UP_node);
      return node->left;
    }
      break;
    case expr_e::SimpleVarSub: {
      SimpleVarSub* node = static_cast<SimpleVarSub*>(UP_node);
      return node->tok;
    }
      break;
    case expr_e::Unary: {
      expr::Unary* node = static_cast<expr::Unary*>(UP_node);
      return node->op;
    }
      break;
    case expr_e::Binary: {
      expr::Binary* node = static_cast<expr::Binary*>(UP_node);
      return node->op;
    }
      break;
    case expr_e::Slice: {
      expr::Slice* node = static_cast<expr::Slice*>(UP_node);
      return node->op;
    }
      break;
    case expr_e::Range: {
      expr::Range* node = static_cast<expr::Range*>(UP_node);
      return node->op;
    }
      break;
    case expr_e::Compare: {
      expr::Compare* node = static_cast<expr::Compare*>(UP_node);
      return TokenForExpr(node->left);
    }
      break;
    case expr_e::IfExp: {
      return loc::Missing;
    }
      break;
    case expr_e::List: {
      expr::List* node = static_cast<expr::List*>(UP_node);
      return node->left;
    }
      break;
    case expr_e::Tuple: {
      expr::Tuple* node = static_cast<expr::Tuple*>(UP_node);
      return node->left;
    }
      break;
    case expr_e::Dict: {
      expr::Dict* node = static_cast<expr::Dict*>(UP_node);
      return node->left;
    }
      break;
    case expr_e::ListComp: {
      expr::ListComp* node = static_cast<expr::ListComp*>(UP_node);
      return node->left;
    }
      break;
    case expr_e::GeneratorExp: {
      return loc::Missing;
    }
      break;
    case expr_e::Lambda: {
      return loc::Missing;
    }
      break;
    case expr_e::FuncCall: {
      expr::FuncCall* node = static_cast<expr::FuncCall*>(UP_node);
      return node->args->left;
    }
      break;
    case expr_e::Subscript: {
      Subscript* node = static_cast<Subscript*>(UP_node);
      return node->left;
    }
      break;
    case expr_e::Attribute: {
      Attribute* node = static_cast<Attribute*>(UP_node);
      return node->op;
    }
      break;
    case expr_e::Eggex: {
      Eggex* node = static_cast<Eggex*>(UP_node);
      return node->left;
    }
      break;
    default: {
      assert(0);  // AssertionError
    }
  }
}

}  // define namespace location

namespace parse_lib {  // define

using id_kind_asdl::Id_t;
using syntax_asdl::Token;
using syntax_asdl::CompoundWord;
using syntax_asdl::expr_t;
using syntax_asdl::Redir;
using syntax_asdl::ArgList;
using syntax_asdl::Proc;
using syntax_asdl::Func;
using syntax_asdl::command;
using syntax_asdl::pat_t;
using types_asdl::lex_mode_e;
namespace fmt = format;
using expr_parse::ctx_PNodeAllocator;

_BaseTrail::_BaseTrail() {
  this->words = Alloc<List<syntax_asdl::CompoundWord*>>();
  this->redirects = Alloc<List<syntax_asdl::Redir*>>();
  this->tokens = Alloc<List<syntax_asdl::Token*>>();
  this->alias_words = Alloc<List<syntax_asdl::CompoundWord*>>();
  this->_expanding_alias = false;
}

void _BaseTrail::Clear() {
  ;  // pass
}

void _BaseTrail::SetLatestWords(List<syntax_asdl::CompoundWord*>* words, List<syntax_asdl::Redir*>* redirects) {
  StackRoot _root0(&words);
  StackRoot _root1(&redirects);

  ;  // pass
}

void _BaseTrail::AppendToken(syntax_asdl::Token* token) {
  StackRoot _root0(&token);

  ;  // pass
}

void _BaseTrail::BeginAliasExpansion() {
  ;  // pass
}

void _BaseTrail::EndAliasExpansion() {
  ;  // pass
}

ctx_Alias::ctx_Alias(parse_lib::_BaseTrail* trail) {
  gHeap.PushRoot(reinterpret_cast<RawObject**>(&(this->trail)));
  trail->_expanding_alias = true;
  this->trail = trail;
}

ctx_Alias::~ctx_Alias() {
  this->trail->_expanding_alias = false;
  gHeap.PopRoot();
}

Trail::Trail() : ::parse_lib::_BaseTrail() {
}

void Trail::Clear() {
  this->words->clear();
  this->redirects->clear();
  this->tokens->clear();
  this->alias_words->clear();
}

void Trail::SetLatestWords(List<syntax_asdl::CompoundWord*>* words, List<syntax_asdl::Redir*>* redirects) {
  StackRoot _root0(&words);
  StackRoot _root1(&redirects);

  if (this->_expanding_alias) {
    this->alias_words = words;
    return ;
  }
  this->words = words;
  this->redirects = redirects;
}

void Trail::AppendToken(syntax_asdl::Token* token) {
  StackRoot _root0(&token);

  if (this->_expanding_alias) {
    return ;
  }
  this->tokens->append(token);
}

ParseContext::ParseContext(alloc::Arena* arena, optview::Parse* parse_opts, Dict<BigStr*, BigStr*>* aliases, grammar::Grammar* ysh_grammar, bool do_lossless) {
  this->arena = arena;
  this->parse_opts = parse_opts;
  this->aliases = aliases;
  this->ysh_grammar = ysh_grammar;
  this->do_lossless = do_lossless;
  if (ysh_grammar) {
    this->tr = Alloc<expr_to_ast::Transformer>(ysh_grammar);
  }
  else {
    this->tr = nullptr;
  }
  this->trail = Alloc<_BaseTrail>();
}

void ParseContext::Init_Trail(parse_lib::_BaseTrail* trail) {
  StackRoot _root0(&trail);

  this->trail = trail;
}

lexer::Lexer* ParseContext::MakeLexer(reader::_Reader* line_reader) {
  lexer::LineLexer* line_lexer = nullptr;
  StackRoot _root0(&line_reader);
  StackRoot _root1(&line_lexer);

  line_lexer = Alloc<lexer::LineLexer>(line_reader->arena);
  return Alloc<lexer::Lexer>(line_lexer, line_reader);
}

cmd_parse::CommandParser* ParseContext::MakeOshParser(reader::_Reader* line_reader, bool emit_comp_dummy) {
  lexer::Lexer* lx = nullptr;
  word_parse::WordParser* w_parser = nullptr;
  cmd_parse::CommandParser* c_parser = nullptr;
  StackRoot _root0(&line_reader);
  StackRoot _root1(&lx);
  StackRoot _root2(&w_parser);
  StackRoot _root3(&c_parser);

  lx = this->MakeLexer(line_reader);
  if (emit_comp_dummy) {
    lx->EmitCompDummy();
  }
  w_parser = Alloc<word_parse::WordParser>(this, lx, line_reader);
  c_parser = Alloc<cmd_parse::CommandParser>(this, this->parse_opts, w_parser, lx, line_reader);
  return c_parser;
}

cmd_parse::CommandParser* ParseContext::MakeConfigParser(reader::_Reader* line_reader) {
  lexer::Lexer* lx = nullptr;
  optview::Parse* parse_opts = nullptr;
  word_parse::WordParser* w_parser = nullptr;
  cmd_parse::CommandParser* c_parser = nullptr;
  StackRoot _root0(&line_reader);
  StackRoot _root1(&lx);
  StackRoot _root2(&parse_opts);
  StackRoot _root3(&w_parser);
  StackRoot _root4(&c_parser);

  lx = this->MakeLexer(line_reader);
  parse_opts = state::MakeOilOpts();
  w_parser = Alloc<word_parse::WordParser>(this, lx, line_reader);
  c_parser = Alloc<cmd_parse::CommandParser>(this, parse_opts, w_parser, lx, line_reader);
  return c_parser;
}

word_parse::WordParser* ParseContext::MakeWordParserForHereDoc(reader::_Reader* line_reader) {
  lexer::Lexer* lx = nullptr;
  StackRoot _root0(&line_reader);
  StackRoot _root1(&lx);

  lx = this->MakeLexer(line_reader);
  return Alloc<word_parse::WordParser>(this, lx, line_reader);
}

word_parse::WordParser* ParseContext::MakeWordParser(lexer::Lexer* lx, reader::_Reader* line_reader) {
  StackRoot _root0(&lx);
  StackRoot _root1(&line_reader);

  return Alloc<word_parse::WordParser>(this, lx, line_reader);
}

tdop::TdopParser* ParseContext::MakeArithParser(BigStr* code_str) {
  reader::FileLineReader* line_reader = nullptr;
  lexer::Lexer* lx = nullptr;
  word_parse::WordParser* w_parser = nullptr;
  tdop::TdopParser* a_parser = nullptr;
  StackRoot _root0(&code_str);
  StackRoot _root1(&line_reader);
  StackRoot _root2(&lx);
  StackRoot _root3(&w_parser);
  StackRoot _root4(&a_parser);

  line_reader = reader::StringLineReader(code_str, this->arena);
  lx = this->MakeLexer(line_reader);
  w_parser = Alloc<word_parse::WordParser>(this, lx, line_reader);
  w_parser->Init(lex_mode_e::Arith);
  a_parser = Alloc<tdop::TdopParser>(arith_parse::Spec(), w_parser, this->parse_opts);
  return a_parser;
}

cmd_parse::CommandParser* ParseContext::MakeParserForCommandSub(reader::_Reader* line_reader, lexer::Lexer* lexer, int eof_id) {
  word_parse::WordParser* w_parser = nullptr;
  cmd_parse::CommandParser* c_parser = nullptr;
  StackRoot _root0(&line_reader);
  StackRoot _root1(&lexer);
  StackRoot _root2(&w_parser);
  StackRoot _root3(&c_parser);

  w_parser = Alloc<word_parse::WordParser>(this, lexer, line_reader);
  c_parser = Alloc<cmd_parse::CommandParser>(this, this->parse_opts, w_parser, lexer, line_reader, eof_id);
  return c_parser;
}

word_parse::WordParser* ParseContext::MakeWordParserForPlugin(BigStr* code_str) {
  reader::FileLineReader* line_reader = nullptr;
  lexer::Lexer* lx = nullptr;
  StackRoot _root0(&code_str);
  StackRoot _root1(&line_reader);
  StackRoot _root2(&lx);

  line_reader = reader::StringLineReader(code_str, this->arena);
  lx = this->MakeLexer(line_reader);
  return Alloc<word_parse::WordParser>(this, lx, line_reader);
}

expr_parse::ExprParser* ParseContext::_YshParser() {
  return Alloc<expr_parse::ExprParser>(this, this->ysh_grammar);
}

Tuple2<command::VarDecl*, syntax_asdl::Token*> ParseContext::ParseVarDecl(syntax_asdl::Token* kw_token, lexer::Lexer* lexer) {
  expr_parse::ExprParser* e_parser = nullptr;
  pnode::PNode* pnode = nullptr;
  syntax_asdl::Token* last_token = nullptr;
  command::VarDecl* ast_node = nullptr;
  StackRoot _root0(&kw_token);
  StackRoot _root1(&lexer);
  StackRoot _root2(&e_parser);
  StackRoot _root3(&pnode);
  StackRoot _root4(&last_token);
  StackRoot _root5(&ast_node);

  e_parser = this->_YshParser();
  {  // with
    ctx_PNodeAllocator ctx{e_parser};

    Tuple2<pnode::PNode*, syntax_asdl::Token*> tup0 = e_parser->Parse(lexer, grammar_nt::ysh_var_decl);
    pnode = tup0.at0();
    last_token = tup0.at1();
    ast_node = this->tr->MakeVarDecl(pnode);
    ast_node->keyword = kw_token;
  }
  return Tuple2<command::VarDecl*, syntax_asdl::Token*>(ast_node, last_token);
}

Tuple2<command::Mutation*, syntax_asdl::Token*> ParseContext::ParseMutation(syntax_asdl::Token* kw_token, lexer::Lexer* lexer) {
  expr_parse::ExprParser* e_parser = nullptr;
  pnode::PNode* pnode = nullptr;
  syntax_asdl::Token* last_token = nullptr;
  command::Mutation* ast_node = nullptr;
  StackRoot _root0(&kw_token);
  StackRoot _root1(&lexer);
  StackRoot _root2(&e_parser);
  StackRoot _root3(&pnode);
  StackRoot _root4(&last_token);
  StackRoot _root5(&ast_node);

  e_parser = this->_YshParser();
  {  // with
    ctx_PNodeAllocator ctx{e_parser};

    Tuple2<pnode::PNode*, syntax_asdl::Token*> tup1 = e_parser->Parse(lexer, grammar_nt::ysh_mutation);
    pnode = tup1.at0();
    last_token = tup1.at1();
    ast_node = this->tr->MakeMutation(pnode);
    ast_node->keyword = kw_token;
  }
  return Tuple2<command::Mutation*, syntax_asdl::Token*>(ast_node, last_token);
}

void ParseContext::ParseProcCallArgs(lexer::Lexer* lx, syntax_asdl::ArgList* out, int start_symbol) {
  expr_parse::ExprParser* e_parser = nullptr;
  pnode::PNode* pnode = nullptr;
  syntax_asdl::Token* last_token = nullptr;
  StackRoot _root0(&lx);
  StackRoot _root1(&out);
  StackRoot _root2(&e_parser);
  StackRoot _root3(&pnode);
  StackRoot _root4(&last_token);

  e_parser = this->_YshParser();
  {  // with
    ctx_PNodeAllocator ctx{e_parser};

    Tuple2<pnode::PNode*, syntax_asdl::Token*> tup2 = e_parser->Parse(lx, start_symbol);
    pnode = tup2.at0();
    last_token = tup2.at1();
    this->tr->ProcCallArgs(pnode, out);
    out->right = last_token;
  }
}

Tuple2<syntax_asdl::expr_t*, syntax_asdl::Token*> ParseContext::ParseYshExpr(lexer::Lexer* lx, int start_symbol) {
  expr_parse::ExprParser* e_parser = nullptr;
  pnode::PNode* pnode = nullptr;
  syntax_asdl::Token* last_token = nullptr;
  syntax_asdl::expr_t* ast_node = nullptr;
  StackRoot _root0(&lx);
  StackRoot _root1(&e_parser);
  StackRoot _root2(&pnode);
  StackRoot _root3(&last_token);
  StackRoot _root4(&ast_node);

  e_parser = this->_YshParser();
  {  // with
    ctx_PNodeAllocator ctx{e_parser};

    Tuple2<pnode::PNode*, syntax_asdl::Token*> tup3 = e_parser->Parse(lx, start_symbol);
    pnode = tup3.at0();
    last_token = tup3.at1();
    ast_node = this->tr->Expr(pnode);
  }
  return Tuple2<syntax_asdl::expr_t*, syntax_asdl::Token*>(ast_node, last_token);
}

Tuple3<syntax_asdl::pat_t*, syntax_asdl::Token*, syntax_asdl::Token*> ParseContext::ParseYshCasePattern(lexer::Lexer* lexer) {
  expr_parse::ExprParser* e_parser = nullptr;
  pnode::PNode* pnode = nullptr;
  syntax_asdl::Token* last_token = nullptr;
  syntax_asdl::Token* left_tok = nullptr;
  syntax_asdl::pat_t* pattern = nullptr;
  StackRoot _root0(&lexer);
  StackRoot _root1(&e_parser);
  StackRoot _root2(&pnode);
  StackRoot _root3(&last_token);
  StackRoot _root4(&left_tok);
  StackRoot _root5(&pattern);

  e_parser = this->_YshParser();
  {  // with
    ctx_PNodeAllocator ctx{e_parser};

    Tuple2<pnode::PNode*, syntax_asdl::Token*> tup4 = e_parser->Parse(lexer, grammar_nt::ysh_case_pat);
    pnode = tup4.at0();
    last_token = tup4.at1();
    left_tok = pnode->GetChild(0)->tok;
    pattern = this->tr->YshCasePattern(pnode);
  }
  return Tuple3<syntax_asdl::pat_t*, syntax_asdl::Token*, syntax_asdl::Token*>(pattern, left_tok, last_token);
}

syntax_asdl::Token* ParseContext::ParseProc(lexer::Lexer* lexer, syntax_asdl::Proc* out) {
  expr_parse::ExprParser* e_parser = nullptr;
  pnode::PNode* pnode = nullptr;
  syntax_asdl::Token* last_token = nullptr;
  StackRoot _root0(&lexer);
  StackRoot _root1(&out);
  StackRoot _root2(&e_parser);
  StackRoot _root3(&pnode);
  StackRoot _root4(&last_token);

  e_parser = this->_YshParser();
  {  // with
    ctx_PNodeAllocator ctx{e_parser};

    Tuple2<pnode::PNode*, syntax_asdl::Token*> tup5 = e_parser->Parse(lexer, grammar_nt::ysh_proc);
    pnode = tup5.at0();
    last_token = tup5.at1();
    out->sig = this->tr->Proc(pnode);
  }
  return last_token;
}

syntax_asdl::Token* ParseContext::ParseFunc(lexer::Lexer* lexer, syntax_asdl::Func* out) {
  expr_parse::ExprParser* e_parser = nullptr;
  pnode::PNode* pnode = nullptr;
  syntax_asdl::Token* last_token = nullptr;
  StackRoot _root0(&lexer);
  StackRoot _root1(&out);
  StackRoot _root2(&e_parser);
  StackRoot _root3(&pnode);
  StackRoot _root4(&last_token);

  e_parser = this->_YshParser();
  {  // with
    ctx_PNodeAllocator ctx{e_parser};

    Tuple2<pnode::PNode*, syntax_asdl::Token*> tup6 = e_parser->Parse(lexer, grammar_nt::ysh_func);
    pnode = tup6.at0();
    last_token = tup6.at1();
    this->tr->YshFunc(pnode, out);
  }
  return last_token;
}

}  // define namespace parse_lib

namespace reader {  // define

using id_kind_asdl::Id;
using error::p_die;
BigStr* _PS2 = str1312;

_Reader::_Reader(alloc::Arena* arena) {
  this->arena = arena;
  this->line_num = 1;
}

void _Reader::SetLineOffset(int n) {
  this->line_num = n;
}

BigStr* _Reader::_GetLine() {
  FAIL(kNotImplemented);  // Python NotImplementedError
}

Tuple2<syntax_asdl::SourceLine*, int> _Reader::GetLine() {
  BigStr* line_str = nullptr;
  syntax_asdl::SourceLine* eof_line = nullptr;
  syntax_asdl::SourceLine* src_line = nullptr;
  StackRoot _root0(&line_str);
  StackRoot _root1(&eof_line);
  StackRoot _root2(&src_line);

  line_str = this->_GetLine();
  if (line_str == nullptr) {
    eof_line = nullptr;
    return Tuple2<syntax_asdl::SourceLine*, int>(eof_line, 0);
  }
  src_line = this->arena->AddLine(line_str, this->line_num);
  this->line_num += 1;
  return Tuple2<syntax_asdl::SourceLine*, int>(src_line, 0);
}

void _Reader::Reset() {
  ;  // pass
}

bool _Reader::LastLineHint() {
  return false;
}

DisallowedLineReader::DisallowedLineReader(alloc::Arena* arena, syntax_asdl::Token* blame_token) : ::reader::_Reader(arena) {
  this->blame_token = blame_token;
}

BigStr* DisallowedLineReader::_GetLine() {
  p_die(str1313, this->blame_token);
}

FileLineReader::FileLineReader(mylib::LineReader* f, alloc::Arena* arena) : ::reader::_Reader(arena) {
  this->f = f;
  this->last_line_hint = false;
}

BigStr* FileLineReader::_GetLine() {
  BigStr* line = nullptr;
  StackRoot _root0(&line);

  line = this->f->readline();
  if (len(line) == 0) {
    return nullptr;
  }
  if (!line->endswith(str1314)) {
    this->last_line_hint = true;
  }
  return line;
}

bool FileLineReader::LastLineHint() {
  return this->last_line_hint;
}

reader::FileLineReader* StringLineReader(BigStr* s, alloc::Arena* arena) {
  StackRoot _root0(&s);
  StackRoot _root1(&arena);

  return Alloc<FileLineReader>(Alloc<mylib::BufLineReader>(s), arena);
}

VirtualLineReader::VirtualLineReader(alloc::Arena* arena, List<Tuple2<syntax_asdl::SourceLine*, int>*>* lines, bool do_lossless) : ::reader::_Reader(arena) {
  this->lines = lines;
  this->do_lossless = do_lossless;
  this->num_lines = len(lines);
  this->pos = 0;
}

Tuple2<syntax_asdl::SourceLine*, int> VirtualLineReader::GetLine() {
  syntax_asdl::SourceLine* eof_line = nullptr;
  syntax_asdl::SourceLine* src_line = nullptr;
  int start_offset;
  StackRoot _root0(&eof_line);
  StackRoot _root1(&src_line);

  if (this->pos == this->num_lines) {
    eof_line = nullptr;
    return Tuple2<syntax_asdl::SourceLine*, int>(eof_line, 0);
  }
  Tuple2<syntax_asdl::SourceLine*, int>* tup0 = this->lines->at(this->pos);
  src_line = tup0->at0();
  start_offset = tup0->at1();
  this->pos += 1;
  if (this->do_lossless) {
    if (start_offset != 0) {
      this->arena->NewToken(Id::Lit_CharsWithoutPrefix, start_offset, 0, src_line);
    }
  }
  return Tuple2<syntax_asdl::SourceLine*, int>(src_line, start_offset);
}

BigStr* _PlainPromptInput(BigStr* prompt) {
  mylib::Writer* w = nullptr;
  BigStr* line = nullptr;
  StackRoot _root0(&prompt);
  StackRoot _root1(&w);
  StackRoot _root2(&line);

  w = mylib::Stderr();
  w->write(prompt);
  w->flush();
  line = mylib::Stdin()->readline();
  if (len(line) == 0) {
    throw Alloc<EOFError>();
  }
  return line;
}

InteractiveLineReader::InteractiveLineReader(alloc::Arena* arena, prompt::Evaluator* prompt_ev, history::Evaluator* hist_ev, py_readline::Readline* line_input, comp_ui::PromptState* prompt_state) : ::reader::_Reader(arena) {
  this->prompt_ev = prompt_ev;
  this->hist_ev = hist_ev;
  this->line_input = line_input;
  this->prompt_state = prompt_state;
  this->prev_line = nullptr;
  this->prompt_str = str1315;
  this->Reset();
}

void InteractiveLineReader::Reset() {
  this->render_ps1 = true;
}

BigStr* InteractiveLineReader::_GetLine() {
  BigStr* line = nullptr;
  StackRoot _root0(&line);

  if (this->render_ps1) {
    this->prompt_str = this->prompt_ev->EvalFirstPrompt();
    this->prompt_state->SetLastPrompt(this->prompt_str);
  }
  line = nullptr;
  try {
    if ((!this->line_input or (!mylib::Stdout()->isatty() or !mylib::Stdin()->isatty()))) {
      line = _PlainPromptInput(this->prompt_str);
    }
    else {
      line = this->line_input->prompt_input(this->prompt_str);
    }
  }
  catch (EOFError*) {
    print(str1316);
  }
  if (line != nullptr) {
    line = this->hist_ev->Eval(line);
    if ((len(line->strip()) and (!(str_equals(line, this->prev_line)) and this->line_input != nullptr))) {
      this->line_input->add_history(line->rstrip());
      this->prev_line = line;
    }
  }
  this->prompt_str = _PS2;
  this->prompt_state->SetLastPrompt(this->prompt_str);
  this->render_ps1 = false;
  return line;
}

}  // define namespace reader

namespace typed_args {  // define

using runtime_asdl::cmd_value;
using syntax_asdl::loc;
using syntax_asdl::loc_t;
using syntax_asdl::ArgList;
using syntax_asdl::LiteralBlock;
using syntax_asdl::command_t;
using syntax_asdl::expr_t;
using value_asdl::value;
using value_asdl::value_e;
using value_asdl::value_t;
using value_asdl::RegexMatch;
using error::e_usage;

void DoesNotAccept(syntax_asdl::ArgList* arg_list) {
  StackRoot _root0(&arg_list);

  if (arg_list != nullptr) {
    e_usage(str1317, arg_list->left);
  }
}

syntax_asdl::command_t* OptionalBlock(cmd_value::Argv* cmd_val) {
  syntax_asdl::command_t* cmd = nullptr;
  typed_args::Reader* r = nullptr;
  StackRoot _root0(&cmd_val);
  StackRoot _root1(&cmd);
  StackRoot _root2(&r);

  cmd = nullptr;
  if (cmd_val->typed_args) {
    r = ReaderForProc(cmd_val);
    cmd = r->OptionalBlock();
    r->Done();
  }
  return cmd;
}

syntax_asdl::LiteralBlock* OptionalLiteralBlock(cmd_value::Argv* cmd_val) {
  syntax_asdl::LiteralBlock* block = nullptr;
  typed_args::Reader* r = nullptr;
  StackRoot _root0(&cmd_val);
  StackRoot _root1(&block);
  StackRoot _root2(&r);

  block = nullptr;
  if (cmd_val->typed_args) {
    r = ReaderForProc(cmd_val);
    block = r->OptionalLiteralBlock();
    r->Done();
  }
  return block;
}

typed_args::Reader* ReaderForProc(cmd_value::Argv* cmd_val) {
  List<value_asdl::value_t*>* pos_args = nullptr;
  Dict<BigStr*, value_asdl::value_t*>* named_args = nullptr;
  syntax_asdl::ArgList* arg_list = nullptr;
  typed_args::Reader* rd = nullptr;
  StackRoot _root0(&cmd_val);
  StackRoot _root1(&pos_args);
  StackRoot _root2(&named_args);
  StackRoot _root3(&arg_list);
  StackRoot _root4(&rd);

  pos_args = cmd_val->pos_args != nullptr ? cmd_val->pos_args : Alloc<List<value_asdl::value_t*>>();
  named_args = cmd_val->named_args != nullptr ? cmd_val->named_args : Alloc<Dict<BigStr*, value_asdl::value_t*>>();
  arg_list = cmd_val->typed_args != nullptr ? cmd_val->typed_args : ArgList::CreateNull();
  rd = Alloc<Reader>(pos_args, named_args, cmd_val->block_arg, arg_list);
  rd->SetFallbackLocation(cmd_val->arg_locs->at(0));
  return rd;
}

Reader::Reader(List<value_asdl::value_t*>* pos_args, Dict<BigStr*, value_asdl::value_t*>* named_args, value_asdl::value_t* block_arg, syntax_asdl::ArgList* arg_list, bool is_bound) {
  this->pos_args = pos_args;
  this->pos_consumed = 0;
  this->is_bound = is_bound;
  this->named_args = named_args;
  this->block_arg = block_arg;
  this->arg_list = arg_list;
  this->fallback_loc = loc::Missing;
}

void Reader::SetFallbackLocation(syntax_asdl::loc_t* blame_loc) {
  StackRoot _root0(&blame_loc);

  this->fallback_loc = blame_loc;
}

syntax_asdl::loc_t* Reader::LeftParenToken() {
  return this->arg_list->left;
}

syntax_asdl::loc_t* Reader::LeastSpecificLocation() {
  if (this->arg_list->left) {
    return this->arg_list->left;
  }
  return this->fallback_loc;
}

syntax_asdl::loc_t* Reader::BlamePos() {
  int pos;
  syntax_asdl::loc_t* l = nullptr;
  StackRoot _root0(&l);

  pos = (this->pos_consumed - 1);
  if (this->is_bound) {
    pos -= 1;
  }
  if (this->arg_list->pos_args == nullptr) {
    return this->LeastSpecificLocation();
  }
  if ((0 <= pos and pos < len(this->arg_list->pos_args))) {
    l = location::TokenForExpr(this->arg_list->pos_args->at(pos));
    if (l != nullptr) {
      return l;
    }
  }
  return this->LeastSpecificLocation();
}

value_asdl::value_t* Reader::PosValue() {
  if (len(this->pos_args) == 0) {
    throw Alloc<error::TypeErrVerbose>(StrFormat("Expected at least %d typed args, but only got %d", (this->pos_consumed + 1), this->pos_consumed), this->LeastSpecificLocation());
  }
  this->pos_consumed += 1;
  return this->pos_args->pop(0);
}

value_asdl::value_t* Reader::OptionalValue() {
  if (len(this->pos_args) == 0) {
    return nullptr;
  }
  this->pos_consumed += 1;
  return this->pos_args->pop(0);
}

BigStr* Reader::_ToStr(value_asdl::value_t* val) {
  StackRoot _root0(&val);

  if (val->tag() == value_e::Str) {
    return static_cast<value::Str*>(val)->s;
  }
  throw Alloc<error::TypeErr>(val, StrFormat("Arg %d should be a Str", this->pos_consumed), this->BlamePos());
}

bool Reader::_ToBool(value_asdl::value_t* val) {
  StackRoot _root0(&val);

  if (val->tag() == value_e::Bool) {
    return static_cast<value::Bool*>(val)->b;
  }
  throw Alloc<error::TypeErr>(val, StrFormat("Arg %d should be a Bool", this->pos_consumed), this->BlamePos());
}

mops::BigInt Reader::_ToInt(value_asdl::value_t* val) {
  StackRoot _root0(&val);

  if (val->tag() == value_e::Int) {
    return static_cast<value::Int*>(val)->i;
  }
  throw Alloc<error::TypeErr>(val, StrFormat("Arg %d should be an Int", this->pos_consumed), this->BlamePos());
}

double Reader::_ToFloat(value_asdl::value_t* val) {
  StackRoot _root0(&val);

  if (val->tag() == value_e::Float) {
    return static_cast<value::Float*>(val)->f;
  }
  throw Alloc<error::TypeErr>(val, StrFormat("Arg %d should be a Float", this->pos_consumed), this->BlamePos());
}

List<BigStr*>* Reader::_ToBashArray(value_asdl::value_t* val) {
  StackRoot _root0(&val);

  if (val->tag() == value_e::BashArray) {
    return static_cast<value::BashArray*>(val)->strs;
  }
  throw Alloc<error::TypeErr>(val, StrFormat("Arg %d should be a BashArray", this->pos_consumed), this->BlamePos());
}

value::SparseArray* Reader::_ToSparseArray(value_asdl::value_t* val) {
  StackRoot _root0(&val);

  if (val->tag() == value_e::SparseArray) {
    return static_cast<value::SparseArray*>(val);
  }
  throw Alloc<error::TypeErr>(val, StrFormat("Arg %d should be a SparseArray", this->pos_consumed), this->BlamePos());
}

List<value_asdl::value_t*>* Reader::_ToList(value_asdl::value_t* val) {
  StackRoot _root0(&val);

  if (val->tag() == value_e::List) {
    return static_cast<value::List*>(val)->items;
  }
  throw Alloc<error::TypeErr>(val, StrFormat("Arg %d should be a List", this->pos_consumed), this->BlamePos());
}

Dict<BigStr*, value_asdl::value_t*>* Reader::_ToDict(value_asdl::value_t* val) {
  StackRoot _root0(&val);

  if (val->tag() == value_e::Dict) {
    return static_cast<value::Dict*>(val)->d;
  }
  throw Alloc<error::TypeErr>(val, StrFormat("Arg %d should be a Dict", this->pos_consumed), this->BlamePos());
}

value::Place* Reader::_ToPlace(value_asdl::value_t* val) {
  StackRoot _root0(&val);

  if (val->tag() == value_e::Place) {
    return static_cast<value::Place*>(val);
  }
  throw Alloc<error::TypeErr>(val, StrFormat("Arg %d should be a Place", this->pos_consumed), this->BlamePos());
}

value_asdl::RegexMatch* Reader::_ToMatch(value_asdl::value_t* val) {
  StackRoot _root0(&val);

  if (val->tag() == value_e::Match) {
    return static_cast<RegexMatch*>(val);
  }
  throw Alloc<error::TypeErr>(val, StrFormat("Arg %d should be a Match", this->pos_consumed), this->BlamePos());
}

value::Eggex* Reader::_ToEggex(value_asdl::value_t* val) {
  StackRoot _root0(&val);

  if (val->tag() == value_e::Eggex) {
    return static_cast<value::Eggex*>(val);
  }
  throw Alloc<error::TypeErr>(val, StrFormat("Arg %d should be an Eggex", this->pos_consumed), this->BlamePos());
}

value::IO* Reader::_ToIO(value_asdl::value_t* val) {
  StackRoot _root0(&val);

  if (val->tag() == value_e::IO) {
    return static_cast<value::IO*>(val);
  }
  throw Alloc<error::TypeErr>(val, StrFormat("Arg %d should be IO", this->pos_consumed), this->BlamePos());
}

syntax_asdl::expr_t* Reader::_ToExpr(value_asdl::value_t* val) {
  StackRoot _root0(&val);

  if (val->tag() == value_e::Expr) {
    return static_cast<value::Expr*>(val)->e;
  }
  throw Alloc<error::TypeErr>(val, StrFormat("Arg %d should be a Expr", this->pos_consumed), this->BlamePos());
}

syntax_asdl::command_t* Reader::_ToCommand(value_asdl::value_t* val) {
  StackRoot _root0(&val);

  if (val->tag() == value_e::Command) {
    return static_cast<value::Command*>(val)->c;
  }
  if (val->tag() == value_e::Block) {
    return static_cast<value::Block*>(val)->block->brace_group;
  }
  throw Alloc<error::TypeErr>(val, StrFormat("Arg %d should be a Command", this->pos_consumed), this->BlamePos());
}

syntax_asdl::command_t* Reader::_ToBlock(value_asdl::value_t* val) {
  StackRoot _root0(&val);

  if (val->tag() == value_e::Command) {
    return static_cast<value::Command*>(val)->c;
  }
  if (val->tag() == value_e::Block) {
    return static_cast<value::Block*>(val)->block->brace_group;
  }
  throw Alloc<error::TypeErr>(val, StrFormat("Arg %d should be a Command", this->pos_consumed), this->BlamePos());
}

syntax_asdl::LiteralBlock* Reader::_ToLiteralBlock(value_asdl::value_t* val) {
  StackRoot _root0(&val);

  if (val->tag() == value_e::Block) {
    return static_cast<value::Block*>(val)->block;
  }
  throw Alloc<error::TypeErr>(val, StrFormat("Arg %d should be a LiteralBlock", this->pos_consumed), this->BlamePos());
}

BigStr* Reader::PosStr() {
  value_asdl::value_t* val = nullptr;
  StackRoot _root0(&val);

  val = this->PosValue();
  return this->_ToStr(val);
}

BigStr* Reader::OptionalStr(BigStr* default_) {
  value_asdl::value_t* val = nullptr;
  StackRoot _root0(&default_);
  StackRoot _root1(&val);

  val = this->OptionalValue();
  if (val == nullptr) {
    return default_;
  }
  return this->_ToStr(val);
}

bool Reader::PosBool() {
  value_asdl::value_t* val = nullptr;
  StackRoot _root0(&val);

  val = this->PosValue();
  return this->_ToBool(val);
}

mops::BigInt Reader::PosInt() {
  value_asdl::value_t* val = nullptr;
  StackRoot _root0(&val);

  val = this->PosValue();
  return this->_ToInt(val);
}

mops::BigInt Reader::OptionalInt(int default_) {
  value_asdl::value_t* val = nullptr;
  StackRoot _root0(&val);

  val = this->OptionalValue();
  if (val == nullptr) {
    return mops::BigInt(default_);
  }
  return this->_ToInt(val);
}

double Reader::PosFloat() {
  value_asdl::value_t* val = nullptr;
  StackRoot _root0(&val);

  val = this->PosValue();
  return this->_ToFloat(val);
}

List<BigStr*>* Reader::PosBashArray() {
  value_asdl::value_t* val = nullptr;
  StackRoot _root0(&val);

  val = this->PosValue();
  return this->_ToBashArray(val);
}

value::SparseArray* Reader::PosSparseArray() {
  value_asdl::value_t* val = nullptr;
  StackRoot _root0(&val);

  val = this->PosValue();
  return this->_ToSparseArray(val);
}

List<value_asdl::value_t*>* Reader::PosList() {
  value_asdl::value_t* val = nullptr;
  StackRoot _root0(&val);

  val = this->PosValue();
  return this->_ToList(val);
}

Dict<BigStr*, value_asdl::value_t*>* Reader::PosDict() {
  value_asdl::value_t* val = nullptr;
  StackRoot _root0(&val);

  val = this->PosValue();
  return this->_ToDict(val);
}

value::Place* Reader::PosPlace() {
  value_asdl::value_t* val = nullptr;
  StackRoot _root0(&val);

  val = this->PosValue();
  return this->_ToPlace(val);
}

value::Eggex* Reader::PosEggex() {
  value_asdl::value_t* val = nullptr;
  StackRoot _root0(&val);

  val = this->PosValue();
  return this->_ToEggex(val);
}

value_asdl::RegexMatch* Reader::PosMatch() {
  value_asdl::value_t* val = nullptr;
  StackRoot _root0(&val);

  val = this->PosValue();
  return this->_ToMatch(val);
}

value::IO* Reader::PosIO() {
  value_asdl::value_t* val = nullptr;
  StackRoot _root0(&val);

  val = this->PosValue();
  return this->_ToIO(val);
}

syntax_asdl::command_t* Reader::PosCommand() {
  value_asdl::value_t* val = nullptr;
  StackRoot _root0(&val);

  val = this->PosValue();
  return this->_ToCommand(val);
}

syntax_asdl::expr_t* Reader::PosExpr() {
  value_asdl::value_t* val = nullptr;
  StackRoot _root0(&val);

  val = this->PosValue();
  return this->_ToExpr(val);
}

syntax_asdl::command_t* Reader::RequiredBlock() {
  if (this->block_arg == nullptr) {
    throw Alloc<error::TypeErrVerbose>(str1335, this->LeastSpecificLocation());
  }
  return this->_ToBlock(this->block_arg);
}

syntax_asdl::command_t* Reader::OptionalBlock() {
  if (this->block_arg == nullptr) {
    return nullptr;
  }
  return this->_ToBlock(this->block_arg);
}

syntax_asdl::LiteralBlock* Reader::OptionalLiteralBlock() {
  if (this->block_arg == nullptr) {
    return nullptr;
  }
  return this->_ToLiteralBlock(this->block_arg);
}

List<value_asdl::value_t*>* Reader::RestPos() {
  List<value_asdl::value_t*>* ret = nullptr;
  StackRoot _root0(&ret);

  ret = this->pos_args;
  this->pos_args = Alloc<List<value_asdl::value_t*>>();
  return ret;
}

syntax_asdl::loc_t* Reader::_BlameNamed(BigStr* name) {
  StackRoot _root0(&name);

  return this->LeastSpecificLocation();
}

BigStr* Reader::NamedStr(BigStr* param_name, BigStr* default_) {
  value_asdl::value_t* val = nullptr;
  value_asdl::value_t* UP_val = nullptr;
  StackRoot _root0(&param_name);
  StackRoot _root1(&default_);
  StackRoot _root2(&val);
  StackRoot _root3(&UP_val);

  if (!dict_contains(this->named_args, param_name)) {
    return default_;
  }
  val = this->named_args->at(param_name);
  UP_val = val;
  if (val->tag() == value_e::Str) {
    mylib::dict_erase(this->named_args, param_name);
    value::Str* val = static_cast<value::Str*>(UP_val);
    return val->s;
  }
  throw Alloc<error::TypeErr>(val, StrFormat("Named arg %r should be a Str", param_name), this->_BlameNamed(param_name));
}

bool Reader::NamedBool(BigStr* param_name, bool default_) {
  value_asdl::value_t* val = nullptr;
  value_asdl::value_t* UP_val = nullptr;
  StackRoot _root0(&param_name);
  StackRoot _root1(&val);
  StackRoot _root2(&UP_val);

  if (!dict_contains(this->named_args, param_name)) {
    return default_;
  }
  val = this->named_args->at(param_name);
  UP_val = val;
  if (val->tag() == value_e::Bool) {
    value::Bool* val = static_cast<value::Bool*>(UP_val);
    mylib::dict_erase(this->named_args, param_name);
    return val->b;
  }
  throw Alloc<error::TypeErr>(val, StrFormat("Named arg %r should be a Bool", param_name), this->_BlameNamed(param_name));
}

mops::BigInt Reader::NamedInt(BigStr* param_name, int default_) {
  value_asdl::value_t* val = nullptr;
  value_asdl::value_t* UP_val = nullptr;
  StackRoot _root0(&param_name);
  StackRoot _root1(&val);
  StackRoot _root2(&UP_val);

  if (!dict_contains(this->named_args, param_name)) {
    return mops::BigInt(default_);
  }
  val = this->named_args->at(param_name);
  UP_val = val;
  if (val->tag() == value_e::Int) {
    value::Int* val = static_cast<value::Int*>(UP_val);
    mylib::dict_erase(this->named_args, param_name);
    return val->i;
  }
  throw Alloc<error::TypeErr>(val, StrFormat("Named arg %r should be a Int", param_name), this->_BlameNamed(param_name));
}

double Reader::NamedFloat(BigStr* param_name, double default_) {
  value_asdl::value_t* val = nullptr;
  value_asdl::value_t* UP_val = nullptr;
  StackRoot _root0(&param_name);
  StackRoot _root1(&val);
  StackRoot _root2(&UP_val);

  if (!dict_contains(this->named_args, param_name)) {
    return default_;
  }
  val = this->named_args->at(param_name);
  UP_val = val;
  if (val->tag() == value_e::Float) {
    value::Float* val = static_cast<value::Float*>(UP_val);
    mylib::dict_erase(this->named_args, param_name);
    return val->f;
  }
  throw Alloc<error::TypeErr>(val, StrFormat("Named arg %r should be a Float", param_name), this->_BlameNamed(param_name));
}

List<value_asdl::value_t*>* Reader::NamedList(BigStr* param_name, List<value_asdl::value_t*>* default_) {
  value_asdl::value_t* val = nullptr;
  value_asdl::value_t* UP_val = nullptr;
  StackRoot _root0(&param_name);
  StackRoot _root1(&default_);
  StackRoot _root2(&val);
  StackRoot _root3(&UP_val);

  if (!dict_contains(this->named_args, param_name)) {
    return default_;
  }
  val = this->named_args->at(param_name);
  UP_val = val;
  if (val->tag() == value_e::List) {
    value::List* val = static_cast<value::List*>(UP_val);
    mylib::dict_erase(this->named_args, param_name);
    return val->items;
  }
  throw Alloc<error::TypeErr>(val, StrFormat("Named arg %r should be a List", param_name), this->_BlameNamed(param_name));
}

Dict<BigStr*, value_asdl::value_t*>* Reader::NamedDict(BigStr* param_name, Dict<BigStr*, value_asdl::value_t*>* default_) {
  value_asdl::value_t* val = nullptr;
  value_asdl::value_t* UP_val = nullptr;
  StackRoot _root0(&param_name);
  StackRoot _root1(&default_);
  StackRoot _root2(&val);
  StackRoot _root3(&UP_val);

  if (!dict_contains(this->named_args, param_name)) {
    return default_;
  }
  val = this->named_args->at(param_name);
  UP_val = val;
  if (val->tag() == value_e::Dict) {
    value::Dict* val = static_cast<value::Dict*>(UP_val);
    mylib::dict_erase(this->named_args, param_name);
    return val->d;
  }
  throw Alloc<error::TypeErr>(val, StrFormat("Named arg %r should be a Dict", param_name), this->_BlameNamed(param_name));
}

Dict<BigStr*, value_asdl::value_t*>* Reader::RestNamed() {
  Dict<BigStr*, value_asdl::value_t*>* ret = nullptr;
  StackRoot _root0(&ret);

  ret = this->named_args;
  this->named_args = Alloc<Dict<BigStr*, value_asdl::value_t*>>();
  return ret;
}

void Reader::Done() {
  int n;
  BigStr* bad_args = nullptr;
  syntax_asdl::loc_t* blame = nullptr;
  StackRoot _root0(&bad_args);
  StackRoot _root1(&blame);

  if (len(this->pos_args)) {
    n = this->pos_consumed;
    if (this->is_bound) {
      n -= 1;
    }
    this->pos_consumed += 1;
    throw Alloc<error::TypeErrVerbose>(StrFormat("Expected %d typed args, but got %d", n, (n + len(this->pos_args))), this->BlamePos());
  }
  if (len(this->named_args)) {
    bad_args = str1343->join(this->named_args->keys());
    blame = this->arg_list->semi_tok;
    if (blame == nullptr) {
      blame = this->LeastSpecificLocation();
    }
    throw Alloc<error::TypeErrVerbose>(StrFormat("Got unexpected named args: %s", bad_args), blame);
  }
}

}  // define namespace typed_args

namespace arith_parse {  // define

using id_kind_asdl::Id;
using syntax_asdl::loc;
using syntax_asdl::arith_expr;
using syntax_asdl::arith_expr_t;
using syntax_asdl::word_e;
using syntax_asdl::word_t;
using syntax_asdl::Token;
using error::p_die;

syntax_asdl::arith_expr_t* NullIncDec(tdop::TdopParser* p, syntax_asdl::word_t* w, int bp) {
  syntax_asdl::arith_expr_t* right = nullptr;
  StackRoot _root0(&p);
  StackRoot _root1(&w);
  StackRoot _root2(&right);

  right = p->ParseUntil(bp);
  tdop::CheckLhsExpr(right, w);
  return Alloc<arith_expr::UnaryAssign>(word_::ArithId(w), right);
}

syntax_asdl::arith_expr_t* NullUnaryPlus(tdop::TdopParser* p, syntax_asdl::word_t* t, int bp) {
  syntax_asdl::arith_expr_t* right = nullptr;
  StackRoot _root0(&p);
  StackRoot _root1(&t);
  StackRoot _root2(&right);

  right = p->ParseUntil(bp);
  return Alloc<arith_expr::Unary>(Id::Node_UnaryPlus, right);
}

syntax_asdl::arith_expr_t* NullUnaryMinus(tdop::TdopParser* p, syntax_asdl::word_t* t, int bp) {
  syntax_asdl::arith_expr_t* right = nullptr;
  StackRoot _root0(&p);
  StackRoot _root1(&t);
  StackRoot _root2(&right);

  right = p->ParseUntil(bp);
  return Alloc<arith_expr::Unary>(Id::Node_UnaryMinus, right);
}

syntax_asdl::arith_expr_t* LeftIncDec(tdop::TdopParser* p, syntax_asdl::word_t* w, syntax_asdl::arith_expr_t* left, int rbp) {
  int arith_id;
  int op_id;
  StackRoot _root0(&p);
  StackRoot _root1(&w);
  StackRoot _root2(&left);

  arith_id = word_::ArithId(w);
  if (arith_id == Id::Arith_DPlus) {
    op_id = Id::Node_PostDPlus;
  }
  else {
    if (arith_id == Id::Arith_DMinus) {
      op_id = Id::Node_PostDMinus;
    }
    else {
      assert(0);  // AssertionError
    }
  }
  tdop::CheckLhsExpr(left, w);
  return Alloc<arith_expr::UnaryAssign>(op_id, left);
}

syntax_asdl::arith_expr_t* LeftIndex(tdop::TdopParser* p, syntax_asdl::word_t* w, syntax_asdl::arith_expr_t* left, int unused_bp) {
  syntax_asdl::arith_expr_t* index = nullptr;
  Token* tok = nullptr;
  StackRoot _root0(&p);
  StackRoot _root1(&w);
  StackRoot _root2(&left);
  StackRoot _root3(&index);
  StackRoot _root4(&tok);

  if (!tdop::IsIndexable(left)) {
    p_die(str1345, Alloc<loc::Word>(w));
  }
  index = p->ParseUntil(0);
  p->Eat(Id::Arith_RBracket);
  tok = static_cast<Token*>(w);
  return Alloc<arith_expr::Binary>(tok, left, index);
}

syntax_asdl::arith_expr_t* LeftTernary(tdop::TdopParser* p, syntax_asdl::word_t* t, syntax_asdl::arith_expr_t* left, int bp) {
  syntax_asdl::arith_expr_t* true_expr = nullptr;
  syntax_asdl::arith_expr_t* false_expr = nullptr;
  StackRoot _root0(&p);
  StackRoot _root1(&t);
  StackRoot _root2(&left);
  StackRoot _root3(&true_expr);
  StackRoot _root4(&false_expr);

  true_expr = p->ParseUntil(0);
  p->Eat(Id::Arith_Colon);
  false_expr = p->ParseUntil(bp);
  return Alloc<arith_expr::TernaryOp>(left, true_expr, false_expr);
}

}  // define namespace arith_parse

namespace bool_parse {  // define

using id_kind_asdl::Id;
using id_kind_asdl::Kind;
using types_asdl::lex_mode_t;
using types_asdl::lex_mode_e;
using syntax_asdl::loc;
using syntax_asdl::word_t;
using syntax_asdl::word_e;
using syntax_asdl::bool_expr;
using syntax_asdl::bool_expr_t;
using syntax_asdl::Token;
using error::p_die;

BoolParser::BoolParser(word_parse::WordEmitter* w_parser) {
  this->w_parser = w_parser;
  this->words = Alloc<List<syntax_asdl::word_t*>>();
  this->cur_word = nullptr;
  this->bool_id = Id::Undefined_Tok;
  this->bool_kind = Kind::Undefined;
}

void BoolParser::_NextOne(types_asdl::lex_mode_t lex_mode) {
  int n;
  syntax_asdl::word_t* w = nullptr;
  StackRoot _root0(&w);

  n = len(this->words);
  if (n == 2) {
    this->words->set(0, this->words->at(1));
    this->cur_word = this->words->at(0);
    this->words->pop();
  }
  else {
    if ((n == 0 || n == 1)) {
      w = this->w_parser->ReadWord(lex_mode);
      if (n == 0) {
        this->words->append(w);
      }
      else {
        this->words->set(0, w);
      }
      this->cur_word = w;
    }
  }
  this->bool_id = word_::BoolId(this->cur_word);
  this->bool_kind = consts::GetKind(this->bool_id);
}

void BoolParser::_Next(types_asdl::lex_mode_t lex_mode) {
  while (true) {
    this->_NextOne(lex_mode);
    if (this->bool_id != Id::Op_Newline) {
      break;
    }
  }
}

syntax_asdl::word_t* BoolParser::_LookAhead() {
  int n;
  syntax_asdl::word_t* w = nullptr;
  StackRoot _root0(&w);

  n = len(this->words);
  if (n != 1) {
    assert(0);  // AssertionError
  }
  w = this->w_parser->ReadWord(lex_mode_e::DBracket);
  this->words->append(w);
  return w;
}

Tuple2<syntax_asdl::bool_expr_t*, syntax_asdl::Token*> BoolParser::Parse() {
  syntax_asdl::bool_expr_t* node = nullptr;
  syntax_asdl::Token* right = nullptr;
  StackRoot _root0(&node);
  StackRoot _root1(&right);

  this->_Next();
  node = this->ParseExpr();
  if (this->bool_id != Id::Lit_DRightBracket) {
    p_die(str1346, Alloc<loc::Word>(this->cur_word));
  }
  right = word_::LiteralToken(this->cur_word);
  return Tuple2<syntax_asdl::bool_expr_t*, syntax_asdl::Token*>(node, right);
}

bool BoolParser::_TestAtEnd() {
  return this->bool_id == Id::Lit_DRightBracket;
}

syntax_asdl::bool_expr_t* BoolParser::ParseForBuiltin() {
  syntax_asdl::bool_expr_t* node = nullptr;
  StackRoot _root0(&node);

  this->_Next();
  node = this->ParseExpr();
  if (this->bool_id != Id::Eof_Real) {
    p_die(StrFormat("Unexpected trailing word %s", word_::Pretty(this->cur_word)), Alloc<loc::Word>(this->cur_word));
  }
  return node;
}

syntax_asdl::bool_expr_t* BoolParser::ParseExpr() {
  syntax_asdl::bool_expr_t* left = nullptr;
  syntax_asdl::bool_expr_t* right = nullptr;
  StackRoot _root0(&left);
  StackRoot _root1(&right);

  left = this->ParseTerm();
  if ((this->bool_id == Id::Op_DPipe || this->bool_id == Id::BoolUnary_o)) {
    this->_Next();
    right = this->ParseExpr();
    return Alloc<bool_expr::LogicalOr>(left, right);
  }
  else {
    return left;
  }
}

syntax_asdl::bool_expr_t* BoolParser::ParseTerm() {
  syntax_asdl::bool_expr_t* left = nullptr;
  syntax_asdl::bool_expr_t* right = nullptr;
  StackRoot _root0(&left);
  StackRoot _root1(&right);

  left = this->ParseNegatedFactor();
  if ((this->bool_id == Id::Op_DAmp || this->bool_id == Id::BoolUnary_a)) {
    this->_Next();
    right = this->ParseTerm();
    return Alloc<bool_expr::LogicalAnd>(left, right);
  }
  else {
    return left;
  }
}

syntax_asdl::bool_expr_t* BoolParser::ParseNegatedFactor() {
  syntax_asdl::bool_expr_t* child = nullptr;
  StackRoot _root0(&child);

  if (this->bool_id == Id::KW_Bang) {
    this->_Next();
    child = this->ParseFactor();
    return Alloc<bool_expr::LogicalNot>(child);
  }
  else {
    return this->ParseFactor();
  }
}

syntax_asdl::bool_expr_t* BoolParser::ParseFactor() {
  int op;
  syntax_asdl::word_t* w = nullptr;
  int tag;
  syntax_asdl::CompoundWord* tilde = nullptr;
  syntax_asdl::bool_expr_t* node = nullptr;
  syntax_asdl::word_t* t2 = nullptr;
  int t2_bool_id;
  id_kind_asdl::Kind_t t2_bool_kind;
  syntax_asdl::word_t* left = nullptr;
  syntax_asdl::word_t* right = nullptr;
  StackRoot _root0(&w);
  StackRoot _root1(&tilde);
  StackRoot _root2(&node);
  StackRoot _root3(&t2);
  StackRoot _root4(&left);
  StackRoot _root5(&right);

  if (this->bool_kind == Kind::BoolUnary) {
    op = this->bool_id;
    this->_Next();
    w = this->cur_word;
    tag = w->tag();
    if ((tag != word_e::Compound and tag != word_e::String)) {
      p_die(str1348, Alloc<loc::Word>(w));
    }
    this->_Next();
    tilde = word_::TildeDetect(w);
    if (tilde) {
      w = tilde;
    }
    node = Alloc<bool_expr::Unary>(op, w);
    return node;
  }
  if (this->bool_kind == Kind::Word) {
    t2 = this->_LookAhead();
    t2_bool_id = word_::BoolId(t2);
    t2_bool_kind = consts::GetKind(t2_bool_id);
    if ((t2_bool_kind == Kind::BoolBinary or (t2_bool_id == Id::Op_Less || t2_bool_id == Id::Op_Great))) {
      left = this->cur_word;
      this->_Next();
      op = this->bool_id;
      if (t2_bool_id == Id::BoolBinary_EqualTilde) {
        this->_Next(lex_mode_e::BashRegex);
      }
      else {
        this->_Next();
      }
      right = this->cur_word;
      this->_Next();
      tilde = word_::TildeDetect(left);
      if (tilde) {
        left = tilde;
      }
      tilde = word_::TildeDetect(right);
      if (tilde) {
        right = tilde;
      }
      return Alloc<bool_expr::Binary>(op, left, right);
    }
    else {
      w = this->cur_word;
      tilde = word_::TildeDetect(w);
      if (tilde) {
        w = tilde;
      }
      this->_Next();
      return Alloc<bool_expr::WordTest>(w);
    }
  }
  if (this->bool_id == Id::Op_LParen) {
    this->_Next();
    node = this->ParseExpr();
    if (this->bool_id != Id::Op_RParen) {
      p_die(StrFormat("Expected ), got %s", word_::Pretty(this->cur_word)), Alloc<loc::Word>(this->cur_word));
    }
    this->_Next();
    return node;
  }
  p_die(StrFormat("Unexpected token in boolean expression (%s)", ui::PrettyId(this->bool_id)), Alloc<loc::Word>(this->cur_word));
}

}  // define namespace bool_parse

namespace braces {  // define

using id_kind_asdl::Id;
using id_kind_asdl::Id_t;
using syntax_asdl::Token;
using syntax_asdl::CompoundWord;
using syntax_asdl::word;
using syntax_asdl::word_e;
using syntax_asdl::word_t;
using syntax_asdl::word_part;
using syntax_asdl::word_part_e;
using syntax_asdl::word_part_t;
using error::p_die;
int NO_STEP = 0;

_NotARange::_NotARange(BigStr* s) {
  ;  // pass
}

_RangeParser::_RangeParser(match::SimpleLexer* lexer, syntax_asdl::Token* blame_tok) {
  this->lexer = lexer;
  this->blame_tok = blame_tok;
  this->token_type = Id::Undefined_Tok;
  this->token_val = str1351;
}

void _RangeParser::_Next() {
  Tuple2<int, BigStr*> tup0 = this->lexer->Next();
  this->token_type = tup0.at0();
  this->token_val = tup0.at1();
}

BigStr* _RangeParser::_Eat(int token_type) {
  BigStr* val = nullptr;
  StackRoot _root0(&val);

  if (this->token_type != token_type) {
    throw Alloc<_NotARange>(StrFormat("Expected %d, got %d", token_type, this->token_type));
  }
  val = this->token_val;
  this->_Next();
  return val;
}

int _RangeParser::_ParseStep() {
  int step;
  this->_Next();
  step = to_int(this->_Eat(Id::Range_Int));
  if (step == 0) {
    p_die(str1353, this->blame_tok);
  }
  return step;
}

word_part::BracedRange* _RangeParser::_ParseRange(int range_kind) {
  BigStr* start = nullptr;
  BigStr* end = nullptr;
  int step;
  word_part::BracedRange* part = nullptr;
  StackRoot _root0(&start);
  StackRoot _root1(&end);
  StackRoot _root2(&part);

  start = this->token_val;
  this->_Next();
  this->_Eat(Id::Range_Dots);
  end = this->_Eat(range_kind);
  if (this->token_type == Id::Range_Dots) {
    step = this->_ParseStep();
  }
  else {
    step = NO_STEP;
  }
  part = Alloc<word_part::BracedRange>(this->blame_tok, range_kind, start, end, step);
  return part;
}

word_part::BracedRange* _RangeParser::Parse() {
  word_part::BracedRange* part = nullptr;
  int start;
  int end;
  int start_num;
  int end_num;
  bool upper1;
  bool upper2;
  StackRoot _root0(&part);

  this->_Next();
  if (this->token_type == Id::Range_Int) {
    part = this->_ParseRange(this->token_type);
    start = to_int(part->start);
    end = to_int(part->end);
    if (start < end) {
      if (part->step == NO_STEP) {
        part->step = 1;
      }
      if (part->step <= 0) {
        p_die(StrFormat("Invalid step %d for ascending integer range", part->step), this->blame_tok);
      }
    }
    else {
      if (start > end) {
        if (part->step == NO_STEP) {
          part->step = -1;
        }
        if (part->step >= 0) {
          p_die(StrFormat("Invalid step %d for descending integer range", part->step), this->blame_tok);
        }
      }
      else {
        part->step = 1;
      }
    }
  }
  else {
    if (this->token_type == Id::Range_Char) {
      part = this->_ParseRange(this->token_type);
      start_num = ord(part->start->at(0));
      end_num = ord(part->end->at(0));
      if (start_num < end_num) {
        if (part->step == NO_STEP) {
          part->step = 1;
        }
        if (part->step <= 0) {
          p_die(StrFormat("Invalid step %d for ascending character range", part->step), this->blame_tok);
        }
      }
      else {
        if (start_num > end_num) {
          if (part->step == NO_STEP) {
            part->step = -1;
          }
          if (part->step >= 0) {
            p_die(StrFormat("Invalid step %d for descending character range", part->step), this->blame_tok);
          }
        }
        else {
          part->step = 1;
        }
      }
      upper1 = part->start->isupper();
      upper2 = part->end->isupper();
      if (upper1 != upper2) {
        p_die(str1358, this->blame_tok);
      }
    }
    else {
      throw Alloc<_NotARange>(str1359);
    }
  }
  this->_Eat(Id::Eol_Tok);
  return part;
}

word_part::BracedRange* _RangePartDetect(syntax_asdl::Token* tok) {
  match::SimpleLexer* lx = nullptr;
  braces::_RangeParser* p = nullptr;
  word_part::BracedRange* part = nullptr;
  StackRoot _root0(&tok);
  StackRoot _root1(&lx);
  StackRoot _root2(&p);
  StackRoot _root3(&part);

  lx = match::BraceRangeLexer(lexer::TokenVal(tok));
  p = Alloc<_RangeParser>(lx, tok);
  try {
    part = p->Parse();
  }
  catch (_NotARange* e) {
    return nullptr;
  }
  return part;
}

_StackFrame::_StackFrame(List<syntax_asdl::word_part_t*>* cur_parts) {
  this->cur_parts = cur_parts;
  this->alt_part = Alloc<word_part::BracedTuple>(Alloc<List<syntax_asdl::CompoundWord*>>());
  this->saw_comma = false;
}

word::BracedTree* BraceDetect(syntax_asdl::CompoundWord* w) {
  List<syntax_asdl::word_part_t*>* cur_parts = nullptr;
  List<braces::_StackFrame*>* stack = nullptr;
  bool found;
  int i;
  bool append;
  syntax_asdl::word_part_t* UP_part = nullptr;
  int id_;
  braces::_StackFrame* new_frame = nullptr;
  syntax_asdl::word_part_t* range_part = nullptr;
  syntax_asdl::word_part_t* part2 = nullptr;
  Token* tok = nullptr;
  braces::_StackFrame* frame = nullptr;
  StackRoot _root0(&w);
  StackRoot _root1(&cur_parts);
  StackRoot _root2(&stack);
  StackRoot _root3(&UP_part);
  StackRoot _root4(&new_frame);
  StackRoot _root5(&range_part);
  StackRoot _root6(&part2);
  StackRoot _root7(&tok);
  StackRoot _root8(&frame);

  cur_parts = Alloc<List<syntax_asdl::word_part_t*>>();
  stack = Alloc<List<braces::_StackFrame*>>();
  found = false;
  i = 0;
  for (ListIter<syntax_asdl::word_part_t*> it(w->parts); !it.Done(); it.Next(), ++i) {
    syntax_asdl::word_part_t* part = it.Value();
    StackRoot _for(&part  );
    append = true;
    UP_part = part;
    if (part->tag() == word_part_e::Literal) {
      Token* part = static_cast<Token*>(UP_part);
      id_ = part->id;
      if (id_ == Id::Lit_LBrace) {
        new_frame = Alloc<_StackFrame>(cur_parts);
        stack->append(new_frame);
        cur_parts = Alloc<List<syntax_asdl::word_part_t*>>();
        append = false;
        found = true;
      }
      else {
        if (id_ == Id::Lit_Comma) {
          if (len(stack)) {
            stack->at(-1)->saw_comma = true;
            stack->at(-1)->alt_part->words->append(Alloc<CompoundWord>(cur_parts));
            cur_parts = Alloc<List<syntax_asdl::word_part_t*>>();
            append = false;
          }
        }
        else {
          if (id_ == Id::Lit_RBrace) {
            if (len(stack) == 0) {
              return nullptr;
            }
            range_part = nullptr;
            if ((!stack->at(-1)->saw_comma and len(cur_parts) == 1)) {
              part2 = cur_parts->at(0);
              if (part2->tag() == word_part_e::Literal) {
                tok = static_cast<Token*>(part2);
                if (tok->id == Id::Lit_Chars) {
                  range_part = _RangePartDetect(tok);
                  if (range_part) {
                    frame = stack->pop();
                    cur_parts = frame->cur_parts;
                    cur_parts->append(range_part);
                    append = false;
                  }
                }
              }
            }
            if (!range_part) {
              if (!stack->at(-1)->saw_comma) {
                return nullptr;
              }
              stack->at(-1)->alt_part->words->append(Alloc<CompoundWord>(cur_parts));
              frame = stack->pop();
              cur_parts = frame->cur_parts;
              cur_parts->append(frame->alt_part);
              append = false;
            }
          }
        }
      }
    }
    if (append) {
      cur_parts->append(part);
    }
  }
  if (len(stack) != 0) {
    return nullptr;
  }
  if (found) {
    return Alloc<word::BracedTree>(cur_parts);
  }
  else {
    return nullptr;
  }
}

List<syntax_asdl::word_t*>* BraceDetectAll(List<syntax_asdl::CompoundWord*>* words) {
  List<syntax_asdl::word_t*>* out = nullptr;
  word::BracedTree* brace_tree = nullptr;
  StackRoot _root0(&words);
  StackRoot _root1(&out);
  StackRoot _root2(&brace_tree);

  out = Alloc<List<syntax_asdl::word_t*>>();
  for (ListIter<syntax_asdl::CompoundWord*> it(words); !it.Done(); it.Next()) {
    syntax_asdl::CompoundWord* w = it.Value();
    StackRoot _for(&w  );
    if (len(w->parts) >= 3) {
      brace_tree = BraceDetect(w);
      if (brace_tree) {
        out->append(brace_tree);
        continue;
      }
    }
    out->append(w);
  }
  return out;
}

int _LeadingZeros(BigStr* s) {
  int n;
  StackRoot _root0(&s);

  n = 0;
  for (StrIter it(s); !it.Done(); it.Next()) {
    BigStr* c = it.Value();
    StackRoot _for(&c  );
    if (str_equals(c, str1360)) {
      n += 1;
    }
    else {
      break;
    }
  }
  return n;
}

BigStr* _IntToString(int i, int width) {
  BigStr* s = nullptr;
  int n;
  BigStr* pad = nullptr;
  StackRoot _root0(&s);
  StackRoot _root1(&pad);

  s = str(i);
  n = len(s);
  if (n < width) {
    pad = str_repeat(str1361, (width - n));
    return str_concat(pad, s);
  }
  else {
    return s;
  }
}

List<BigStr*>* _RangeStrings(word_part::BracedRange* part) {
  List<BigStr*>* nums = nullptr;
  int z1;
  int z2;
  int width;
  int n;
  int end;
  int step;
  List<BigStr*>* chars = nullptr;
  int ord_end;
  StackRoot _root0(&part);
  StackRoot _root1(&nums);
  StackRoot _root2(&chars);

  if (part->kind == Id::Range_Int) {
    nums = Alloc<List<BigStr*>>();
    z1 = _LeadingZeros(part->start);
    z2 = _LeadingZeros(part->end);
    if ((z1 == 0 and z2 == 0)) {
      width = 0;
    }
    else {
      if (z1 < z2) {
        width = len(part->end);
      }
      else {
        width = len(part->start);
      }
    }
    n = to_int(part->start);
    end = to_int(part->end);
    step = part->step;
    if (step > 0) {
      while (true) {
        nums->append(_IntToString(n, width));
        n += step;
        if (n > end) {
          break;
        }
      }
    }
    else {
      while (true) {
        nums->append(_IntToString(n, width));
        n += step;
        if (n < end) {
          break;
        }
      }
    }
    return nums;
  }
  else {
    chars = Alloc<List<BigStr*>>();
    n = ord(part->start);
    ord_end = ord(part->end);
    step = part->step;
    if (step > 0) {
      while (true) {
        chars->append(chr(n));
        n += step;
        if (n > ord_end) {
          break;
        }
      }
    }
    else {
      while (true) {
        chars->append(chr(n));
        n += step;
        if (n < ord_end) {
          break;
        }
      }
    }
    return chars;
  }
}

List<List<syntax_asdl::word_part_t*>*>* _ExpandPart(List<syntax_asdl::word_part_t*>* parts, int first_alt_index, List<List<syntax_asdl::word_part_t*>*>* suffixes) {
  List<List<syntax_asdl::word_part_t*>*>* out = nullptr;
  List<syntax_asdl::word_part_t*>* prefix = nullptr;
  syntax_asdl::word_part_t* expand_part = nullptr;
  syntax_asdl::word_part_t* UP_part = nullptr;
  List<List<syntax_asdl::word_part_t*>*>* expanded_alts = nullptr;
  List<syntax_asdl::word_part_t*>* out_parts = nullptr;
  List<BigStr*>* strs = nullptr;
  List<syntax_asdl::word_part_t*>* out_parts_ = nullptr;
  syntax_asdl::Token* t = nullptr;
  StackRoot _root0(&parts);
  StackRoot _root1(&suffixes);
  StackRoot _root2(&out);
  StackRoot _root3(&prefix);
  StackRoot _root4(&expand_part);
  StackRoot _root5(&UP_part);
  StackRoot _root6(&expanded_alts);
  StackRoot _root7(&out_parts);
  StackRoot _root8(&strs);
  StackRoot _root9(&out_parts_);
  StackRoot _root10(&t);

  out = Alloc<List<List<syntax_asdl::word_part_t*>*>>();
  prefix = parts->slice(0, first_alt_index);
  expand_part = parts->at(first_alt_index);
  UP_part = expand_part;
  switch (expand_part->tag()) {
    case word_part_e::BracedTuple: {
      word_part::BracedTuple* expand_part = static_cast<word_part::BracedTuple*>(UP_part);
      expanded_alts = Alloc<List<List<syntax_asdl::word_part_t*>*>>();
      for (ListIter<syntax_asdl::CompoundWord*> it(expand_part->words); !it.Done(); it.Next()) {
        syntax_asdl::CompoundWord* w = it.Value();
        StackRoot _for(&w      );
        expanded_alts->extend(_BraceExpand(w->parts));
      }
      for (ListIter<List<syntax_asdl::word_part_t*>*> it(expanded_alts); !it.Done(); it.Next()) {
        List<syntax_asdl::word_part_t*>* alt_parts = it.Value();
        StackRoot _for(&alt_parts      );
        for (ListIter<List<syntax_asdl::word_part_t*>*> it(suffixes); !it.Done(); it.Next()) {
          List<syntax_asdl::word_part_t*>* suffix = it.Value();
          StackRoot _for(&suffix        );
          out_parts = Alloc<List<syntax_asdl::word_part_t*>>();
          out_parts->extend(prefix);
          out_parts->extend(alt_parts);
          out_parts->extend(suffix);
          out->append(out_parts);
        }
      }
    }
      break;
    case word_part_e::BracedRange: {
      word_part::BracedRange* expand_part = static_cast<word_part::BracedRange*>(UP_part);
      strs = _RangeStrings(expand_part);
      for (ListIter<BigStr*> it(strs); !it.Done(); it.Next()) {
        BigStr* s = it.Value();
        StackRoot _for(&s      );
        for (ListIter<List<syntax_asdl::word_part_t*>*> it(suffixes); !it.Done(); it.Next()) {
          List<syntax_asdl::word_part_t*>* suffix = it.Value();
          StackRoot _for(&suffix        );
          out_parts_ = Alloc<List<syntax_asdl::word_part_t*>>();
          out_parts_->extend(prefix);
          t = lexer::DummyToken(Id::Lit_Chars, s);
          out_parts_->append(t);
          out_parts_->extend(suffix);
          out->append(out_parts_);
        }
      }
    }
      break;
    default: {
      assert(0);  // AssertionError
    }
  }
  return out;
}

List<List<syntax_asdl::word_part_t*>*>* _BraceExpand(List<syntax_asdl::word_part_t*>* parts) {
  int num_alts;
  int first_alt_index;
  int i;
  int tag;
  List<syntax_asdl::word_part_t*>* suffix = nullptr;
  List<syntax_asdl::word_part_t*>* tail_parts = nullptr;
  List<List<syntax_asdl::word_part_t*>*>* suffixes = nullptr;
  StackRoot _root0(&parts);
  StackRoot _root1(&suffix);
  StackRoot _root2(&tail_parts);
  StackRoot _root3(&suffixes);

  mylib::MaybeCollect();
  num_alts = 0;
  first_alt_index = -1;
  i = 0;
  for (ListIter<syntax_asdl::word_part_t*> it(parts); !it.Done(); it.Next(), ++i) {
    syntax_asdl::word_part_t* part = it.Value();
    StackRoot _for(&part  );
    tag = part->tag();
    if ((tag == word_part_e::BracedTuple || tag == word_part_e::BracedRange)) {
      num_alts += 1;
      if (num_alts == 1) {
        first_alt_index = i;
      }
      else {
        if (num_alts == 2) {
          break;
        }
      }
    }
  }
  if (num_alts == 0) {
    return NewList<List<syntax_asdl::word_part_t*>*>(std::initializer_list<List<syntax_asdl::word_part_t*>*>{parts});
  }
  else {
    if (num_alts == 1) {
      suffix = parts->slice((first_alt_index + 1));
      return _ExpandPart(parts, first_alt_index, NewList<List<syntax_asdl::word_part_t*>*>(std::initializer_list<List<syntax_asdl::word_part_t*>*>{suffix}));
    }
    else {
      tail_parts = parts->slice((first_alt_index + 1));
      suffixes = _BraceExpand(tail_parts);
      return _ExpandPart(parts, first_alt_index, suffixes);
    }
  }
}

List<syntax_asdl::CompoundWord*>* BraceExpandWords(List<syntax_asdl::word_t*>* words) {
  List<syntax_asdl::CompoundWord*>* out = nullptr;
  syntax_asdl::word_t* UP_w = nullptr;
  List<List<syntax_asdl::word_part_t*>*>* parts_list = nullptr;
  syntax_asdl::CompoundWord* expanded = nullptr;
  syntax_asdl::CompoundWord* ti = nullptr;
  StackRoot _root0(&words);
  StackRoot _root1(&out);
  StackRoot _root2(&UP_w);
  StackRoot _root3(&parts_list);
  StackRoot _root4(&expanded);
  StackRoot _root5(&ti);

  out = Alloc<List<syntax_asdl::CompoundWord*>>();
  for (ListIter<syntax_asdl::word_t*> it(words); !it.Done(); it.Next()) {
    syntax_asdl::word_t* w = it.Value();
    StackRoot _for(&w  );
    UP_w = w;
    switch (w->tag()) {
      case word_e::BracedTree: {
        word::BracedTree* w = static_cast<word::BracedTree*>(UP_w);
        parts_list = _BraceExpand(w->parts);
        for (ListIter<List<syntax_asdl::word_part_t*>*> it(parts_list); !it.Done(); it.Next()) {
          List<syntax_asdl::word_part_t*>* parts = it.Value();
          StackRoot _for(&parts        );
          expanded = Alloc<CompoundWord>(parts);
          ti = word_::TildeDetect2(expanded);
          if (ti) {
            out->append(ti);
          }
          else {
            out->append(expanded);
          }
        }
      }
        break;
      case word_e::Compound: {
        CompoundWord* w = static_cast<CompoundWord*>(UP_w);
        out->append(w);
      }
        break;
      default: {
        assert(0);  // AssertionError
      }
    }
  }
  return out;
}

}  // define namespace braces

namespace cmd_eval {  // define

using id_kind_asdl::Id;
using option_asdl::option_i;
using syntax_asdl::IntParamBox;
using syntax_asdl::loc;
using syntax_asdl::loc_t;
using syntax_asdl::loc_e;
using syntax_asdl::Token;
using syntax_asdl::CompoundWord;
using syntax_asdl::command;
using syntax_asdl::command_e;
using syntax_asdl::command_t;
using syntax_asdl::command_str;
using syntax_asdl::condition;
using syntax_asdl::condition_e;
using syntax_asdl::condition_t;
using syntax_asdl::case_arg;
using syntax_asdl::case_arg_e;
using syntax_asdl::case_arg_t;
using syntax_asdl::BraceGroup;
using syntax_asdl::Proc;
using syntax_asdl::Func;
using syntax_asdl::assign_op_e;
using syntax_asdl::expr_t;
using syntax_asdl::proc_sig;
using syntax_asdl::proc_sig_e;
using syntax_asdl::redir_param;
using syntax_asdl::redir_param_e;
using syntax_asdl::for_iter;
using syntax_asdl::for_iter_e;
using syntax_asdl::pat;
using syntax_asdl::pat_e;
using syntax_asdl::word;
using syntax_asdl::Eggex;
using runtime_asdl::cmd_value;
using runtime_asdl::cmd_value_e;
using runtime_asdl::RedirValue;
using runtime_asdl::redirect_arg;
using runtime_asdl::flow_e;
using runtime_asdl::scope_e;
using runtime_asdl::CommandStatus;
using runtime_asdl::StatusArray;
using types_asdl::redir_arg_type_e;
using value_asdl::value;
using value_asdl::value_e;
using value_asdl::value_t;
using value_asdl::y_lvalue;
using value_asdl::y_lvalue_e;
using value_asdl::y_lvalue_t;
using value_asdl::LeftName;
using error::e_die;
using error::e_die_status;
int IsMainProgram = (1 << 0);
int RaiseControlFlow = (1 << 1);
int Optimize = (1 << 2);
int NoDebugTrap = (1 << 3);
int NoErrTrap = (1 << 4);

cmd_value::Argv* MakeBuiltinArgv(List<BigStr*>* argv1) {
  List<BigStr*>* argv = nullptr;
  syntax_asdl::CompoundWord* missing = nullptr;
  StackRoot _root0(&argv1);
  StackRoot _root1(&argv);
  StackRoot _root2(&missing);

  argv = NewList<BigStr*>(std::initializer_list<BigStr*>{str1362});
  argv->extend(argv1);
  missing = nullptr;
  return Alloc<cmd_value::Argv>(argv, list_repeat(missing, len(argv)), nullptr, nullptr, nullptr, nullptr);
}

Deps::Deps() {
  this->mutable_opts = nullptr;
  this->dumper = nullptr;
  this->debug_f = nullptr;
}

bool _HasManyStatuses(syntax_asdl::command_t* node) {
  syntax_asdl::command_t* UP_node = nullptr;
  StackRoot _root0(&node);
  StackRoot _root1(&UP_node);

  UP_node = node;
  switch (node->tag()) {
    case command_e::Simple: 
    case command_e::DBracket: 
    case command_e::DParen: {
      return false;
    }
      break;
    case command_e::Redirect: {
      command::Redirect* node = static_cast<command::Redirect*>(UP_node);
      return _HasManyStatuses(node->child);
    }
      break;
    case command_e::Sentence: {
      command::Sentence* node = static_cast<command::Sentence*>(UP_node);
      return _HasManyStatuses(node->child);
    }
      break;
    case command_e::Pipeline: {
      command::Pipeline* node = static_cast<command::Pipeline*>(UP_node);
      if (len(node->children) == 1) {
        return _HasManyStatuses(node->children->at(0));
      }
      else {
        return true;
      }
    }
      break;
  }
  return true;
}

value_asdl::value_t* PlusEquals(value_asdl::value_t* old_val, value_asdl::value_t* val) {
  value_asdl::value_t* UP_old_val = nullptr;
  value_asdl::value_t* UP_val = nullptr;
  int tag;
  List<BigStr*>* strs = nullptr;
  StackRoot _root0(&old_val);
  StackRoot _root1(&val);
  StackRoot _root2(&UP_old_val);
  StackRoot _root3(&UP_val);
  StackRoot _root4(&strs);

  UP_old_val = old_val;
  UP_val = val;
  tag = val->tag();
  switch (old_val->tag()) {
    case value_e::Undef: {
      ;  // pass
    }
      break;
    case value_e::Str: {
      if (tag == value_e::Str) {
        value::Str* old_val = static_cast<value::Str*>(UP_old_val);
        value::Str* str_to_append = static_cast<value::Str*>(UP_val);
        val = Alloc<value::Str>(str_concat(old_val->s, str_to_append->s));
      }
      else {
        if (tag == value_e::BashArray) {
          e_die(str1363);
        }
        else {
          assert(0);  // AssertionError
        }
      }
    }
      break;
    case value_e::BashArray: {
      if (tag == value_e::Str) {
        e_die(str1364);
      }
      else {
        if (tag == value_e::BashArray) {
          value::BashArray* old_val = static_cast<value::BashArray*>(UP_old_val);
          value::BashArray* to_append = static_cast<value::BashArray*>(UP_val);
          strs = Alloc<List<BigStr*>>();
          strs->extend(old_val->strs);
          strs->extend(to_append->strs);
          val = Alloc<value::BashArray>(strs);
        }
        else {
          assert(0);  // AssertionError
        }
      }
    }
      break;
    case value_e::BashAssoc: {
      ;  // pass
    }
      break;
    default: {
      e_die(StrFormat("Can't append to value of type %s", ui::ValType(old_val)));
    }
  }
  return val;
}

ctx_LoopLevel::ctx_LoopLevel(cmd_eval::CommandEvaluator* cmd_ev) {
  gHeap.PushRoot(reinterpret_cast<RawObject**>(&(this->cmd_ev)));
  cmd_ev->loop_level += 1;
  this->cmd_ev = cmd_ev;
}

ctx_LoopLevel::~ctx_LoopLevel() {
  this->cmd_ev->loop_level -= 1;
  gHeap.PopRoot();
}

CommandEvaluator::CommandEvaluator(state::Mem* mem, optview::Exec* exec_opts, ui::ErrorFormatter* errfmt, Dict<BigStr*, value::Proc*>* procs, Dict<int, vm::_AssignBuiltin*>* assign_builtins, alloc::Arena* arena, cmd_eval::Deps* cmd_deps, trap_osh::TrapState* trap_state, pyos::SignalSafe* signal_safe) {
  this->shell_ex = nullptr;
  this->arith_ev = nullptr;
  this->bool_ev = nullptr;
  this->expr_ev = nullptr;
  this->word_ev = nullptr;
  this->tracer = nullptr;
  this->mem = mem;
  this->exec_opts = exec_opts;
  this->errfmt = errfmt;
  this->procs = procs;
  this->assign_builtins = assign_builtins;
  this->arena = arena;
  this->mutable_opts = cmd_deps->mutable_opts;
  this->dumper = cmd_deps->dumper;
  this->debug_f = cmd_deps->debug_f;
  this->trap_state = trap_state;
  this->signal_safe = signal_safe;
  this->loop_level = 0;
  this->check_command_sub_status = false;
  this->status_array_pool = Alloc<List<runtime_asdl::StatusArray*>>();
}

void CommandEvaluator::CheckCircularDeps() {
}

int CommandEvaluator::_RunAssignBuiltin(cmd_value::Assign* cmd_val) {
  vm::_AssignBuiltin* builtin_func = nullptr;
  List<IOError_OSError*>* io_errors = nullptr;
  int status;
  BigStr* arg0 = nullptr;
  StackRoot _root0(&cmd_val);
  StackRoot _root1(&builtin_func);
  StackRoot _root2(&io_errors);
  StackRoot _root3(&arg0);

  builtin_func = this->assign_builtins->get(cmd_val->builtin_id);
  if (builtin_func == nullptr) {
    e_die(StrFormat("Assignment builtin %r not configured", cmd_val->argv->at(0)), cmd_val->arg_locs->at(0));
  }
  io_errors = Alloc<List<IOError_OSError*>>();
  {  // with
    vm::ctx_FlushStdout ctx{io_errors};

    {  // with
      ui::ctx_Location ctx{this->errfmt, cmd_val->arg_locs->at(0)};

      try {
        status = builtin_func->Run(cmd_val);
      }
      catch (IOError_OSError* e) {
        this->errfmt->PrintMessage(StrFormat("%s builtin I/O error: %s", cmd_val->argv->at(0), pyutil::strerror(e)), cmd_val->arg_locs->at(0));
        return 1;
      }
      catch (error::Usage* e) {
        arg0 = cmd_val->argv->at(0);
        this->errfmt->PrefixPrint(e->msg, StrFormat("%r ", arg0), e->location);
        return 2;
      }
    }
  }
  if (len(io_errors)) {
    this->errfmt->PrintMessage(StrFormat("%s builtin I/O: %s", cmd_val->argv->at(0), pyutil::strerror(io_errors->at(0))), cmd_val->arg_locs->at(0));
    return 1;
  }
  return status;
}

void CommandEvaluator::_CheckStatus(int status, runtime_asdl::CommandStatus* cmd_st, syntax_asdl::command_t* node, syntax_asdl::loc_t* default_loc) {
  syntax_asdl::command_t* UP_node = nullptr;
  BigStr* desc = nullptr;
  syntax_asdl::loc_t* blame_loc = nullptr;
  BigStr* msg = nullptr;
  StackRoot _root0(&cmd_st);
  StackRoot _root1(&node);
  StackRoot _root2(&default_loc);
  StackRoot _root3(&UP_node);
  StackRoot _root4(&desc);
  StackRoot _root5(&blame_loc);
  StackRoot _root6(&msg);

  if (status == 0) {
    return ;
  }
  this->_MaybeRunErrTrap();
  if (this->exec_opts->errexit()) {
    UP_node = node;
    switch (node->tag()) {
      case command_e::ShAssignment: {
        command::ShAssignment* node = static_cast<command::ShAssignment*>(UP_node);
        cmd_st->show_code = true;
      }
        break;
      case command_e::Subshell: {
        command::Subshell* node = static_cast<command::Subshell*>(UP_node);
        cmd_st->show_code = true;
      }
        break;
      case command_e::Pipeline: {
        command::Pipeline* node = static_cast<command::Pipeline*>(UP_node);
        cmd_st->show_code = true;
      }
        break;
    }
    desc = command_str(node->tag());
    if (default_loc->tag() != loc_e::Missing) {
      blame_loc = default_loc;
    }
    else {
      blame_loc = location::TokenForCommand(node);
    }
    msg = StrFormat("%s failed with status %d", desc, status);
    throw Alloc<error::ErrExit>(status, msg, blame_loc, cmd_st->show_code);
  }
}

runtime_asdl::RedirValue* CommandEvaluator::_EvalRedirect(syntax_asdl::Redir* r) {
  runtime_asdl::RedirValue* result = nullptr;
  syntax_asdl::redir_param_t* arg = nullptr;
  syntax_asdl::redir_param_t* UP_arg = nullptr;
  types_asdl::redir_arg_type_t redir_type;
  word::BracedTree* b = nullptr;
  List<BigStr*>* files = nullptr;
  int n;
  value::Str* val = nullptr;
  BigStr* t = nullptr;
  int target_fd;
  syntax_asdl::CompoundWord* w = nullptr;
  StackRoot _root0(&r);
  StackRoot _root1(&result);
  StackRoot _root2(&arg);
  StackRoot _root3(&UP_arg);
  StackRoot _root4(&b);
  StackRoot _root5(&files);
  StackRoot _root6(&val);
  StackRoot _root7(&t);
  StackRoot _root8(&w);

  result = Alloc<RedirValue>(r->op->id, r->op, r->loc, nullptr);
  arg = r->arg;
  UP_arg = arg;
  switch (arg->tag()) {
    case redir_param_e::Word: {
      CompoundWord* arg_word = static_cast<CompoundWord*>(UP_arg);
      this->mem->SetTokenForLine(r->op);
      redir_type = consts::RedirArgType(r->op->id);
      if (redir_type == redir_arg_type_e::Path) {
        b = braces::BraceDetect(arg_word);
        if (b != nullptr) {
          throw Alloc<error::RedirectEval>(str1371, arg_word);
        }
        files = this->word_ev->EvalWordSequence(NewList<syntax_asdl::CompoundWord*>(std::initializer_list<syntax_asdl::CompoundWord*>{arg_word}));
        n = len(files);
        if (n == 0) {
          throw Alloc<error::RedirectEval>(str1372, arg_word);
        }
        if (n > 1) {
          throw Alloc<error::RedirectEval>(str1373, arg_word);
        }
        result->arg = Alloc<redirect_arg::Path>(files->at(0));
        return result;
      }
      else {
        if (redir_type == redir_arg_type_e::Desc) {
          val = this->word_ev->EvalWordToString(arg_word);
          t = val->s;
          if (len(t) == 0) {
            throw Alloc<error::RedirectEval>(str1374, arg_word);
            return nullptr;
          }
          try {
            if (str_equals(t, str1375)) {
              result->arg = redirect_arg::CloseFd;
            }
            else {
              if (str_equals(t->at(-1), str1376)) {
                target_fd = to_int(t->slice(0, -1));
                result->arg = Alloc<redirect_arg::MoveFd>(target_fd);
              }
              else {
                result->arg = Alloc<redirect_arg::CopyFd>(to_int(t));
              }
            }
          }
          catch (ValueError*) {
            throw Alloc<error::RedirectEval>(StrFormat("Invalid descriptor %r.  Expected D, -, or D- where D is an integer", t), arg_word);
            return nullptr;
          }
          return result;
        }
        else {
          if (redir_type == redir_arg_type_e::Here) {
            val = this->word_ev->EvalWordToString(arg_word);
            result->arg = Alloc<redirect_arg::HereDoc>(str_concat(val->s, str1378));
            return result;
          }
          else {
            assert(0);  // AssertionError
          }
        }
      }
    }
      break;
    case redir_param_e::HereDoc: {
      redir_param::HereDoc* arg = static_cast<redir_param::HereDoc*>(UP_arg);
      w = Alloc<CompoundWord>(arg->stdin_parts);
      val = this->word_ev->EvalWordToString(w);
      result->arg = Alloc<redirect_arg::HereDoc>(val->s);
      return result;
    }
      break;
    default: {
      assert(0);  // AssertionError
    }
  }
  assert(0);  // AssertionError
}

int CommandEvaluator::_RunSimpleCommand(runtime_asdl::cmd_value_t* cmd_val, runtime_asdl::CommandStatus* cmd_st, int run_flags) {
  runtime_asdl::cmd_value_t* UP_cmd_val = nullptr;
  StackRoot _root0(&cmd_val);
  StackRoot _root1(&cmd_st);
  StackRoot _root2(&UP_cmd_val);

  UP_cmd_val = cmd_val;
  switch (UP_cmd_val->tag()) {
    case cmd_value_e::Argv: {
      cmd_value::Argv* cmd_val = static_cast<cmd_value::Argv*>(UP_cmd_val);
      this->tracer->OnSimpleCommand(cmd_val->argv);
      return this->shell_ex->RunSimpleCommand(cmd_val, cmd_st, run_flags);
    }
      break;
    case cmd_value_e::Assign: {
      cmd_value::Assign* cmd_val = static_cast<cmd_value::Assign*>(UP_cmd_val);
      this->tracer->OnAssignBuiltin(cmd_val);
      return this->_RunAssignBuiltin(cmd_val);
    }
      break;
    default: {
      assert(0);  // AssertionError
    }
  }
}

void CommandEvaluator::_EvalTempEnv(List<syntax_asdl::EnvPair*>* more_env, int flags) {
  value_asdl::value_t* val = nullptr;
  StackRoot _root0(&more_env);
  StackRoot _root1(&val);

  for (ListIter<syntax_asdl::EnvPair*> it(more_env); !it.Done(); it.Next()) {
    syntax_asdl::EnvPair* e_pair = it.Value();
    StackRoot _for(&e_pair  );
    val = this->word_ev->EvalRhsWord(e_pair->val);
    this->mem->SetNamed(location::LName(e_pair->name), val, scope_e::LocalOnly, flags);
  }
}

void CommandEvaluator::_StrictErrExit(syntax_asdl::command_t* node) {
  BigStr* node_str = nullptr;
  StackRoot _root0(&node);
  StackRoot _root1(&node_str);

  if (!(this->exec_opts->errexit() and this->exec_opts->strict_errexit())) {
    return ;
  }
  if (_HasManyStatuses(node)) {
    node_str = ui::CommandType(node);
    e_die(StrFormat("strict_errexit only allows simple commands in conditionals (got %s). ", node_str), Alloc<loc::Command>(node));
  }
}

void CommandEvaluator::_StrictErrExitList(List<syntax_asdl::command_t*>* node_list) {
  syntax_asdl::command_t* node = nullptr;
  BigStr* node_str = nullptr;
  StackRoot _root0(&node_list);
  StackRoot _root1(&node);
  StackRoot _root2(&node_str);

  if (!(this->exec_opts->errexit() and this->exec_opts->strict_errexit())) {
    return ;
  }
  if (len(node_list) > 1) {
    e_die(str1383, Alloc<loc::Command>(node_list->at(0)));
  }
  node = node_list->at(0);
  if (_HasManyStatuses(node)) {
    node_str = ui::CommandType(node);
    e_die(StrFormat("strict_errexit only allows simple commands in conditionals (got %s). ", node_str), Alloc<loc::Command>(node));
  }
}

bool CommandEvaluator::_EvalCondition(syntax_asdl::condition_t* cond, syntax_asdl::Token* blame_tok) {
  bool b;
  syntax_asdl::condition_t* UP_cond = nullptr;
  int cond_status;
  value_asdl::value_t* obj = nullptr;
  StackRoot _root0(&cond);
  StackRoot _root1(&blame_tok);
  StackRoot _root2(&UP_cond);
  StackRoot _root3(&obj);

  b = false;
  UP_cond = cond;
  switch (cond->tag()) {
    case condition_e::Shell: {
      condition::Shell* cond = static_cast<condition::Shell*>(UP_cond);
      this->_StrictErrExitList(cond->commands);
      {  // with
        state::ctx_ErrExit ctx{this->mutable_opts, false, blame_tok};

        cond_status = this->_ExecuteList(cond->commands);
      }
      b = cond_status == 0;
    }
      break;
    case condition_e::YshExpr: {
      condition::YshExpr* cond = static_cast<condition::YshExpr*>(UP_cond);
      obj = this->expr_ev->EvalExpr(cond->e, blame_tok);
      b = val_ops::ToBool(obj);
    }
      break;
  }
  return b;
}

value_asdl::value_t* CommandEvaluator::_EvalCaseArg(syntax_asdl::case_arg_t* arg, syntax_asdl::loc_t* blame) {
  syntax_asdl::case_arg_t* UP_arg = nullptr;
  StackRoot _root0(&arg);
  StackRoot _root1(&blame);
  StackRoot _root2(&UP_arg);

  UP_arg = arg;
  switch (arg->tag()) {
    case case_arg_e::Word: {
      case_arg::Word* arg = static_cast<case_arg::Word*>(UP_arg);
      return this->word_ev->EvalWordToString(arg->w);
    }
      break;
    case case_arg_e::YshExpr: {
      case_arg::YshExpr* arg = static_cast<case_arg::YshExpr*>(UP_arg);
      return this->expr_ev->EvalExpr(arg->e, blame);
    }
      break;
    default: {
      FAIL(kNotImplemented);  // Python NotImplementedError
    }
  }
}

int CommandEvaluator::_DoVarDecl(command::VarDecl* node) {
  syntax_asdl::NameType* lhs0 = nullptr;
  value_asdl::LeftName* lval = nullptr;
  value_asdl::value_t* val = nullptr;
  int flags;
  int i;
  value_asdl::value_t* right_val = nullptr;
  List<value_asdl::LeftName*>* lvals = nullptr;
  List<value_asdl::value_t*>* rhs_vals = nullptr;
  int num_lhs;
  List<value_asdl::value_t*>* items = nullptr;
  int num_rhs;
  value_asdl::value_t* rval = nullptr;
  StackRoot _root0(&node);
  StackRoot _root1(&lhs0);
  StackRoot _root2(&lval);
  StackRoot _root3(&val);
  StackRoot _root4(&right_val);
  StackRoot _root5(&lvals);
  StackRoot _root6(&rhs_vals);
  StackRoot _root7(&items);
  StackRoot _root8(&rval);

  if (node->keyword == nullptr) {
    lhs0 = node->lhs->at(0);
    lval = Alloc<LeftName>(lhs0->name, lhs0->left);
    val = this->expr_ev->EvalExpr(node->rhs, loc::Missing);
    this->mem->SetNamed(lval, val, scope_e::LocalOnly, state::SetReadOnly);
  }
  else {
    flags = node->keyword->id == Id::KW_Const ? state::SetReadOnly : 0;
    if (node->rhs == nullptr) {
      i = 0;
      for (ListIter<syntax_asdl::NameType*> it(node->lhs); !it.Done(); it.Next(), ++i) {
        syntax_asdl::NameType* lhs_val = it.Value();
        StackRoot _for(&lhs_val      );
        lval = Alloc<LeftName>(lhs_val->name, lhs_val->left);
        this->mem->SetNamed(lval, value::Null, scope_e::LocalOnly, flags);
      }
      return 0;
    }
    right_val = this->expr_ev->EvalExpr(node->rhs, loc::Missing);
    lvals = nullptr;
    rhs_vals = nullptr;
    num_lhs = len(node->lhs);
    if (num_lhs == 1) {
      lhs0 = node->lhs->at(0);
      lvals = NewList<value_asdl::LeftName*>(std::initializer_list<value_asdl::LeftName*>{Alloc<LeftName>(lhs0->name, lhs0->left)});
      rhs_vals = NewList<value_asdl::value_t*>(std::initializer_list<value_asdl::value_t*>{right_val});
    }
    else {
      items = val_ops::ToList(right_val, str1385, node->keyword);
      num_rhs = len(items);
      if (num_lhs != num_rhs) {
        throw Alloc<error::Expr>(StrFormat("Got %d places on the left, but %d values on right", num_lhs, num_rhs), node->keyword);
      }
      lvals = Alloc<List<value_asdl::LeftName*>>();
      rhs_vals = Alloc<List<value_asdl::value_t*>>();
      i = 0;
      for (ListIter<syntax_asdl::NameType*> it(node->lhs); !it.Done(); it.Next(), ++i) {
        syntax_asdl::NameType* lhs_val = it.Value();
        StackRoot _for(&lhs_val      );
        lval = Alloc<LeftName>(lhs_val->name, lhs_val->left);
        lvals->append(lval);
        rhs_vals->append(items->at(i));
      }
    }
    i = 0;
    for (ListIter<value_asdl::LeftName*> it(lvals); !it.Done(); it.Next(), ++i) {
      value_asdl::LeftName* lval = it.Value();
      StackRoot _for(&lval    );
      rval = rhs_vals->at(i);
      this->mem->SetNamed(lval, rval, scope_e::LocalOnly, flags);
    }
  }
  return 0;
}

void CommandEvaluator::_DoMutation(command::Mutation* node) {
  runtime_asdl::scope_t which_scopes;
  value_asdl::value_t* right_val = nullptr;
  List<value_asdl::y_lvalue_t*>* lvals = nullptr;
  List<value_asdl::value_t*>* rhs_vals = nullptr;
  int num_lhs;
  List<value_asdl::value_t*>* items = nullptr;
  int num_rhs;
  int i;
  value_asdl::value_t* rval = nullptr;
  value_asdl::y_lvalue_t* UP_lval = nullptr;
  value_asdl::value_t* obj = nullptr;
  value_asdl::value_t* UP_obj = nullptr;
  int index;
  BigStr* key = nullptr;
  value_asdl::y_lvalue_t* aug_lval = nullptr;
  value_asdl::value_t* val = nullptr;
  StackRoot _root0(&node);
  StackRoot _root1(&right_val);
  StackRoot _root2(&lvals);
  StackRoot _root3(&rhs_vals);
  StackRoot _root4(&items);
  StackRoot _root5(&rval);
  StackRoot _root6(&UP_lval);
  StackRoot _root7(&obj);
  StackRoot _root8(&UP_obj);
  StackRoot _root9(&key);
  StackRoot _root10(&aug_lval);
  StackRoot _root11(&val);

  switch (node->keyword->id) {
    case Id::KW_SetVar: {
      which_scopes = scope_e::LocalOnly;
    }
      break;
    case Id::KW_SetGlobal: {
      which_scopes = scope_e::GlobalOnly;
    }
      break;
    default: {
      assert(0);  // AssertionError
    }
  }
  if (node->op->id == Id::Arith_Equal) {
    right_val = this->expr_ev->EvalExpr(node->rhs, loc::Missing);
    lvals = nullptr;
    rhs_vals = nullptr;
    num_lhs = len(node->lhs);
    if (num_lhs == 1) {
      lvals = NewList<value_asdl::y_lvalue_t*>(std::initializer_list<value_asdl::y_lvalue_t*>{this->expr_ev->EvalLhsExpr(node->lhs->at(0), which_scopes)});
      rhs_vals = NewList<value_asdl::value_t*>(std::initializer_list<value_asdl::value_t*>{right_val});
    }
    else {
      items = val_ops::ToList(right_val, str1387, node->keyword);
      num_rhs = len(items);
      if (num_lhs != num_rhs) {
        throw Alloc<error::Expr>(StrFormat("Got %d places on the left, but %d values on the right", num_lhs, num_rhs), node->keyword);
      }
      lvals = Alloc<List<value_asdl::y_lvalue_t*>>();
      rhs_vals = Alloc<List<value_asdl::value_t*>>();
      i = 0;
      for (ListIter<syntax_asdl::y_lhs_t*> it(node->lhs); !it.Done(); it.Next(), ++i) {
        syntax_asdl::y_lhs_t* lhs_val = it.Value();
        StackRoot _for(&lhs_val      );
        lvals->append(this->expr_ev->EvalLhsExpr(lhs_val, which_scopes));
        rhs_vals->append(items->at(i));
      }
    }
    i = 0;
    for (ListIter<value_asdl::y_lvalue_t*> it(lvals); !it.Done(); it.Next(), ++i) {
      value_asdl::y_lvalue_t* lval = it.Value();
      StackRoot _for(&lval    );
      rval = rhs_vals->at(i);
      UP_lval = lval;
      if (lval->tag() == y_lvalue_e::Local) {
        LeftName* lval = static_cast<LeftName*>(UP_lval);
        this->mem->SetNamed(lval, rval, which_scopes);
      }
      else {
        if (lval->tag() == y_lvalue_e::Container) {
          y_lvalue::Container* lval = static_cast<y_lvalue::Container*>(UP_lval);
          obj = lval->obj;
          UP_obj = obj;
          switch (obj->tag()) {
            case value_e::List: {
              value::List* obj = static_cast<value::List*>(UP_obj);
              index = val_ops::ToInt(lval->index, str1389, loc::Missing);
              obj->items->set(index, rval);
            }
              break;
            case value_e::Dict: {
              value::Dict* obj = static_cast<value::Dict*>(UP_obj);
              key = val_ops::ToStr(lval->index, str1390, loc::Missing);
              obj->d->set(key, rval);
            }
              break;
            default: {
              throw Alloc<error::TypeErr>(obj, str1391, loc::Missing);
            }
          }
        }
        else {
          assert(0);  // AssertionError
        }
      }
    }
  }
  else {
    aug_lval = this->expr_ev->EvalLhsExpr(node->lhs->at(0), which_scopes);
    val = this->expr_ev->EvalExpr(node->rhs, loc::Missing);
    this->expr_ev->EvalAugmented(aug_lval, val, node->op, which_scopes);
  }
}

int CommandEvaluator::_DoSimple(command::Simple* node, runtime_asdl::CommandStatus* cmd_st) {
  List<syntax_asdl::CompoundWord*>* words = nullptr;
  runtime_asdl::cmd_value_t* cmd_val = nullptr;
  runtime_asdl::cmd_value_t* UP_cmd_val = nullptr;
  int run_flags;
  bool is_other_special;
  int status;
  StackRoot _root0(&node);
  StackRoot _root1(&cmd_st);
  StackRoot _root2(&words);
  StackRoot _root3(&cmd_val);
  StackRoot _root4(&UP_cmd_val);

  DTRACE_PROBE(cmd_eval, _DoSimple_enter);
  words = braces::BraceExpandWords(node->words);
  cmd_val = this->word_ev->EvalWordSequence2(words, true);
  UP_cmd_val = cmd_val;
  if (UP_cmd_val->tag() == cmd_value_e::Argv) {
    cmd_value::Argv* cmd_val = static_cast<cmd_value::Argv*>(UP_cmd_val);
    if (len(cmd_val->argv)) {
      this->mem->SetLastArgument(cmd_val->argv->at(-1));
    }
    else {
      this->mem->SetLastArgument(str1392);
    }
    if ((node->typed_args or node->block)) {
      func_proc::EvalTypedArgsToProc(this->expr_ev, this->mutable_opts, node, cmd_val);
    }
  }
  else {
    if (node->block) {
      e_die(str1393, node->block->brace_group->left);
    }
    cmd_value::Assign* cmd_val = static_cast<cmd_value::Assign*>(UP_cmd_val);
  }
  run_flags = node->do_fork ? executor::DO_FORK : 0;
  if (len(node->more_env)) {
    is_other_special = false;
    if ((cmd_val->tag() == cmd_value_e::Assign or is_other_special)) {
      this->_EvalTempEnv(node->more_env, 0);
      status = this->_RunSimpleCommand(cmd_val, cmd_st, run_flags);
    }
    else {
      {  // with
        state::ctx_Temp ctx{this->mem};

        this->_EvalTempEnv(node->more_env, state::SetExport);
        status = this->_RunSimpleCommand(cmd_val, cmd_st, run_flags);
      }
    }
  }
  else {
    status = this->_RunSimpleCommand(cmd_val, cmd_st, run_flags);
  }
  DTRACE_PROBE1(cmd_eval, _DoSimple_exit, status);
  return status;
}

int CommandEvaluator::_DoExpandedAlias(command::ExpandedAlias* node) {
  StackRoot _root0(&node);

  if (len(node->more_env)) {
    {  // with
      state::ctx_Temp ctx{this->mem};

      this->_EvalTempEnv(node->more_env, state::SetExport);
      return this->_Execute(node->child);
    }
  }
  else {
    return this->_Execute(node->child);
  }
}

int CommandEvaluator::_DoPipeline(command::Pipeline* node, runtime_asdl::CommandStatus* cmd_st) {
  int status;
  int tmp_status;
  StackRoot _root0(&node);
  StackRoot _root1(&cmd_st);

  cmd_st->check_errexit = true;
  for (ListIter<syntax_asdl::Token*> it(node->ops); !it.Done(); it.Next()) {
    syntax_asdl::Token* op = it.Value();
    StackRoot _for(&op  );
    if (op->id != Id::Op_Pipe) {
      e_die(str1394, op);
    }
  }
  this->mem->SetLastArgument(str1395);
  status = -1;
  if (node->negated != nullptr) {
    this->_StrictErrExit(node);
    {  // with
      state::ctx_ErrExit ctx{this->mutable_opts, false, node->negated};

      if (len(node->children) == 1) {
        tmp_status = this->_Execute(node->children->at(0));
        status = tmp_status == 0 ? 1 : 0;
      }
      else {
        this->shell_ex->RunPipeline(node, cmd_st);
        cmd_st->pipe_negated = true;
      }
    }
    cmd_st->check_errexit = false;
  }
  else {
    this->shell_ex->RunPipeline(node, cmd_st);
  }
  return status;
}

int CommandEvaluator::_DoShAssignment(command::ShAssignment* node, runtime_asdl::CommandStatus* cmd_st) {
  runtime_asdl::scope_t which_scopes;
  value_asdl::value_t* rhs = nullptr;
  value_asdl::sh_lvalue_t* lval = nullptr;
  value_asdl::value_t* old_val = nullptr;
  value_asdl::value_t* val = nullptr;
  int flags;
  int last_status;
  StackRoot _root0(&node);
  StackRoot _root1(&cmd_st);
  StackRoot _root2(&rhs);
  StackRoot _root3(&lval);
  StackRoot _root4(&old_val);
  StackRoot _root5(&val);

  which_scopes = this->mem->ScopesForWriting();
  for (ListIter<syntax_asdl::AssignPair*> it(node->pairs); !it.Done(); it.Next()) {
    syntax_asdl::AssignPair* pair = it.Value();
    StackRoot _for(&pair  );
    if (pair->op == assign_op_e::PlusEqual) {
      rhs = this->word_ev->EvalRhsWord(pair->rhs);
      lval = this->arith_ev->EvalShellLhs(pair->lhs, which_scopes);
      old_val = sh_expr_eval::OldValue(lval, this->mem, nullptr);
      val = PlusEquals(old_val, rhs);
    }
    else {
      lval = this->arith_ev->EvalShellLhs(pair->lhs, which_scopes);
      if (pair->rhs) {
        val = this->word_ev->EvalRhsWord(pair->rhs);
      }
      else {
        val = nullptr;
      }
    }
    flags = 0;
    this->mem->SetValue(lval, val, which_scopes, flags);
    this->tracer->OnShAssignment(lval, pair->op, val, flags, which_scopes);
  }
  if (this->check_command_sub_status) {
    last_status = this->mem->LastStatus();
    this->_CheckStatus(last_status, cmd_st, node, loc::Missing);
    return last_status;
  }
  else {
    return 0;
  }
}

int CommandEvaluator::_DoExpr(command::Expr* node) {
  value_asdl::value_t* val = nullptr;
  List<IOError_OSError*>* io_errors = nullptr;
  StackRoot _root0(&node);
  StackRoot _root1(&val);
  StackRoot _root2(&io_errors);

  val = this->expr_ev->EvalExpr(node->e, loc::Missing);
  if (node->keyword->id == Id::Lit_Equals) {
    io_errors = Alloc<List<IOError_OSError*>>();
    {  // with
      vm::ctx_FlushStdout ctx{io_errors};

      try {
        ui::PrettyPrintValue(val, mylib::Stdout());
      }
      catch (IOError_OSError* e) {
        this->errfmt->PrintMessage(StrFormat("I/O error during = keyword: %s", pyutil::strerror(e)), node->keyword);
        return 1;
      }
    }
    if (len(io_errors)) {
      this->errfmt->PrintMessage(StrFormat("I/O error during = keyword: %s", pyutil::strerror(io_errors->at(0))), node->keyword);
      return 1;
    }
  }
  return 0;
}

int CommandEvaluator::_DoControlFlow(command::ControlFlow* node) {
  syntax_asdl::Token* keyword = nullptr;
  value::Str* str_val = nullptr;
  int arg;
  BigStr* msg = nullptr;
  StackRoot _root0(&node);
  StackRoot _root1(&keyword);
  StackRoot _root2(&str_val);
  StackRoot _root3(&msg);

  keyword = node->keyword;
  if (node->arg_word) {
    str_val = this->word_ev->EvalWordToString(node->arg_word);
    if ((len(str_val->s) == 0 and !this->exec_opts->strict_control_flow())) {
      arg = 0;
    }
    else {
      try {
        arg = to_int(str_val->s);
      }
      catch (ValueError*) {
        e_die(StrFormat("%r expected a small integer, got %r", lexer::TokenVal(keyword), str_val->s), Alloc<loc::Word>(node->arg_word));
      }
    }
  }
  else {
    if ((keyword->id == Id::ControlFlow_Exit || keyword->id == Id::ControlFlow_Return)) {
      arg = this->mem->LastStatus();
    }
    else {
      arg = 1;
    }
  }
  this->tracer->OnControlFlow(consts::ControlFlowName(keyword->id), arg);
  if (((keyword->id == Id::ControlFlow_Break || keyword->id == Id::ControlFlow_Continue) and this->loop_level == 0)) {
    msg = str1399;
    if (this->exec_opts->strict_control_flow()) {
      e_die(msg, keyword);
    }
    else {
      this->errfmt->PrefixPrint(msg, str1400, keyword);
      return 0;
    }
  }
  if (keyword->id == Id::ControlFlow_Exit) {
    throw Alloc<util::UserExit>(arg);
  }
  else {
    throw Alloc<vm::IntControlFlow>(keyword, arg);
  }
}

int CommandEvaluator::_DoAndOr(command::AndOr* node, runtime_asdl::CommandStatus* cmd_st) {
  syntax_asdl::command_t* left = nullptr;
  int status;
  int i;
  int n;
  syntax_asdl::command_t* child = nullptr;
  syntax_asdl::Token* op = nullptr;
  int op_id;
  StackRoot _root0(&node);
  StackRoot _root1(&cmd_st);
  StackRoot _root2(&left);
  StackRoot _root3(&child);
  StackRoot _root4(&op);

  left = node->children->at(0);
  this->_StrictErrExit(left);
  {  // with
    state::ctx_ErrExit ctx{this->mutable_opts, false, node->ops->at(0)};

    status = this->_Execute(left);
  }
  i = 1;
  n = len(node->children);
  while (i < n) {
    child = node->children->at(i);
    op = node->ops->at((i - 1));
    op_id = op->id;
    if ((op_id == Id::Op_DPipe and status == 0)) {
      i += 1;
      continue;
    }
    else {
      if ((op_id == Id::Op_DAmp and status != 0)) {
        i += 1;
        continue;
      }
    }
    if (i == (n - 1)) {
      status = this->_Execute(child);
    }
    else {
      this->_StrictErrExit(child);
      {  // with
        state::ctx_ErrExit ctx{this->mutable_opts, false, op};

        status = this->_Execute(child);
      }
    }
    i += 1;
  }
  return status;
}

int CommandEvaluator::_DoWhileUntil(command::WhileUntil* node) {
  int status;
  bool b;
  runtime_asdl::flow_t action;
  StackRoot _root0(&node);

  status = 0;
  {  // with
    ctx_LoopLevel ctx{this};

    while (true) {
      try {
        b = this->_EvalCondition(node->cond, node->keyword);
        if (node->keyword->id == Id::KW_Until) {
          b = !b;
        }
        if (!b) {
          break;
        }
        status = this->_Execute(node->body);
      }
      catch (vm::IntControlFlow* e) {
        status = 0;
        action = e->HandleLoop();
        if (action == flow_e::Break) {
          break;
        }
        else {
          if (action == flow_e::Raise) {
            throw ;
          }
        }
      }
    }
  }
  return status;
}

int CommandEvaluator::_DoForEach(command::ForEach* node) {
  List<BigStr*>* iter_list = nullptr;
  syntax_asdl::expr_t* iter_expr = nullptr;
  syntax_asdl::loc_t* expr_blame = nullptr;
  syntax_asdl::for_iter_t* iterable = nullptr;
  syntax_asdl::for_iter_t* UP_iterable = nullptr;
  List<syntax_asdl::CompoundWord*>* words = nullptr;
  int n;
  value_asdl::LeftName* i_name = nullptr;
  value_asdl::LeftName* name1 = nullptr;
  value_asdl::LeftName* name2 = nullptr;
  val_ops::Iterator* it2 = nullptr;
  value_asdl::value_t* val = nullptr;
  value_asdl::value_t* UP_val = nullptr;
  int status;
  value_asdl::value_t* first = nullptr;
  runtime_asdl::flow_t action;
  StackRoot _root0(&node);
  StackRoot _root1(&iter_list);
  StackRoot _root2(&iter_expr);
  StackRoot _root3(&expr_blame);
  StackRoot _root4(&iterable);
  StackRoot _root5(&UP_iterable);
  StackRoot _root6(&words);
  StackRoot _root7(&i_name);
  StackRoot _root8(&name1);
  StackRoot _root9(&name2);
  StackRoot _root10(&it2);
  StackRoot _root11(&val);
  StackRoot _root12(&UP_val);
  StackRoot _root13(&first);

  iter_list = nullptr;
  iter_expr = nullptr;
  expr_blame = nullptr;
  iterable = node->iterable;
  UP_iterable = iterable;
  switch (node->iterable->tag()) {
    case for_iter_e::Args: {
      iter_list = this->mem->GetArgv();
    }
      break;
    case for_iter_e::Words: {
      for_iter::Words* iterable = static_cast<for_iter::Words*>(UP_iterable);
      words = braces::BraceExpandWords(iterable->words);
      iter_list = this->word_ev->EvalWordSequence(words);
    }
      break;
    case for_iter_e::YshExpr: {
      for_iter::YshExpr* iterable = static_cast<for_iter::YshExpr*>(UP_iterable);
      iter_expr = iterable->e;
      expr_blame = iterable->blame;
    }
      break;
    default: {
      assert(0);  // AssertionError
    }
  }
  n = len(node->iter_names);
  i_name = nullptr;
  name1 = nullptr;
  name2 = nullptr;
  it2 = nullptr;
  if (iter_expr) {
    val = this->expr_ev->EvalExpr(iter_expr, expr_blame);
    UP_val = val;
    switch (val->tag()) {
      case value_e::List: {
        value::List* val = static_cast<value::List*>(UP_val);
        it2 = Alloc<val_ops::ListIterator>(val);
        if (n == 1) {
          name1 = location::LName(node->iter_names->at(0));
        }
        else {
          if (n == 2) {
            i_name = location::LName(node->iter_names->at(0));
            name1 = location::LName(node->iter_names->at(1));
          }
          else {
            e_die_status(2, str1401, node->keyword);
          }
        }
      }
        break;
      case value_e::Dict: {
        value::Dict* val = static_cast<value::Dict*>(UP_val);
        it2 = Alloc<val_ops::DictIterator>(val);
        if (n == 1) {
          name1 = location::LName(node->iter_names->at(0));
        }
        else {
          if (n == 2) {
            name1 = location::LName(node->iter_names->at(0));
            name2 = location::LName(node->iter_names->at(1));
          }
          else {
            if (n == 3) {
              i_name = location::LName(node->iter_names->at(0));
              name1 = location::LName(node->iter_names->at(1));
              name2 = location::LName(node->iter_names->at(2));
            }
            else {
              assert(0);  // AssertionError
            }
          }
        }
      }
        break;
      case value_e::Range: {
        value::Range* val = static_cast<value::Range*>(UP_val);
        it2 = Alloc<val_ops::RangeIterator>(val);
        if (n == 1) {
          name1 = location::LName(node->iter_names->at(0));
        }
        else {
          if (n == 2) {
            i_name = location::LName(node->iter_names->at(0));
            name1 = location::LName(node->iter_names->at(1));
          }
          else {
            e_die_status(2, str1402, node->keyword);
          }
        }
      }
        break;
      case value_e::Stdin: {
        it2 = Alloc<val_ops::StdinIterator>(expr_blame);
        if (n == 1) {
          name1 = location::LName(node->iter_names->at(0));
        }
        else {
          if (n == 2) {
            i_name = location::LName(node->iter_names->at(0));
            name1 = location::LName(node->iter_names->at(1));
          }
          else {
            e_die_status(2, str1403, node->keyword);
          }
        }
      }
        break;
      default: {
        throw Alloc<error::TypeErr>(val, str1404, node->keyword);
      }
    }
  }
  else {
    it2 = Alloc<val_ops::ArrayIter>(iter_list);
    if (n == 1) {
      name1 = location::LName(node->iter_names->at(0));
    }
    else {
      if (n == 2) {
        i_name = location::LName(node->iter_names->at(0));
        name1 = location::LName(node->iter_names->at(1));
      }
      else {
        e_die_status(2, str1405, node->keyword);
      }
    }
  }
  status = 0;
  {  // with
    ctx_LoopLevel ctx{this};

    while (true) {
      first = it2->FirstValue();
      if (first == nullptr) {
        break;
      }
      if (first->tag() == value_e::Interrupted) {
        this->RunPendingTraps();
        continue;
      }
      this->mem->SetLocalName(name1, first);
      if (name2) {
        this->mem->SetLocalName(name2, it2->SecondValue());
      }
      if (i_name) {
        this->mem->SetLocalName(i_name, num::ToBig(it2->Index()));
      }
      it2->Next();
      try {
        status = this->_Execute(node->body);
      }
      catch (vm::IntControlFlow* e) {
        status = 0;
        action = e->HandleLoop();
        if (action == flow_e::Break) {
          break;
        }
        else {
          if (action == flow_e::Raise) {
            throw ;
          }
        }
      }
    }
  }
  return status;
}

int CommandEvaluator::_DoForExpr(command::ForExpr* node) {
  int status;
  syntax_asdl::arith_expr_t* init = nullptr;
  syntax_asdl::arith_expr_t* for_cond = nullptr;
  syntax_asdl::command_t* body = nullptr;
  syntax_asdl::arith_expr_t* update = nullptr;
  mops::BigInt cond_int;
  runtime_asdl::flow_t action;
  StackRoot _root0(&node);
  StackRoot _root1(&init);
  StackRoot _root2(&for_cond);
  StackRoot _root3(&body);
  StackRoot _root4(&update);

  status = 0;
  init = node->init;
  for_cond = node->cond;
  body = node->body;
  update = node->update;
  this->arith_ev->Eval(init);
  {  // with
    ctx_LoopLevel ctx{this};

    while (true) {
      cond_int = this->arith_ev->EvalToBigInt(for_cond);
      if (mops::Equal(cond_int, mops::ZERO)) {
        break;
      }
      try {
        status = this->_Execute(body);
      }
      catch (vm::IntControlFlow* e) {
        status = 0;
        action = e->HandleLoop();
        if (action == flow_e::Break) {
          break;
        }
        else {
          if (action == flow_e::Raise) {
            throw ;
          }
        }
      }
      this->arith_ev->Eval(update);
    }
  }
  return status;
}

void CommandEvaluator::_DoShFunction(command::ShFunction* node) {
  StackRoot _root0(&node);

  if ((dict_contains(this->procs, node->name) and !this->exec_opts->redefine_proc_func())) {
    e_die(StrFormat("Function %s was already defined (redefine_proc_func)", node->name), node->name_tok);
  }
  this->procs->set(node->name, Alloc<value::Proc>(node->name, node->name_tok, proc_sig::Open, node->body, nullptr, true));
}

void CommandEvaluator::_DoProc(syntax_asdl::Proc* node) {
  BigStr* proc_name = nullptr;
  proc_sig::Closed* sig = nullptr;
  value_asdl::ProcDefaults* proc_defaults = nullptr;
  StackRoot _root0(&node);
  StackRoot _root1(&proc_name);
  StackRoot _root2(&sig);
  StackRoot _root3(&proc_defaults);

  proc_name = lexer::TokenVal(node->name);
  if ((dict_contains(this->procs, proc_name) and !this->exec_opts->redefine_proc_func())) {
    e_die(StrFormat("Proc %s was already defined (redefine_proc_func)", proc_name), node->name);
  }
  if (node->sig->tag() == proc_sig_e::Closed) {
    sig = static_cast<proc_sig::Closed*>(node->sig);
    proc_defaults = func_proc::EvalProcDefaults(this->expr_ev, sig);
  }
  else {
    proc_defaults = nullptr;
  }
  this->procs->set(proc_name, Alloc<value::Proc>(proc_name, node->name, node->sig, node->body, proc_defaults, false));
}

void CommandEvaluator::_DoFunc(syntax_asdl::Func* node) {
  BigStr* name = nullptr;
  value_asdl::LeftName* lval = nullptr;
  runtime_asdl::Cell* cell = nullptr;
  bool did_unset;
  List<value_asdl::value_t*>* pos_defaults = nullptr;
  Dict<BigStr*, value_asdl::value_t*>* named_defaults = nullptr;
  value::Func* func_val = nullptr;
  StackRoot _root0(&node);
  StackRoot _root1(&name);
  StackRoot _root2(&lval);
  StackRoot _root3(&cell);
  StackRoot _root4(&pos_defaults);
  StackRoot _root5(&named_defaults);
  StackRoot _root6(&func_val);

  name = lexer::TokenVal(node->name);
  lval = location::LName(name);
  cell = this->mem->GetCell(name, scope_e::LocalOnly);
  if ((cell and cell->val->tag() == value_e::Func)) {
    if (this->exec_opts->redefine_proc_func()) {
      cell->readonly = false;
      did_unset = this->mem->Unset(lval, scope_e::LocalOnly);
    }
    else {
      e_die(StrFormat("Func %s was already defined (redefine_proc_func)", name), node->name);
    }
  }
  Tuple2<List<value_asdl::value_t*>*, Dict<BigStr*, value_asdl::value_t*>*> tup0 = func_proc::EvalFuncDefaults(this->expr_ev, node);
  pos_defaults = tup0.at0();
  named_defaults = tup0.at1();
  func_val = Alloc<value::Func>(name, node, pos_defaults, named_defaults, nullptr);
  this->mem->SetNamed(lval, func_val, scope_e::LocalOnly, state::SetReadOnly);
}

int CommandEvaluator::_DoIf(command::If* node) {
  int status;
  bool done;
  bool b;
  StackRoot _root0(&node);

  status = -1;
  done = false;
  for (ListIter<syntax_asdl::IfArm*> it(node->arms); !it.Done(); it.Next()) {
    syntax_asdl::IfArm* if_arm = it.Value();
    StackRoot _for(&if_arm  );
    b = this->_EvalCondition(if_arm->cond, if_arm->keyword);
    if (b) {
      status = this->_ExecuteList(if_arm->action);
      done = true;
      break;
    }
  }
  if ((!done and node->else_action != nullptr)) {
    status = this->_ExecuteList(node->else_action);
  }
  return status;
}

int CommandEvaluator::_DoCase(command::Case* node) {
  value_asdl::value_t* to_match = nullptr;
  int fnmatch_flags;
  int status;
  bool done;
  bool ignore_next_cond;
  value::Str* to_match_str = nullptr;
  pat::Words* pat_words = nullptr;
  bool this_arm_matches;
  value::Str* word_val = nullptr;
  int id_;
  pat::YshExprs* pat_exprs = nullptr;
  value_asdl::value_t* expr_val = nullptr;
  Eggex* eggex = nullptr;
  value::Eggex* eggex_val = nullptr;
  StackRoot _root0(&node);
  StackRoot _root1(&to_match);
  StackRoot _root2(&to_match_str);
  StackRoot _root3(&pat_words);
  StackRoot _root4(&word_val);
  StackRoot _root5(&pat_exprs);
  StackRoot _root6(&expr_val);
  StackRoot _root7(&eggex);
  StackRoot _root8(&eggex_val);

  to_match = this->_EvalCaseArg(node->to_match, node->case_kw);
  fnmatch_flags = this->exec_opts->nocasematch() ? FNM_CASEFOLD : 0;
  status = 0;
  done = false;
  ignore_next_cond = false;
  for (ListIter<syntax_asdl::CaseArm*> it(node->arms); !it.Done(); it.Next()) {
    syntax_asdl::CaseArm* case_arm = it.Value();
    StackRoot _for(&case_arm  );
    switch (case_arm->pattern->tag()) {
      case pat_e::Words: {
        if (to_match->tag() != value_e::Str) {
          continue;
        }
        to_match_str = static_cast<value::Str*>(to_match);
        pat_words = static_cast<pat::Words*>(case_arm->pattern);
        this_arm_matches = false;
        if (ignore_next_cond) {
          this_arm_matches = true;
          ignore_next_cond = false;
        }
        else {
          for (ListIter<syntax_asdl::word_t*> it(pat_words->words); !it.Done(); it.Next()) {
            syntax_asdl::word_t* pat_word = it.Value();
            StackRoot _for(&pat_word          );
            word_val = this->word_ev->EvalWordToString(pat_word, word_eval::QUOTE_FNMATCH);
            if (libc::fnmatch(word_val->s, to_match_str->s, fnmatch_flags)) {
              this_arm_matches = true;
              break;
            }
          }
        }
        if (this_arm_matches) {
          status = this->_ExecuteList(case_arm->action);
          done = true;
          if (case_arm->right) {
            id_ = case_arm->right->id;
            if (id_ == Id::Op_SemiAmp) {
              ignore_next_cond = true;
              done = false;
            }
            else {
              if (id_ == Id::Op_DSemiAmp) {
                done = false;
              }
            }
          }
        }
      }
        break;
      case pat_e::YshExprs: {
        pat_exprs = static_cast<pat::YshExprs*>(case_arm->pattern);
        for (ListIter<syntax_asdl::expr_t*> it(pat_exprs->exprs); !it.Done(); it.Next()) {
          syntax_asdl::expr_t* pat_expr = it.Value();
          StackRoot _for(&pat_expr        );
          expr_val = this->expr_ev->EvalExpr(pat_expr, case_arm->left);
          if (val_ops::ExactlyEqual(expr_val, to_match, case_arm->left)) {
            status = this->_ExecuteList(case_arm->action);
            done = true;
            break;
          }
        }
      }
        break;
      case pat_e::Eggex: {
        eggex = static_cast<Eggex*>(case_arm->pattern);
        eggex_val = this->expr_ev->EvalEggex(eggex);
        if (val_ops::MatchRegex(to_match, eggex_val, this->mem)) {
          status = this->_ExecuteList(case_arm->action);
          done = true;
          break;
        }
      }
        break;
      case pat_e::Else: {
        status = this->_ExecuteList(case_arm->action);
        done = true;
        break;
      }
        break;
      default: {
        assert(0);  // AssertionError
      }
    }
    if (done) {
      break;
    }
  }
  return status;
}

int CommandEvaluator::_DoTimeBlock(command::TimeBlock* node) {
  double s_real;
  double s_user;
  double s_sys;
  int status;
  double e_real;
  double e_user;
  double e_sys;
  StackRoot _root0(&node);

  Tuple3<double, double, double> tup1 = pyos::Time();
  s_real = tup1.at0();
  s_user = tup1.at1();
  s_sys = tup1.at2();
  status = this->_Execute(node->pipeline);
  Tuple3<double, double, double> tup2 = pyos::Time();
  e_real = tup2.at0();
  e_user = tup2.at1();
  e_sys = tup2.at2();
  libc::print_time((e_real - s_real), (e_user - s_user), (e_sys - s_sys));
  return status;
}

int CommandEvaluator::_DoRedirect(command::Redirect* node, runtime_asdl::CommandStatus* cmd_st) {
  int status;
  List<runtime_asdl::RedirValue*>* redirects = nullptr;
  List<IOError_OSError*>* io_errors = nullptr;
  StackRoot _root0(&node);
  StackRoot _root1(&cmd_st);
  StackRoot _root2(&redirects);
  StackRoot _root3(&io_errors);

  status = 0;
  redirects = Alloc<List<runtime_asdl::RedirValue*>>();
  try {
    for (ListIter<syntax_asdl::Redir*> it(node->redirects); !it.Done(); it.Next()) {
      syntax_asdl::Redir* redir = it.Value();
      StackRoot _for(&redir    );
      redirects->append(this->_EvalRedirect(redir));
    }
  }
  catch (error::RedirectEval* e) {
    this->errfmt->PrettyPrintError(e);
    redirects = nullptr;
  }
  catch (error::FailGlob* e) {
    if (!e->HasLocation()) {
      e->location = this->mem->GetFallbackLocation();
    }
    this->errfmt->PrettyPrintError(e, str1409);
    redirects = nullptr;
  }
  if (redirects == nullptr) {
    status = 1;
  }
  io_errors = Alloc<List<IOError_OSError*>>();
  if (status == 0) {
    this->shell_ex->PushRedirects(redirects, io_errors);
    if (len(io_errors)) {
      this->errfmt->PrintMessage(StrFormat("I/O error applying redirect: %s", pyutil::strerror(io_errors->at(0))), this->mem->GetFallbackLocation());
      status = 1;
    }
  }
  if (status == 0) {
    {  // with
      vm::ctx_Redirect ctx{this->shell_ex, len(redirects), io_errors};

      status = this->_Execute(node->child);
    }
    if (len(io_errors)) {
      e_die(StrFormat("Fatal error popping redirect: %s", pyutil::strerror(io_errors->at(0))));
    }
  }
  return status;
}

int CommandEvaluator::_Dispatch(syntax_asdl::command_t* node, runtime_asdl::CommandStatus* cmd_st) {
  syntax_asdl::command_t* UP_node = nullptr;
  int status;
  bool result;
  mops::BigInt i;
  value_asdl::value_t* val = nullptr;
  StackRoot _root0(&node);
  StackRoot _root1(&cmd_st);
  StackRoot _root2(&UP_node);
  StackRoot _root3(&val);

  DTRACE_PROBE1(cmd_eval, _Dispatch, node->tag());
  this->check_command_sub_status = false;
  UP_node = node;
  switch (node->tag()) {
    case command_e::Simple: {
      command::Simple* node = static_cast<command::Simple*>(UP_node);
      if (node->blame_tok != nullptr) {
        this->mem->SetTokenForLine(node->blame_tok);
      }
      this->_MaybeRunDebugTrap();
      cmd_st->check_errexit = true;
      status = this->_DoSimple(node, cmd_st);
    }
      break;
    case command_e::ExpandedAlias: {
      command::ExpandedAlias* node = static_cast<command::ExpandedAlias*>(UP_node);
      status = this->_DoExpandedAlias(node);
    }
      break;
    case command_e::Sentence: {
      command::Sentence* node = static_cast<command::Sentence*>(UP_node);
      if (node->terminator->id == Id::Op_Semi) {
        status = this->_Execute(node->child);
      }
      else {
        status = this->shell_ex->RunBackgroundJob(node->child);
      }
    }
      break;
    case command_e::Redirect: {
      command::Redirect* node = static_cast<command::Redirect*>(UP_node);
      cmd_st->check_errexit = true;
      status = this->_DoRedirect(node, cmd_st);
    }
      break;
    case command_e::Pipeline: {
      command::Pipeline* node = static_cast<command::Pipeline*>(UP_node);
      status = this->_DoPipeline(node, cmd_st);
    }
      break;
    case command_e::Subshell: {
      command::Subshell* node = static_cast<command::Subshell*>(UP_node);
      cmd_st->check_errexit = true;
      status = this->shell_ex->RunSubshell(node->child);
    }
      break;
    case command_e::DBracket: {
      command::DBracket* node = static_cast<command::DBracket*>(UP_node);
      this->mem->SetTokenForLine(node->left);
      this->_MaybeRunDebugTrap();
      this->tracer->PrintSourceCode(node->left, node->right, this->arena);
      cmd_st->check_errexit = true;
      cmd_st->show_code = true;
      result = this->bool_ev->EvalB(node->expr);
      status = result ? 0 : 1;
    }
      break;
    case command_e::DParen: {
      command::DParen* node = static_cast<command::DParen*>(UP_node);
      this->mem->SetTokenForLine(node->left);
      this->_MaybeRunDebugTrap();
      this->tracer->PrintSourceCode(node->left, node->right, this->arena);
      cmd_st->check_errexit = true;
      cmd_st->show_code = true;
      i = this->arith_ev->EvalToBigInt(node->child);
      status = mops::Equal(i, mops::ZERO) ? 1 : 0;
    }
      break;
    case command_e::ControlFlow: {
      command::ControlFlow* node = static_cast<command::ControlFlow*>(UP_node);
      this->mem->SetTokenForLine(node->keyword);
      this->_MaybeRunDebugTrap();
      status = this->_DoControlFlow(node);
    }
      break;
    case command_e::VarDecl: {
      command::VarDecl* node = static_cast<command::VarDecl*>(UP_node);
      this->mem->SetTokenForLine(node->lhs->at(0)->left);
      status = this->_DoVarDecl(node);
    }
      break;
    case command_e::Mutation: {
      command::Mutation* node = static_cast<command::Mutation*>(UP_node);
      this->mem->SetTokenForLine(node->keyword);
      this->_DoMutation(node);
      status = 0;
    }
      break;
    case command_e::ShAssignment: {
      command::ShAssignment* node = static_cast<command::ShAssignment*>(UP_node);
      this->mem->SetTokenForLine(node->pairs->at(0)->left);
      this->_MaybeRunDebugTrap();
      status = this->_DoShAssignment(node, cmd_st);
    }
      break;
    case command_e::Expr: {
      command::Expr* node = static_cast<command::Expr*>(UP_node);
      this->mem->SetTokenForLine(node->keyword);
      status = this->_DoExpr(node);
    }
      break;
    case command_e::Retval: {
      command::Retval* node = static_cast<command::Retval*>(UP_node);
      this->mem->SetTokenForLine(node->keyword);
      val = this->expr_ev->EvalExpr(node->val, node->keyword);
      throw Alloc<vm::ValueControlFlow>(node->keyword, val);
    }
      break;
    case command_e::CommandList: {
      command::CommandList* node = static_cast<command::CommandList*>(UP_node);
      status = this->_ExecuteList(node->children);
    }
      break;
    case command_e::DoGroup: {
      command::DoGroup* node = static_cast<command::DoGroup*>(UP_node);
      status = this->_ExecuteList(node->children);
    }
      break;
    case command_e::BraceGroup: {
      BraceGroup* node = static_cast<BraceGroup*>(UP_node);
      status = this->_ExecuteList(node->children);
    }
      break;
    case command_e::AndOr: {
      command::AndOr* node = static_cast<command::AndOr*>(UP_node);
      status = this->_DoAndOr(node, cmd_st);
    }
      break;
    case command_e::WhileUntil: {
      command::WhileUntil* node = static_cast<command::WhileUntil*>(UP_node);
      this->mem->SetTokenForLine(node->keyword);
      status = this->_DoWhileUntil(node);
    }
      break;
    case command_e::ForEach: {
      command::ForEach* node = static_cast<command::ForEach*>(UP_node);
      this->mem->SetTokenForLine(node->keyword);
      status = this->_DoForEach(node);
    }
      break;
    case command_e::ForExpr: {
      command::ForExpr* node = static_cast<command::ForExpr*>(UP_node);
      this->mem->SetTokenForLine(node->keyword);
      status = this->_DoForExpr(node);
    }
      break;
    case command_e::ShFunction: {
      command::ShFunction* node = static_cast<command::ShFunction*>(UP_node);
      this->_DoShFunction(node);
      status = 0;
    }
      break;
    case command_e::Proc: {
      Proc* node = static_cast<Proc*>(UP_node);
      this->_DoProc(node);
      status = 0;
    }
      break;
    case command_e::Func: {
      Func* node = static_cast<Func*>(UP_node);
      this->mem->SetTokenForLine(node->name);
      this->_DoFunc(node);
      status = 0;
    }
      break;
    case command_e::If: {
      command::If* node = static_cast<command::If*>(UP_node);
      status = this->_DoIf(node);
    }
      break;
    case command_e::NoOp: {
      status = 0;
    }
      break;
    case command_e::Case: {
      command::Case* node = static_cast<command::Case*>(UP_node);
      this->mem->SetTokenForLine(node->case_kw);
      this->_MaybeRunDebugTrap();
      status = this->_DoCase(node);
    }
      break;
    case command_e::TimeBlock: {
      command::TimeBlock* node = static_cast<command::TimeBlock*>(UP_node);
      status = this->_DoTimeBlock(node);
    }
      break;
    default: {
      FAIL(kNotImplemented);  // Python NotImplementedError
    }
  }
  return status;
}

void CommandEvaluator::RunPendingTraps() {
  List<syntax_asdl::command_t*>* trap_nodes = nullptr;
  StackRoot _root0(&trap_nodes);

  trap_nodes = this->trap_state->GetPendingTraps();
  if (trap_nodes != nullptr) {
    {  // with
      state::ctx_Option ctx{this->mutable_opts, NewList<int>(std::initializer_list<int>{option_i::_running_trap}), true};

      for (ListIter<syntax_asdl::command_t*> it(trap_nodes); !it.Done(); it.Next()) {
        syntax_asdl::command_t* trap_node = it.Value();
        StackRoot _for(&trap_node      );
        {  // with
          state::ctx_Registers ctx{this->mem};

          {  // with
            dev::ctx_Tracer ctx{this->tracer, str1412, nullptr};

            this->_Execute(trap_node);
          }
        }
      }
    }
  }
}

int CommandEvaluator::_Execute(syntax_asdl::command_t* node) {
  runtime_asdl::CommandStatus* cmd_st = nullptr;
  runtime_asdl::StatusArray* process_sub_st = nullptr;
  int status;
  List<int>* pipe_status = nullptr;
  syntax_asdl::loc_t* errexit_loc = nullptr;
  int i;
  List<int>* codes = nullptr;
  StackRoot _root0(&node);
  StackRoot _root1(&cmd_st);
  StackRoot _root2(&process_sub_st);
  StackRoot _root3(&pipe_status);
  StackRoot _root4(&errexit_loc);
  StackRoot _root5(&codes);

  this->RunPendingTraps();
  // if MYCPP
  {
    if (this->signal_safe->PollSigInt()) {
      throw Alloc<KeyboardInterrupt>();
    }
  }
  // endif MYCPP
  mylib::MaybeCollect();
  cmd_st = CommandStatus::CreateNull();
  if (len(this->status_array_pool)) {
    process_sub_st = this->status_array_pool->pop();
  }
  else {
    process_sub_st = StatusArray::CreateNull();
  }
  {  // with
    vm::ctx_ProcessSub ctx{this->shell_ex, process_sub_st};

    try {
      status = this->_Dispatch(node, cmd_st);
    }
    catch (error::FailGlob* e) {
      if (!e->HasLocation()) {
        e->location = this->mem->GetFallbackLocation();
      }
      this->errfmt->PrettyPrintError(e, str1413);
      status = 1;
      cmd_st->check_errexit = true;
    }
  }
  pipe_status = cmd_st->pipe_status;
  errexit_loc = loc::Missing;
  if (pipe_status != nullptr) {
    this->mem->SetPipeStatus(pipe_status);
    if (this->exec_opts->pipefail()) {
      status = 0;
      i = 0;
      for (ListIter<int> it(pipe_status); !it.Done(); it.Next(), ++i) {
        int st = it.Value();
        if (st != 0) {
          status = st;
          errexit_loc = cmd_st->pipe_locs->at(i);
        }
      }
    }
    else {
      status = pipe_status->at(-1);
    }
    if (cmd_st->pipe_negated) {
      status = status == 0 ? 1 : 0;
    }
  }
  if (process_sub_st->codes == nullptr) {
    this->status_array_pool->append(process_sub_st);
  }
  else {
    codes = process_sub_st->codes;
    this->mem->SetProcessSubStatus(codes);
    if ((status == 0 and this->exec_opts->process_sub_fail())) {
      i = 0;
      for (ListIter<int> it(codes); !it.Done(); it.Next(), ++i) {
        int st = it.Value();
        if (st != 0) {
          status = st;
          errexit_loc = process_sub_st->locs->at(i);
        }
      }
    }
  }
  this->mem->SetLastStatus(status);
  if (cmd_st->check_errexit) {
    this->_CheckStatus(status, cmd_st, node, errexit_loc);
  }
  return status;
}

int CommandEvaluator::_ExecuteList(List<syntax_asdl::command_t*>* children) {
  int status;
  StackRoot _root0(&children);

  status = 0;
  for (ListIter<syntax_asdl::command_t*> it(children); !it.Done(); it.Next()) {
    syntax_asdl::command_t* child = it.Value();
    StackRoot _for(&child  );
    status = this->_Execute(child);
  }
  return status;
}

int CommandEvaluator::LastStatus() {
  return this->mem->LastStatus();
}

void CommandEvaluator::_NoForkLast(syntax_asdl::command_t* node) {
  syntax_asdl::command_t* UP_node = nullptr;
  StackRoot _root0(&node);
  StackRoot _root1(&UP_node);

  UP_node = node;
  switch (node->tag()) {
    case command_e::Simple: {
      command::Simple* node = static_cast<command::Simple*>(UP_node);
      node->do_fork = false;
    }
      break;
    case command_e::Pipeline: {
      command::Pipeline* node = static_cast<command::Pipeline*>(UP_node);
      if (node->negated == nullptr) {
        this->_NoForkLast(node->children->at(-1));
      }
    }
      break;
    case command_e::Sentence: {
      command::Sentence* node = static_cast<command::Sentence*>(UP_node);
      this->_NoForkLast(node->child);
    }
      break;
    case command_e::CommandList: {
      command::CommandList* node = static_cast<command::CommandList*>(UP_node);
      this->_NoForkLast(node->children->at(-1));
    }
      break;
    case command_e::BraceGroup: {
      BraceGroup* node = static_cast<BraceGroup*>(UP_node);
      this->_NoForkLast(node->children->at(-1));
    }
      break;
  }
}

syntax_asdl::command_t* CommandEvaluator::_RemoveSubshells(syntax_asdl::command_t* node) {
  syntax_asdl::command_t* UP_node = nullptr;
  StackRoot _root0(&node);
  StackRoot _root1(&UP_node);

  UP_node = node;
  switch (node->tag()) {
    case command_e::Subshell: {
      command::Subshell* node = static_cast<command::Subshell*>(UP_node);
      return this->_RemoveSubshells(node->child);
    }
      break;
  }
  return node;
}

Tuple2<bool, bool> CommandEvaluator::ExecuteAndCatch(syntax_asdl::command_t* node, int cmd_flags) {
  bool is_return;
  bool is_fatal;
  bool is_errexit;
  error::FatalRuntime* err = nullptr;
  int status;
  List<int>* options = nullptr;
  StackRoot _root0(&node);
  StackRoot _root1(&err);
  StackRoot _root2(&options);

  if ((cmd_flags & Optimize)) {
    node = this->_RemoveSubshells(node);
    this->_NoForkLast(node);
  }
  is_return = false;
  is_fatal = false;
  is_errexit = false;
  err = nullptr;
  status = -1;
  try {
    options = Alloc<List<int>>();
    if ((cmd_flags & NoDebugTrap)) {
      options->append(option_i::_no_debug_trap);
    }
    if ((cmd_flags & NoErrTrap)) {
      options->append(option_i::_no_err_trap);
    }
    {  // with
      state::ctx_Option ctx{this->mutable_opts, options, true};

      status = this->_Execute(node);
    }
  }
  catch (vm::IntControlFlow* e) {
    if ((cmd_flags & RaiseControlFlow)) {
      throw ;
    }
    else {
      if (e->IsReturn()) {
        is_return = true;
        status = e->StatusCode();
      }
      else {
        this->errfmt->Print_(str1419, e->token);
        is_fatal = true;
        status = 1;
      }
    }
  }
  catch (error::Parse* e) {
    this->dumper->MaybeRecord(this, e);
    throw ;
  }
  catch (error::ErrExit* e) {
    err = e;
    is_errexit = true;
  }
  catch (error::FatalRuntime* e) {
    err = e;
  }
  if (err) {
    status = err->ExitStatus();
    is_fatal = true;
    this->dumper->MaybeRecord(this, err);
    if (!err->HasLocation()) {
      err->location = this->mem->GetFallbackLocation();
    }
    if (is_errexit) {
      if (this->exec_opts->verbose_errexit()) {
        this->errfmt->PrintErrExit(static_cast<error::ErrExit*>(err), posix::getpid());
      }
    }
    else {
      this->errfmt->PrettyPrintError(err, str1420);
    }
  }
  this->dumper->MaybeDump(status);
  this->mem->SetLastStatus(status);
  return Tuple2<bool, bool>(is_return, is_fatal);
}

int CommandEvaluator::EvalCommand(syntax_asdl::command_t* block) {
  int status;
  StackRoot _root0(&block);

  status = 0;
  try {
    status = this->_Execute(block);
  }
  catch (vm::IntControlFlow* e) {
    if (e->IsReturn()) {
      status = e->StatusCode();
    }
    else {
      e_die(str1421, e->token);
    }
  }
  return status;
}

void CommandEvaluator::MaybeRunExitTrap(syntax_asdl::IntParamBox* mut_status) {
  syntax_asdl::command_t* node = nullptr;
  bool is_return;
  bool is_fatal;
  StackRoot _root0(&mut_status);
  StackRoot _root1(&node);

  node = this->trap_state->GetHook(str1422);
  if (node) {
    {  // with
      dev::ctx_Tracer ctx{this->tracer, str1423, nullptr};

      try {
        Tuple2<bool, bool> tup3 = this->ExecuteAndCatch(node);
        is_return = tup3.at0();
        is_fatal = tup3.at1();
      }
      catch (util::UserExit* e) {
        mut_status->i = e->status;
        return ;
      }
      if (is_return) {
        mut_status->i = this->LastStatus();
      }
    }
  }
}

void CommandEvaluator::_MaybeRunDebugTrap() {
  syntax_asdl::command_t* node = nullptr;
  StackRoot _root0(&node);

  node = this->trap_state->GetHook(str1424);
  if (node == nullptr) {
    return ;
  }
  if (this->exec_opts->_no_debug_trap()) {
    return ;
  }
  if (!this->mem->ShouldRunDebugTrap()) {
    return ;
  }
  {  // with
    dev::ctx_Tracer ctx{this->tracer, str1425, nullptr};

    {  // with
      state::ctx_Registers ctx{this->mem};

      {  // with
        state::ctx_DebugTrap ctx{this->mem};

        this->_Execute(node);
      }
    }
  }
}

void CommandEvaluator::_MaybeRunErrTrap() {
  syntax_asdl::command_t* node = nullptr;
  StackRoot _root0(&node);

  node = this->trap_state->GetHook(str1426);
  if (node == nullptr) {
    return ;
  }
  if (this->exec_opts->_no_err_trap()) {
    return ;
  }
  if (this->mem->running_err_trap) {
    return ;
  }
  if (this->mutable_opts->ErrExitIsDisabled()) {
    return ;
  }
  if (this->mem->InsideFunction()) {
    return ;
  }
  {  // with
    dev::ctx_Tracer ctx{this->tracer, str1427, nullptr};

    {  // with
      state::ctx_ErrTrap ctx{this->mem};

      this->_Execute(node);
    }
  }
}

int CommandEvaluator::RunProc(value::Proc* proc, cmd_value::Argv* cmd_val) {
  syntax_asdl::proc_sig_t* sig = nullptr;
  List<BigStr*>* proc_argv = nullptr;
  int status;
  StackRoot _root0(&proc);
  StackRoot _root1(&cmd_val);
  StackRoot _root2(&sig);
  StackRoot _root3(&proc_argv);

  sig = proc->sig;
  if (sig->tag() == proc_sig_e::Closed) {
    proc_argv = Alloc<List<BigStr*>>();
  }
  else {
    proc_argv = cmd_val->argv->slice(1);
  }
  {  // with
    state::ctx_ProcCall ctx{this->mem, this->mutable_opts, proc, proc_argv};

    func_proc::BindProcArgs(proc, cmd_val, this->mem);
    try {
      status = this->_Execute(proc->body);
    }
    catch (vm::IntControlFlow* e) {
      if (e->IsReturn()) {
        status = e->StatusCode();
      }
      else {
        e_die(StrFormat("Unexpected %r (in proc call)", lexer::TokenVal(e->token)), e->token);
      }
    }
    catch (error::FatalRuntime* e) {
      this->dumper->MaybeRecord(this, e);
      throw ;
    }
  }
  return status;
}

int CommandEvaluator::RunFuncForCompletion(value::Proc* proc, List<BigStr*>* argv) {
  cmd_value::Argv* cmd_val = nullptr;
  int status;
  StackRoot _root0(&proc);
  StackRoot _root1(&argv);
  StackRoot _root2(&cmd_val);

  cmd_val = MakeBuiltinArgv(argv);
  try {
    status = this->RunProc(proc, cmd_val);
  }
  catch (error::FatalRuntime* e) {
    this->errfmt->PrettyPrintError(e);
    status = e->ExitStatus();
  }
  catch (vm::IntControlFlow* e) {
    this->errfmt->Print_(str1429, e->token);
    status = 1;
  }
  return status;
}

}  // define namespace cmd_eval

namespace cmd_parse {  // define

using id_kind_asdl::Id;
using id_kind_asdl::Id_t;
using id_kind_asdl::Id_str;
using id_kind_asdl::Kind;
using id_kind_asdl::Kind_str;
using types_asdl::lex_mode_e;
using types_asdl::cmd_mode_e;
using types_asdl::cmd_mode_t;
using syntax_asdl::loc;
using syntax_asdl::SourceLine;
using syntax_asdl::source;
using syntax_asdl::parse_result;
using syntax_asdl::parse_result_t;
using syntax_asdl::command;
using syntax_asdl::command_t;
using syntax_asdl::condition;
using syntax_asdl::condition_t;
using syntax_asdl::for_iter;
using syntax_asdl::ArgList;
using syntax_asdl::BraceGroup;
using syntax_asdl::LiteralBlock;
using syntax_asdl::CaseArm;
using syntax_asdl::case_arg;
using syntax_asdl::IfArm;
using syntax_asdl::pat;
using syntax_asdl::pat_t;
using syntax_asdl::Redir;
using syntax_asdl::redir_param;
using syntax_asdl::redir_loc;
using syntax_asdl::redir_loc_t;
using syntax_asdl::word_e;
using syntax_asdl::word_t;
using syntax_asdl::CompoundWord;
using syntax_asdl::Token;
using syntax_asdl::word_part_e;
using syntax_asdl::word_part_t;
using syntax_asdl::rhs_word;
using syntax_asdl::rhs_word_t;
using syntax_asdl::sh_lhs;
using syntax_asdl::sh_lhs_t;
using syntax_asdl::AssignPair;
using syntax_asdl::EnvPair;
using syntax_asdl::ParsedAssignment;
using syntax_asdl::assign_op_e;
using syntax_asdl::NameType;
using syntax_asdl::proc_sig;
using syntax_asdl::proc_sig_e;
using syntax_asdl::Proc;
using syntax_asdl::Func;
using error::p_die;
int TAB_CH = 9;
int SPACE_CH = 32;

Tuple2<List<Tuple2<syntax_asdl::SourceLine*, int>*>*, Tuple2<syntax_asdl::SourceLine*, int>*> _ReadHereLines(reader::_Reader* line_reader, syntax_asdl::Redir* h, BigStr* delimiter) {
  List<Tuple2<syntax_asdl::SourceLine*, int>*>* here_lines = nullptr;
  Tuple2<syntax_asdl::SourceLine*, int>* last_line = nullptr;
  bool strip_leading_tabs;
  syntax_asdl::SourceLine* src_line = nullptr;
  BigStr* line = nullptr;
  int start_offset;
  int n;
  int i;
  StackRoot _root0(&line_reader);
  StackRoot _root1(&h);
  StackRoot _root2(&delimiter);
  StackRoot _root3(&here_lines);
  StackRoot _root4(&last_line);
  StackRoot _root5(&src_line);
  StackRoot _root6(&line);

  here_lines = Alloc<List<Tuple2<syntax_asdl::SourceLine*, int>*>>();
  last_line = nullptr;
  strip_leading_tabs = h->op->id == Id::Redir_DLessDash;
  while (true) {
    Tuple2<syntax_asdl::SourceLine*, int> tup0 = line_reader->GetLine();
    src_line = tup0.at0();
    if (src_line == nullptr) {
      p_die(str1430, h->op);
    }
    line = src_line->content;
    start_offset = 0;
    if (strip_leading_tabs) {
      n = len(line);
      i = 0;
      while (i < n) {
        if (!(str_equals(line->at(i), str1431))) {
          break;
        }
        i += 1;
      }
      start_offset = i;
    }
    if (str_equals(line->slice(start_offset)->rstrip(), delimiter)) {
      last_line = (Alloc<Tuple2<syntax_asdl::SourceLine*, int>>(src_line, start_offset));
      break;
    }
    here_lines->append((Alloc<Tuple2<syntax_asdl::SourceLine*, int>>(src_line, start_offset)));
  }
  return Tuple2<List<Tuple2<syntax_asdl::SourceLine*, int>*>*, Tuple2<syntax_asdl::SourceLine*, int>*>(here_lines, last_line);
}

List<syntax_asdl::word_part_t*>* _MakeLiteralHereLines(List<Tuple2<syntax_asdl::SourceLine*, int>*>* here_lines, alloc::Arena* arena, bool do_lossless) {
  List<syntax_asdl::word_part_t*>* tokens = nullptr;
  syntax_asdl::SourceLine* src_line = nullptr;
  int start_offset;
  syntax_asdl::Token* t = nullptr;
  StackRoot _root0(&here_lines);
  StackRoot _root1(&arena);
  StackRoot _root2(&tokens);
  StackRoot _root3(&src_line);
  StackRoot _root4(&t);

  tokens = Alloc<List<syntax_asdl::word_part_t*>>();
  for (ListIter<Tuple2<syntax_asdl::SourceLine*, int>*> it(here_lines); !it.Done(); it.Next()) {
    Tuple2<syntax_asdl::SourceLine*, int>* tup1 = it.Value();
    src_line = tup1->at0();
    start_offset = tup1->at1();
    if (do_lossless) {
      arena->NewToken(Id::Lit_CharsWithoutPrefix, start_offset, 0, src_line);
    }
    t = arena->NewToken(Id::Lit_Chars, start_offset, len(src_line->content), src_line);
    tokens->append(t);
  }
  return tokens;
}

void _ParseHereDocBody(parse_lib::ParseContext* parse_ctx, syntax_asdl::Redir* r, reader::_Reader* line_reader, alloc::Arena* arena) {
  redir_param::HereDoc* h = nullptr;
  bool ok;
  BigStr* delimiter = nullptr;
  bool delim_quoted;
  List<Tuple2<syntax_asdl::SourceLine*, int>*>* here_lines = nullptr;
  Tuple2<syntax_asdl::SourceLine*, int>* last_line = nullptr;
  word_parse::WordParser* w_parser = nullptr;
  syntax_asdl::SourceLine* end_line = nullptr;
  int start_offset;
  StackRoot _root0(&parse_ctx);
  StackRoot _root1(&r);
  StackRoot _root2(&line_reader);
  StackRoot _root3(&arena);
  StackRoot _root4(&h);
  StackRoot _root5(&delimiter);
  StackRoot _root6(&here_lines);
  StackRoot _root7(&last_line);
  StackRoot _root8(&w_parser);
  StackRoot _root9(&end_line);

  h = static_cast<redir_param::HereDoc*>(r->arg);
  Tuple3<bool, BigStr*, bool> tup2 = word_::StaticEval(h->here_begin);
  ok = tup2.at0();
  delimiter = tup2.at1();
  delim_quoted = tup2.at2();
  if (!ok) {
    p_die(str1432, Alloc<loc::Word>(h->here_begin));
  }
  Tuple2<List<Tuple2<syntax_asdl::SourceLine*, int>*>*, Tuple2<syntax_asdl::SourceLine*, int>*> tup3 = _ReadHereLines(line_reader, r, delimiter);
  here_lines = tup3.at0();
  last_line = tup3.at1();
  if (delim_quoted) {
    h->stdin_parts = _MakeLiteralHereLines(here_lines, arena, parse_ctx->do_lossless);
  }
  else {
    line_reader = Alloc<reader::VirtualLineReader>(arena, here_lines, parse_ctx->do_lossless);
    w_parser = parse_ctx->MakeWordParserForHereDoc(line_reader);
    w_parser->ReadHereDocBody(h->stdin_parts);
  }
  Tuple2<syntax_asdl::SourceLine*, int>* tup4 = last_line;
  end_line = tup4->at0();
  start_offset = tup4->at1();
  if (parse_ctx->do_lossless) {
    arena->NewToken(Id::Lit_CharsWithoutPrefix, start_offset, 0, end_line);
  }
  h->here_end_tok = arena->NewToken(Id::Undefined_Tok, start_offset, len(end_line->content), end_line);
}

syntax_asdl::AssignPair* _MakeAssignPair(parse_lib::ParseContext* parse_ctx, syntax_asdl::ParsedAssignment* preparsed, alloc::Arena* arena) {
  syntax_asdl::Token* left_token = nullptr;
  syntax_asdl::Token* close_token = nullptr;
  syntax_asdl::sh_lhs_t* lhs = nullptr;
  BigStr* var_name = nullptr;
  syntax_asdl::assign_op_t op;
  int left_pos;
  BigStr* index_str = nullptr;
  int s;
  BigStr* code_str = nullptr;
  tdop::TdopParser* a_parser = nullptr;
  source::Reparsed* src = nullptr;
  syntax_asdl::arith_expr_t* index_node = nullptr;
  List<syntax_asdl::word_part_t*>* parts = nullptr;
  int offset;
  int n;
  syntax_asdl::rhs_word_t* rhs = nullptr;
  syntax_asdl::CompoundWord* w = nullptr;
  StackRoot _root0(&parse_ctx);
  StackRoot _root1(&preparsed);
  StackRoot _root2(&arena);
  StackRoot _root3(&left_token);
  StackRoot _root4(&close_token);
  StackRoot _root5(&lhs);
  StackRoot _root6(&var_name);
  StackRoot _root7(&index_str);
  StackRoot _root8(&code_str);
  StackRoot _root9(&a_parser);
  StackRoot _root10(&src);
  StackRoot _root11(&index_node);
  StackRoot _root12(&parts);
  StackRoot _root13(&rhs);
  StackRoot _root14(&w);

  left_token = preparsed->left;
  close_token = preparsed->close;
  lhs = nullptr;
  if (left_token->id == Id::Lit_VarLike) {
    if (lexer::IsPlusEquals(left_token)) {
      var_name = lexer::TokenSliceRight(left_token, -2);
      op = assign_op_e::PlusEqual;
    }
    else {
      var_name = lexer::TokenSliceRight(left_token, -1);
      op = assign_op_e::Equal;
    }
    lhs = Alloc<sh_lhs::Name>(left_token, var_name);
  }
  else {
    if ((left_token->id == Id::Lit_ArrayLhsOpen and parse_ctx->do_lossless)) {
      var_name = lexer::TokenSliceRight(left_token, -1);
      if (lexer::IsPlusEquals(close_token)) {
        op = assign_op_e::PlusEqual;
      }
      else {
        op = assign_op_e::Equal;
      }
      left_pos = (left_token->col + left_token->length);
      index_str = left_token->line->content->slice(left_pos, close_token->col);
      lhs = Alloc<sh_lhs::UnparsedIndex>(left_token, var_name, index_str);
    }
    else {
      if (left_token->id == Id::Lit_ArrayLhsOpen) {
        var_name = lexer::TokenSliceRight(left_token, -1);
        if (lexer::IsPlusEquals(close_token)) {
          op = assign_op_e::PlusEqual;
        }
        else {
          op = assign_op_e::Equal;
        }
        if (left_token->line == close_token->line) {
          s = (left_token->col + left_token->length);
          code_str = left_token->line->content->slice(s, close_token->col);
        }
        else {
          FAIL(kNotImplemented);  // Python NotImplementedError
        }
        a_parser = parse_ctx->MakeArithParser(code_str);
        src = Alloc<source::Reparsed>(str1434, left_token, close_token);
        {  // with
          alloc::ctx_SourceCode ctx{arena, src};

          index_node = a_parser->Parse();
        }
        lhs = Alloc<sh_lhs::IndexedName>(left_token, var_name, index_node);
      }
      else {
        assert(0);  // AssertionError
      }
    }
  }
  parts = preparsed->w->parts;
  offset = preparsed->part_offset;
  n = len(parts);
  if (offset == n) {
    rhs = rhs_word::Empty;
  }
  else {
    w = Alloc<CompoundWord>(parts->slice(offset));
    word_::TildeDetectAssign(w);
    rhs = w;
  }
  return Alloc<AssignPair>(left_token, lhs, op, rhs);
}

void _AppendMoreEnv(List<syntax_asdl::ParsedAssignment*>* preparsed_list, List<syntax_asdl::EnvPair*>* more_env) {
  syntax_asdl::Token* left_token = nullptr;
  BigStr* var_name = nullptr;
  List<syntax_asdl::word_part_t*>* parts = nullptr;
  int n;
  int offset;
  syntax_asdl::rhs_word_t* rhs = nullptr;
  syntax_asdl::CompoundWord* w = nullptr;
  StackRoot _root0(&preparsed_list);
  StackRoot _root1(&more_env);
  StackRoot _root2(&left_token);
  StackRoot _root3(&var_name);
  StackRoot _root4(&parts);
  StackRoot _root5(&rhs);
  StackRoot _root6(&w);

  for (ListIter<syntax_asdl::ParsedAssignment*> it(preparsed_list); !it.Done(); it.Next()) {
    syntax_asdl::ParsedAssignment* preparsed = it.Value();
    StackRoot _for(&preparsed  );
    left_token = preparsed->left;
    if (left_token->id != Id::Lit_VarLike) {
      p_die(str1435, left_token);
    }
    if (lexer::IsPlusEquals(left_token)) {
      p_die(str1436, left_token);
    }
    var_name = lexer::TokenSliceRight(left_token, -1);
    parts = preparsed->w->parts;
    n = len(parts);
    offset = preparsed->part_offset;
    if (offset == n) {
      rhs = rhs_word::Empty;
    }
    else {
      w = Alloc<CompoundWord>(parts->slice(offset));
      word_::TildeDetectAssign(w);
      rhs = w;
    }
    more_env->append(Alloc<EnvPair>(left_token, var_name, rhs));
  }
}

Tuple2<List<syntax_asdl::ParsedAssignment*>*, List<syntax_asdl::CompoundWord*>*> _SplitSimpleCommandPrefix(List<syntax_asdl::CompoundWord*>* words) {
  List<syntax_asdl::ParsedAssignment*>* preparsed_list = nullptr;
  List<syntax_asdl::CompoundWord*>* suffix_words = nullptr;
  bool done_prefix;
  syntax_asdl::Token* left_token = nullptr;
  syntax_asdl::Token* close_token = nullptr;
  int part_offset;
  StackRoot _root0(&words);
  StackRoot _root1(&preparsed_list);
  StackRoot _root2(&suffix_words);
  StackRoot _root3(&left_token);
  StackRoot _root4(&close_token);

  preparsed_list = Alloc<List<syntax_asdl::ParsedAssignment*>>();
  suffix_words = Alloc<List<syntax_asdl::CompoundWord*>>();
  done_prefix = false;
  for (ListIter<syntax_asdl::CompoundWord*> it(words); !it.Done(); it.Next()) {
    syntax_asdl::CompoundWord* w = it.Value();
    StackRoot _for(&w  );
    if (done_prefix) {
      suffix_words->append(w);
      continue;
    }
    Tuple3<syntax_asdl::Token*, syntax_asdl::Token*, int> tup5 = word_::DetectShAssignment(w);
    left_token = tup5.at0();
    close_token = tup5.at1();
    part_offset = tup5.at2();
    if (left_token) {
      preparsed_list->append(Alloc<ParsedAssignment>(left_token, close_token, part_offset, w));
    }
    else {
      done_prefix = true;
      suffix_words->append(w);
    }
  }
  return Tuple2<List<syntax_asdl::ParsedAssignment*>*, List<syntax_asdl::CompoundWord*>*>(preparsed_list, suffix_words);
}

command::Simple* _MakeSimpleCommand(List<syntax_asdl::ParsedAssignment*>* preparsed_list, List<syntax_asdl::CompoundWord*>* suffix_words, syntax_asdl::ArgList* typed_args, syntax_asdl::LiteralBlock* block) {
  syntax_asdl::word_part_t* part0 = nullptr;
  syntax_asdl::Token* blame_tok = nullptr;
  List<syntax_asdl::word_t*>* words2 = nullptr;
  List<syntax_asdl::word_t*>* words3 = nullptr;
  List<syntax_asdl::EnvPair*>* more_env = nullptr;
  StackRoot _root0(&preparsed_list);
  StackRoot _root1(&suffix_words);
  StackRoot _root2(&typed_args);
  StackRoot _root3(&block);
  StackRoot _root4(&part0);
  StackRoot _root5(&blame_tok);
  StackRoot _root6(&words2);
  StackRoot _root7(&words3);
  StackRoot _root8(&more_env);

  for (ListIter<syntax_asdl::ParsedAssignment*> it(preparsed_list); !it.Done(); it.Next()) {
    syntax_asdl::ParsedAssignment* preparsed = it.Value();
    StackRoot _for(&preparsed  );
    if (word_::HasArrayPart(preparsed->w)) {
      p_die(str1437, Alloc<loc::Word>(preparsed->w));
    }
  }
  part0 = suffix_words->at(0)->parts->at(0);
  blame_tok = location::LeftTokenForWordPart(part0);
  words2 = braces::BraceDetectAll(suffix_words);
  words3 = word_::TildeDetectAll(words2);
  more_env = Alloc<List<syntax_asdl::EnvPair*>>();
  _AppendMoreEnv(preparsed_list, more_env);
  return Alloc<command::Simple>(blame_tok, more_env, words3, typed_args, block, true);
}

VarChecker::VarChecker() {
  this->tokens = Alloc<List<syntax_asdl::Token*>>();
  this->names = Alloc<List<Dict<BigStr*, int>*>>();
}

void VarChecker::Push(syntax_asdl::Token* blame_tok) {
  Dict<BigStr*, int>* entry = nullptr;
  StackRoot _root0(&blame_tok);
  StackRoot _root1(&entry);

  if (len(this->tokens) != 0) {
    if (blame_tok->id == Id::KW_Proc) {
      p_die(str1439, blame_tok);
    }
    if (blame_tok->id == Id::KW_Func) {
      p_die(str1440, blame_tok);
    }
    if ((this->tokens->at(0)->id == Id::KW_Proc || this->tokens->at(0)->id == Id::KW_Func)) {
      p_die(str1441, blame_tok);
    }
  }
  this->tokens->append(blame_tok);
  entry = Alloc<Dict<BigStr*, int>>();
  this->names->append(entry);
}

void VarChecker::Pop() {
  this->names->pop();
  this->tokens->pop();
}

void VarChecker::Check(int keyword_id, BigStr* var_name, syntax_asdl::Token* blame_tok) {
  Dict<BigStr*, int>* top = nullptr;
  StackRoot _root0(&var_name);
  StackRoot _root1(&blame_tok);
  StackRoot _root2(&top);

  if (len(this->names) == 0) {
    return ;
  }
  top = this->names->at(-1);
  if (keyword_id == Id::KW_Var) {
    if (dict_contains(top, var_name)) {
      p_die(StrFormat("%r was already declared", var_name), blame_tok);
    }
    else {
      top->set(var_name, keyword_id);
    }
  }
  if (keyword_id == Id::KW_SetVar) {
    if (!dict_contains(top, var_name)) {
      p_die(StrFormat("setvar couldn't find matching 'var %s' (OILS-ERR-10)", var_name), blame_tok);
    }
  }
}

ctx_VarChecker::ctx_VarChecker(cmd_parse::VarChecker* var_checker, syntax_asdl::Token* blame_tok) {
  gHeap.PushRoot(reinterpret_cast<RawObject**>(&(this->var_checker)));
  var_checker->Push(blame_tok);
  this->var_checker = var_checker;
}

ctx_VarChecker::~ctx_VarChecker() {
  this->var_checker->Pop();
  gHeap.PopRoot();
}

ctx_CmdMode::ctx_CmdMode(cmd_parse::CommandParser* cmd_parse, types_asdl::cmd_mode_t new_cmd_mode) {
  gHeap.PushRoot(reinterpret_cast<RawObject**>(&(this->cmd_parse)));
  this->cmd_parse = cmd_parse;
  this->prev_cmd_mode = cmd_parse->cmd_mode;
  cmd_parse->cmd_mode = new_cmd_mode;
}

ctx_CmdMode::~ctx_CmdMode() {
  this->cmd_parse->cmd_mode = this->prev_cmd_mode;
  gHeap.PopRoot();
}
GLOBAL_LIST(SECONDARY_KEYWORDS, int, 7, {Id::KW_Do COMMA Id::KW_Done COMMA Id::KW_Then COMMA Id::KW_Fi COMMA Id::KW_Elif COMMA Id::KW_Else COMMA Id::KW_Esac});

CommandParser::CommandParser(parse_lib::ParseContext* parse_ctx, optview::Parse* parse_opts, word_parse::WordParser* w_parser, lexer::Lexer* lexer, reader::_Reader* line_reader, int eof_id) {
  this->parse_ctx = parse_ctx;
  this->aliases = parse_ctx->aliases;
  this->parse_opts = parse_opts;
  this->w_parser = w_parser;
  this->lexer = lexer;
  this->line_reader = line_reader;
  this->eof_id = eof_id;
  this->arena = line_reader->arena;
  this->aliases_in_flight = Alloc<List<Tuple2<BigStr*, int>*>>();
  this->allow_block = true;
  this->hay_attrs_stack = Alloc<List<bool>>();
  this->var_checker = Alloc<VarChecker>();
  this->cmd_mode = cmd_mode_e::Shell;
  this->Reset();
}

void CommandParser::Init_AliasesInFlight(List<Tuple2<BigStr*, int>*>* aliases_in_flight) {
  StackRoot _root0(&aliases_in_flight);

  this->aliases_in_flight = aliases_in_flight;
}

void CommandParser::Reset() {
  this->next_lex_mode = lex_mode_e::ShCommand;
  this->cur_word = nullptr;
  this->c_kind = Kind::Undefined;
  this->c_id = Id::Undefined_Tok;
  this->pending_here_docs = Alloc<List<syntax_asdl::Redir*>>();
}

void CommandParser::ResetInputObjects() {
  this->w_parser->Reset();
  this->lexer->ResetInputObjects();
  this->line_reader->Reset();
}

void CommandParser::_SetNext() {
  this->next_lex_mode = lex_mode_e::ShCommand;
}

void CommandParser::_SetNextBrack() {
  this->next_lex_mode = lex_mode_e::ShCommandFakeBrack;
}

void CommandParser::_GetWord() {
  syntax_asdl::word_t* w = nullptr;
  Token* tok = nullptr;
  StackRoot _root0(&w);
  StackRoot _root1(&tok);

  if (this->next_lex_mode != lex_mode_e::Undefined) {
    w = this->w_parser->ReadWord(this->next_lex_mode);
    if (w->tag() == word_e::Operator) {
      tok = static_cast<Token*>(w);
      if (tok->id == Id::Op_Newline) {
        for (ListIter<syntax_asdl::Redir*> it(this->pending_here_docs); !it.Done(); it.Next()) {
          syntax_asdl::Redir* h = it.Value();
          StackRoot _for(&h        );
          _ParseHereDocBody(this->parse_ctx, h, this->line_reader, this->arena);
        }
        this->pending_here_docs->clear();
      }
    }
    this->cur_word = w;
    this->c_kind = word_::CommandKind(this->cur_word);
    this->c_id = word_::CommandId(this->cur_word);
    this->next_lex_mode = lex_mode_e::Undefined;
  }
}

syntax_asdl::word_t* CommandParser::_Eat(int c_id, BigStr* msg) {
  syntax_asdl::word_t* skipped = nullptr;
  StackRoot _root0(&msg);
  StackRoot _root1(&skipped);

  this->_GetWord();
  if (this->c_id != c_id) {
    if (msg == nullptr) {
      msg = StrFormat("Expected word type %s, got %s", ui::PrettyId(c_id), ui::PrettyId(this->c_id));
    }
    p_die(msg, Alloc<loc::Word>(this->cur_word));
  }
  skipped = this->cur_word;
  this->_SetNext();
  return skipped;
}

void CommandParser::_NewlineOk() {
  this->_GetWord();
  if (this->c_id == Id::Op_Newline) {
    this->_SetNext();
  }
}

bool CommandParser::_AtSecondaryKeyword() {
  this->_GetWord();
  if (list_contains(SECONDARY_KEYWORDS, this->c_id)) {
    return true;
  }
  return false;
}

syntax_asdl::Redir* CommandParser::ParseRedirect() {
  Token* op_tok = nullptr;
  BigStr* op_val = nullptr;
  int pos;
  syntax_asdl::redir_loc_t* where = nullptr;
  redir_param::HereDoc* arg = nullptr;
  syntax_asdl::Redir* r = nullptr;
  syntax_asdl::word_t* arg_word = nullptr;
  syntax_asdl::CompoundWord* tilde = nullptr;
  StackRoot _root0(&op_tok);
  StackRoot _root1(&op_val);
  StackRoot _root2(&where);
  StackRoot _root3(&arg);
  StackRoot _root4(&r);
  StackRoot _root5(&arg_word);
  StackRoot _root6(&tilde);

  this->_GetWord();
  op_tok = static_cast<Token*>(this->cur_word);
  op_val = lexer::TokenVal(op_tok);
  if (str_equals(op_val->at(0), str1445)) {
    pos = op_val->find(str1446);
    where = Alloc<redir_loc::VarName>(op_val->slice(1, pos));
  }
  else {
    if (op_val->at(0)->isdigit()) {
      pos = 1;
      if (op_val->at(1)->isdigit()) {
        pos = 2;
      }
      where = Alloc<redir_loc::Fd>(to_int(op_val->slice(0, pos)));
    }
    else {
      where = Alloc<redir_loc::Fd>(consts::RedirDefaultFd(op_tok->id));
    }
  }
  this->_SetNext();
  this->_GetWord();
  if (this->c_kind != Kind::Word) {
    p_die(str1447, Alloc<loc::Word>(this->cur_word));
  }
  if ((op_tok->id == Id::Redir_DLess || op_tok->id == Id::Redir_DLessDash)) {
    arg = redir_param::HereDoc::CreateNull();
    arg->here_begin = this->cur_word;
    arg->stdin_parts = Alloc<List<syntax_asdl::word_part_t*>>();
    r = Alloc<Redir>(op_tok, where, arg);
    this->pending_here_docs->append(r);
    this->_SetNext();
    return r;
  }
  arg_word = this->cur_word;
  tilde = word_::TildeDetect(arg_word);
  if (tilde) {
    arg_word = tilde;
  }
  this->_SetNext();
  return Alloc<Redir>(op_tok, where, static_cast<CompoundWord*>(arg_word));
}

List<syntax_asdl::Redir*>* CommandParser::_ParseRedirectList() {
  List<syntax_asdl::Redir*>* redirects = nullptr;
  syntax_asdl::Redir* node = nullptr;
  StackRoot _root0(&redirects);
  StackRoot _root1(&node);

  redirects = Alloc<List<syntax_asdl::Redir*>>();
  while (true) {
    this->_GetWord();
    if (this->c_kind != Kind::Redir) {
      break;
    }
    node = this->ParseRedirect();
    redirects->append(node);
    this->_SetNext();
  }
  return redirects;
}

syntax_asdl::command_t* CommandParser::_MaybeParseRedirectList(syntax_asdl::command_t* node) {
  List<syntax_asdl::Redir*>* redirects = nullptr;
  StackRoot _root0(&node);
  StackRoot _root1(&redirects);

  this->_GetWord();
  if (this->c_kind != Kind::Redir) {
    return node;
  }
  redirects = NewList<syntax_asdl::Redir*>(std::initializer_list<syntax_asdl::Redir*>{this->ParseRedirect()});
  while (true) {
    this->_GetWord();
    if (this->c_kind != Kind::Redir) {
      break;
    }
    redirects->append(this->ParseRedirect());
    this->_SetNext();
  }
  return Alloc<command::Redirect>(node, redirects);
}

Tuple4<List<syntax_asdl::Redir*>*, List<syntax_asdl::CompoundWord*>*, syntax_asdl::ArgList*, syntax_asdl::LiteralBlock*> CommandParser::_ScanSimpleCommand() {
  List<syntax_asdl::Redir*>* redirects = nullptr;
  List<syntax_asdl::CompoundWord*>* words = nullptr;
  syntax_asdl::ArgList* typed_args = nullptr;
  syntax_asdl::LiteralBlock* block = nullptr;
  bool first_word_caps;
  int i;
  id_kind_asdl::Kind_t kind2;
  syntax_asdl::Redir* node = nullptr;
  CompoundWord* w = nullptr;
  syntax_asdl::word_part_t* part0 = nullptr;
  Token* tok = nullptr;
  bool ok;
  BigStr* word_str = nullptr;
  bool quoted;
  int prev_byte;
  int next_id;
  syntax_asdl::BraceGroup* brace_group = nullptr;
  List<syntax_asdl::SourceLine*>* lines = nullptr;
  StackRoot _root0(&redirects);
  StackRoot _root1(&words);
  StackRoot _root2(&typed_args);
  StackRoot _root3(&block);
  StackRoot _root4(&node);
  StackRoot _root5(&w);
  StackRoot _root6(&part0);
  StackRoot _root7(&tok);
  StackRoot _root8(&word_str);
  StackRoot _root9(&brace_group);
  StackRoot _root10(&lines);

  redirects = Alloc<List<syntax_asdl::Redir*>>();
  words = Alloc<List<syntax_asdl::CompoundWord*>>();
  typed_args = nullptr;
  block = nullptr;
  first_word_caps = false;
  i = 0;
  while (true) {
    this->_GetWord();
    kind2 = this->c_kind;
    if ((kind2 == Kind::Word and (this->parse_opts->parse_brace() and (this->c_id == Id::Lit_LBrace || this->c_id == Id::Lit_RBrace)))) {
      kind2 = Kind::Op;
    }
    if (kind2 == Kind::Redir) {
      node = this->ParseRedirect();
      redirects->append(node);
    }
    else {
      if (kind2 == Kind::Word) {
        w = static_cast<CompoundWord*>(this->cur_word);
        if (i == 0) {
          part0 = w->parts->at(0);
          if (part0->tag() == word_part_e::Literal) {
            tok = static_cast<Token*>(part0);
            if (tok->id == Id::Lit_Equals) {
              p_die(str1448, tok);
            }
          }
          Tuple3<bool, BigStr*, bool> tup6 = word_::StaticEval(w);
          ok = tup6.at0();
          word_str = tup6.at1();
          quoted = tup6.at2();
          if ((ok and (len(word_str) and (word_str->at(0)->isupper() and !word_str->isupper())))) {
            first_word_caps = true;
          }
        }
        words->append(w);
      }
      else {
        break;
      }
    }
    this->_SetNextBrack();
    i += 1;
  }
  this->_GetWord();
  if (this->c_id == Id::Op_LParen) {
    prev_byte = this->lexer->ByteLookBack();
    if ((prev_byte != SPACE_CH && prev_byte != TAB_CH)) {
      if (this->parse_opts->parse_at()) {
        p_die(str1449, Alloc<loc::Word>(this->cur_word));
      }
      else {
        p_die(str1450, Alloc<loc::Word>(this->cur_word));
      }
    }
    next_id = this->lexer->LookPastSpace(lex_mode_e::ShCommand);
    if (next_id == Id::Op_RParen) {
      p_die(str1451, Alloc<loc::Word>(this->cur_word));
    }
    typed_args = this->w_parser->ParseProcCallArgs(grammar_nt::ysh_eager_arglist);
    this->_SetNext();
  }
  else {
    if (this->c_id == Id::Op_LBracket) {
      typed_args = this->w_parser->ParseProcCallArgs(grammar_nt::ysh_lazy_arglist);
      this->_SetNext();
    }
  }
  this->_GetWord();
  if (this->c_kind == Kind::Redir) {
    redirects->extend(this->_ParseRedirectList());
  }
  if ((this->parse_opts->parse_brace() and (this->c_id == Id::Lit_LBrace and this->allow_block))) {
    this->hay_attrs_stack->append(first_word_caps);
    brace_group = this->ParseBraceGroup();
    lines = this->arena->SaveLinesAndDiscard(brace_group->left, brace_group->right);
    block = Alloc<LiteralBlock>(brace_group, lines);
    this->hay_attrs_stack->pop();
  }
  this->_GetWord();
  if (this->c_kind == Kind::Redir) {
    redirects->extend(this->_ParseRedirectList());
  }
  return Tuple4<List<syntax_asdl::Redir*>*, List<syntax_asdl::CompoundWord*>*, syntax_asdl::ArgList*, syntax_asdl::LiteralBlock*>(redirects, words, typed_args, block);
}

syntax_asdl::command_t* CommandParser::_MaybeExpandAliases(List<syntax_asdl::CompoundWord*>* words) {
  List<Tuple2<BigStr*, int>*>* aliases_in_flight = nullptr;
  BigStr* first_word_str = nullptr;
  loc::Word* argv0_loc = nullptr;
  List<BigStr*>* expanded = nullptr;
  int i;
  int n;
  syntax_asdl::CompoundWord* w = nullptr;
  bool ok;
  BigStr* word_str = nullptr;
  bool quoted;
  BigStr* alias_exp = nullptr;
  syntax_asdl::Token* left_tok = nullptr;
  syntax_asdl::Token* right_tok = nullptr;
  BigStr* words_str = nullptr;
  BigStr* code_str = nullptr;
  alloc::Arena* arena = nullptr;
  reader::FileLineReader* line_reader = nullptr;
  cmd_parse::CommandParser* cp = nullptr;
  source::Alias* src = nullptr;
  command::CommandList* node = nullptr;
  StackRoot _root0(&words);
  StackRoot _root1(&aliases_in_flight);
  StackRoot _root2(&first_word_str);
  StackRoot _root3(&argv0_loc);
  StackRoot _root4(&expanded);
  StackRoot _root5(&w);
  StackRoot _root6(&word_str);
  StackRoot _root7(&alias_exp);
  StackRoot _root8(&left_tok);
  StackRoot _root9(&right_tok);
  StackRoot _root10(&words_str);
  StackRoot _root11(&code_str);
  StackRoot _root12(&arena);
  StackRoot _root13(&line_reader);
  StackRoot _root14(&cp);
  StackRoot _root15(&src);
  StackRoot _root16(&node);

  aliases_in_flight = len(this->aliases_in_flight) ? this->aliases_in_flight : Alloc<List<Tuple2<BigStr*, int>*>>();
  first_word_str = nullptr;
  argv0_loc = Alloc<loc::Word>(words->at(0));
  expanded = Alloc<List<BigStr*>>();
  i = 0;
  n = len(words);
  while (i < n) {
    w = words->at(i);
    Tuple3<bool, BigStr*, bool> tup7 = word_::StaticEval(w);
    ok = tup7.at0();
    word_str = tup7.at1();
    quoted = tup7.at2();
    if ((!ok or quoted)) {
      break;
    }
    alias_exp = this->aliases->get(word_str);
    if (alias_exp == nullptr) {
      break;
    }
    if (list_contains(aliases_in_flight, (Alloc<Tuple2<BigStr*, int>>(word_str, i)))) {
      break;
    }
    if (i == 0) {
      first_word_str = word_str;
    }
    aliases_in_flight->append((Alloc<Tuple2<BigStr*, int>>(word_str, i)));
    expanded->append(alias_exp);
    i += 1;
    if (!alias_exp->endswith(str1452)) {
      expanded->append(str1453);
      break;
    }
  }
  if (len(expanded) == 0) {
    return nullptr;
  }
  if (i < n) {
    left_tok = location::LeftTokenForWord(words->at(i));
    right_tok = location::RightTokenForWord(words->at(-1));
    words_str = this->arena->SnipCodeString(left_tok, right_tok);
    expanded->append(words_str);
  }
  code_str = str1454->join(expanded);
  arena = this->arena;
  line_reader = reader::StringLineReader(code_str, arena);
  cp = this->parse_ctx->MakeOshParser(line_reader);
  cp->Init_AliasesInFlight(aliases_in_flight);
  src = Alloc<source::Alias>(first_word_str, argv0_loc);
  {  // with
    alloc::ctx_SourceCode ctx{arena, src};

    {  // with
      parse_lib::ctx_Alias ctx{this->parse_ctx->trail};

      try {
        node = cp->_ParseCommandTerm();
      }
      catch (error::Parse* e) {
        throw ;
      }
    }
  }
  return node;
}

syntax_asdl::command_t* CommandParser::ParseSimpleCommand() {
  List<syntax_asdl::Redir*>* redirects = nullptr;
  List<syntax_asdl::CompoundWord*>* words = nullptr;
  syntax_asdl::ArgList* typed_args = nullptr;
  syntax_asdl::LiteralBlock* block = nullptr;
  syntax_asdl::Token* typed_loc = nullptr;
  List<syntax_asdl::ParsedAssignment*>* preparsed_list = nullptr;
  List<syntax_asdl::CompoundWord*>* suffix_words = nullptr;
  List<syntax_asdl::AssignPair*>* pairs = nullptr;
  syntax_asdl::Token* left_tok = nullptr;
  command::ShAssignment* assign_node = nullptr;
  id_kind_asdl::Kind_t kind;
  syntax_asdl::Token* kw_token = nullptr;
  syntax_asdl::word_t* arg_word = nullptr;
  syntax_asdl::command_t* expanded_node = nullptr;
  List<syntax_asdl::EnvPair*>* more_env = nullptr;
  command::ExpandedAlias* exp = nullptr;
  command::Simple* node = nullptr;
  StackRoot _root0(&redirects);
  StackRoot _root1(&words);
  StackRoot _root2(&typed_args);
  StackRoot _root3(&block);
  StackRoot _root4(&typed_loc);
  StackRoot _root5(&preparsed_list);
  StackRoot _root6(&suffix_words);
  StackRoot _root7(&pairs);
  StackRoot _root8(&left_tok);
  StackRoot _root9(&assign_node);
  StackRoot _root10(&kw_token);
  StackRoot _root11(&arg_word);
  StackRoot _root12(&expanded_node);
  StackRoot _root13(&more_env);
  StackRoot _root14(&exp);
  StackRoot _root15(&node);

  Tuple4<List<syntax_asdl::Redir*>*, List<syntax_asdl::CompoundWord*>*, syntax_asdl::ArgList*, syntax_asdl::LiteralBlock*> tup8 = this->_ScanSimpleCommand();
  redirects = tup8.at0();
  words = tup8.at1();
  typed_args = tup8.at2();
  block = tup8.at3();
  typed_loc = nullptr;
  if (block) {
    typed_loc = block->brace_group->left;
  }
  if (typed_args) {
    typed_loc = typed_args->left;
  }
  if (len(words) == 0) {
    if (typed_loc != nullptr) {
      p_die(str1456, typed_loc);
    }
    return Alloc<command::Redirect>(command::NoOp, redirects);
  }
  Tuple2<List<syntax_asdl::ParsedAssignment*>*, List<syntax_asdl::CompoundWord*>*> tup9 = _SplitSimpleCommandPrefix(words);
  preparsed_list = tup9.at0();
  suffix_words = tup9.at1();
  if (len(preparsed_list)) {
    if (len(suffix_words) == 0) {
      if ((this->cmd_mode != cmd_mode_e::Shell or (len(this->hay_attrs_stack) and this->hay_attrs_stack->at(-1)))) {
        p_die(str1457, preparsed_list->at(0)->left);
      }
    }
  }
  this->parse_ctx->trail->SetLatestWords(suffix_words, redirects);
  if (len(suffix_words) == 0) {
    if (typed_loc != nullptr) {
      p_die(str1458, typed_loc);
    }
    pairs = Alloc<List<syntax_asdl::AssignPair*>>();
    for (ListIter<syntax_asdl::ParsedAssignment*> it(preparsed_list); !it.Done(); it.Next()) {
      syntax_asdl::ParsedAssignment* preparsed = it.Value();
      StackRoot _for(&preparsed    );
      pairs->append(_MakeAssignPair(this->parse_ctx, preparsed, this->arena));
    }
    left_tok = location::LeftTokenForCompoundWord(words->at(0));
    assign_node = Alloc<command::ShAssignment>(left_tok, pairs);
    if (len(redirects)) {
      return Alloc<command::Redirect>(assign_node, redirects);
    }
    else {
      return assign_node;
    }
  }
  Tuple2<id_kind_asdl::Kind_t, syntax_asdl::Token*> tup10 = word_::IsControlFlow(suffix_words->at(0));
  kind = tup10.at0();
  kw_token = tup10.at1();
  if (kind == Kind::ControlFlow) {
    if ((!this->parse_opts->parse_ignored() and len(redirects))) {
      p_die(str1459, kw_token);
    }
    if (len(preparsed_list)) {
      p_die(str1460, preparsed_list->at(0)->left);
    }
    if (kw_token->id == Id::ControlFlow_Return) {
      if (typed_args == nullptr) {
        if ((this->cmd_mode != cmd_mode_e::Shell && this->cmd_mode != cmd_mode_e::Proc)) {
          p_die(str1461, kw_token);
        }
      }
      else {
        if (this->cmd_mode != cmd_mode_e::Func) {
          p_die(str1462, typed_loc);
        }
        if (len(typed_args->pos_args) != 1) {
          p_die(str1463, typed_loc);
        }
        if (len(typed_args->named_args) != 0) {
          p_die(str1464, typed_loc);
        }
        return Alloc<command::Retval>(kw_token, typed_args->pos_args->at(0));
      }
    }
    if (typed_loc != nullptr) {
      p_die(str1465, typed_loc);
    }
    if (len(suffix_words) == 1) {
      arg_word = nullptr;
    }
    else {
      if (len(suffix_words) == 2) {
        arg_word = suffix_words->at(1);
      }
      else {
        p_die(StrFormat("Unexpected argument to %r", lexer::TokenVal(kw_token)), Alloc<loc::Word>(suffix_words->at(2)));
      }
    }
    return Alloc<command::ControlFlow>(kw_token, arg_word);
  }
  if ((!typed_args and (!block and this->parse_opts->expand_aliases()))) {
    expanded_node = this->_MaybeExpandAliases(suffix_words);
    if (expanded_node) {
      more_env = Alloc<List<syntax_asdl::EnvPair*>>();
      _AppendMoreEnv(preparsed_list, more_env);
      exp = Alloc<command::ExpandedAlias>(expanded_node, more_env);
      if (len(redirects)) {
        return Alloc<command::Redirect>(exp, redirects);
      }
      else {
        return exp;
      }
    }
  }
  node = _MakeSimpleCommand(preparsed_list, suffix_words, typed_args, block);
  if (len(redirects)) {
    return Alloc<command::Redirect>(node, redirects);
  }
  else {
    return node;
  }
}

syntax_asdl::BraceGroup* CommandParser::ParseBraceGroup() {
  syntax_asdl::word_t* ate = nullptr;
  syntax_asdl::Token* left = nullptr;
  syntax_asdl::word_t* doc_word = nullptr;
  Token* doc_token = nullptr;
  command::CommandList* c_list = nullptr;
  syntax_asdl::Token* right = nullptr;
  StackRoot _root0(&ate);
  StackRoot _root1(&left);
  StackRoot _root2(&doc_word);
  StackRoot _root3(&doc_token);
  StackRoot _root4(&c_list);
  StackRoot _root5(&right);

  ate = this->_Eat(Id::Lit_LBrace);
  left = word_::BraceToken(ate);
  doc_word = nullptr;
  this->_GetWord();
  if (this->c_id == Id::Op_Newline) {
    this->_SetNext();
    {  // with
      word_::ctx_EmitDocToken ctx{this->w_parser};

      this->_GetWord();
    }
  }
  if (this->c_id == Id::Ignored_Comment) {
    doc_word = this->cur_word;
    this->_SetNext();
  }
  doc_token = static_cast<Token*>(doc_word);
  c_list = this->_ParseCommandList();
  ate = this->_Eat(Id::Lit_RBrace);
  right = word_::BraceToken(ate);
  return Alloc<BraceGroup>(left, doc_token, c_list->children, right);
}

command::DoGroup* CommandParser::ParseDoGroup() {
  syntax_asdl::word_t* ate = nullptr;
  syntax_asdl::Token* do_kw = nullptr;
  command::CommandList* c_list = nullptr;
  syntax_asdl::Token* done_kw = nullptr;
  StackRoot _root0(&ate);
  StackRoot _root1(&do_kw);
  StackRoot _root2(&c_list);
  StackRoot _root3(&done_kw);

  ate = this->_Eat(Id::KW_Do);
  do_kw = word_::AsKeywordToken(ate);
  c_list = this->_ParseCommandList();
  ate = this->_Eat(Id::KW_Done);
  done_kw = word_::AsKeywordToken(ate);
  return Alloc<command::DoGroup>(do_kw, c_list->children, done_kw);
}

Tuple2<List<syntax_asdl::CompoundWord*>*, syntax_asdl::Token*> CommandParser::ParseForWords() {
  List<syntax_asdl::CompoundWord*>* words = nullptr;
  syntax_asdl::Token* semi_tok = nullptr;
  Token* tok = nullptr;
  CompoundWord* w2 = nullptr;
  StackRoot _root0(&words);
  StackRoot _root1(&semi_tok);
  StackRoot _root2(&tok);
  StackRoot _root3(&w2);

  words = Alloc<List<syntax_asdl::CompoundWord*>>();
  semi_tok = nullptr;
  while (true) {
    this->_GetWord();
    if (this->c_id == Id::Op_Semi) {
      tok = static_cast<Token*>(this->cur_word);
      semi_tok = tok;
      this->_SetNext();
      this->_NewlineOk();
      break;
    }
    else {
      if (this->c_id == Id::Op_Newline) {
        this->_SetNext();
        break;
      }
      else {
        if ((this->parse_opts->parse_brace() and this->c_id == Id::Lit_LBrace)) {
          break;
        }
      }
    }
    if (this->cur_word->tag() != word_e::Compound) {
      p_die(str1467, Alloc<loc::Word>(this->cur_word));
    }
    w2 = static_cast<CompoundWord*>(this->cur_word);
    words->append(w2);
    this->_SetNext();
  }
  return Tuple2<List<syntax_asdl::CompoundWord*>*, syntax_asdl::Token*>(words, semi_tok);
}

command::ForExpr* CommandParser::_ParseForExprLoop(syntax_asdl::Token* for_kw) {
  command::ForExpr* node = nullptr;
  StackRoot _root0(&for_kw);
  StackRoot _root1(&node);

  node = this->w_parser->ReadForExpression();
  node->keyword = for_kw;
  this->_SetNext();
  this->_GetWord();
  if (this->c_id == Id::Op_Semi) {
    this->_SetNext();
    this->_NewlineOk();
  }
  else {
    if (this->c_id == Id::Op_Newline) {
      this->_SetNext();
    }
    else {
      if (this->c_id == Id::KW_Do) {
        ;  // pass
      }
      else {
        if (this->c_id == Id::Lit_LBrace) {
          ;  // pass
        }
        else {
          p_die(str1468, Alloc<loc::Word>(this->cur_word));
        }
      }
    }
  }
  if (this->c_id == Id::Lit_LBrace) {
    node->body = this->ParseBraceGroup();
  }
  else {
    node->body = this->ParseDoGroup();
  }
  return node;
}

command::ForEach* CommandParser::_ParseForEachLoop(syntax_asdl::Token* for_kw) {
  command::ForEach* node = nullptr;
  int num_iter_names;
  syntax_asdl::word_t* w = nullptr;
  syntax_asdl::word_t* UP_w = nullptr;
  bool ok;
  BigStr* iter_name = nullptr;
  bool quoted;
  syntax_asdl::Token* expr_blame = nullptr;
  int next_id;
  syntax_asdl::expr_t* enode = nullptr;
  syntax_asdl::Token* semi_tok = nullptr;
  List<syntax_asdl::CompoundWord*>* iter_words = nullptr;
  BigStr* s = nullptr;
  List<syntax_asdl::word_t*>* words2 = nullptr;
  List<syntax_asdl::word_t*>* words3 = nullptr;
  StackRoot _root0(&for_kw);
  StackRoot _root1(&node);
  StackRoot _root2(&w);
  StackRoot _root3(&UP_w);
  StackRoot _root4(&iter_name);
  StackRoot _root5(&expr_blame);
  StackRoot _root6(&enode);
  StackRoot _root7(&semi_tok);
  StackRoot _root8(&iter_words);
  StackRoot _root9(&s);
  StackRoot _root10(&words2);
  StackRoot _root11(&words3);

  node = command::ForEach::CreateNull(true);
  node->keyword = for_kw;
  num_iter_names = 0;
  while (true) {
    w = this->cur_word;
    UP_w = w;
    if (w->tag() == word_e::Compound) {
      CompoundWord* w = static_cast<CompoundWord*>(UP_w);
      if (word_::LiteralId(w->parts->at(-1)) == Id::Lit_Comma) {
        w->parts->pop();
      }
    }
    Tuple3<bool, BigStr*, bool> tup11 = word_::StaticEval(w);
    ok = tup11.at0();
    iter_name = tup11.at1();
    quoted = tup11.at2();
    if ((!ok or quoted)) {
      p_die(str1469, Alloc<loc::Word>(w));
    }
    if (!match::IsValidVarName(iter_name)) {
      if (str_contains(iter_name, str1470)) {
        p_die(str1471, Alloc<loc::Word>(w));
      }
      p_die(StrFormat("Invalid loop variable name %r", iter_name), Alloc<loc::Word>(w));
    }
    node->iter_names->append(iter_name);
    num_iter_names += 1;
    this->_SetNext();
    this->_GetWord();
    if (((this->c_id == Id::KW_In || this->c_id == Id::KW_Do) or this->c_kind == Kind::Op)) {
      break;
    }
    if (num_iter_names == 3) {
      p_die(str1473, Alloc<loc::Word>(this->cur_word));
    }
  }
  this->_NewlineOk();
  this->_GetWord();
  if (this->c_id == Id::KW_In) {
    expr_blame = word_::AsKeywordToken(this->cur_word);
    this->_SetNext();
    next_id = this->w_parser->LookPastSpace();
    if (next_id == Id::Op_LParen) {
      enode = this->w_parser->ParseYshExprForCommand();
      node->iterable = Alloc<for_iter::YshExpr>(enode, expr_blame);
      this->_GetWord();
      if (this->c_id != Id::Lit_LBrace) {
        p_die(str1474, Alloc<loc::Word>(this->cur_word));
      }
    }
    else {
      if (next_id == Id::Redir_LessGreat) {
        w = this->_Eat(Id::Redir_LessGreat);
        p_die(str1475, Alloc<loc::Word>(this->cur_word));
      }
      else {
        if (next_id == Id::Redir_Less) {
          w = this->_Eat(Id::Redir_Less);
          p_die(str1476, Alloc<loc::Word>(this->cur_word));
        }
        else {
          semi_tok = nullptr;
          Tuple2<List<syntax_asdl::CompoundWord*>*, syntax_asdl::Token*> tup12 = this->ParseForWords();
          iter_words = tup12.at0();
          semi_tok = tup12.at1();
          node->semi_tok = semi_tok;
          if ((!this->parse_opts->parse_bare_word() and len(iter_words) == 1)) {
            Tuple3<bool, BigStr*, bool> tup13 = word_::StaticEval(iter_words->at(0));
            ok = tup13.at0();
            s = tup13.at1();
            quoted = tup13.at2();
            if ((ok and (match::IsValidVarName(s) and !quoted))) {
              p_die(str1477, Alloc<loc::Word>(iter_words->at(0)));
            }
          }
          words2 = braces::BraceDetectAll(iter_words);
          words3 = word_::TildeDetectAll(words2);
          node->iterable = Alloc<for_iter::Words>(words3);
          if (num_iter_names > 2) {
            p_die(str1478, for_kw);
          }
        }
      }
    }
  }
  else {
    if (this->c_id == Id::KW_Do) {
      node->iterable = for_iter::Args;
    }
    else {
      if (this->c_id == Id::Op_Semi) {
        node->iterable = for_iter::Args;
        this->_SetNext();
      }
      else {
        p_die(str1479, Alloc<loc::Word>(this->cur_word));
      }
    }
  }
  this->_GetWord();
  if (this->c_id == Id::Lit_LBrace) {
    node->body = this->ParseBraceGroup();
  }
  else {
    node->body = this->ParseDoGroup();
  }
  return node;
}

syntax_asdl::command_t* CommandParser::ParseFor() {
  syntax_asdl::word_t* ate = nullptr;
  syntax_asdl::Token* for_kw = nullptr;
  command::ForExpr* n1 = nullptr;
  command::ForEach* n2 = nullptr;
  StackRoot _root0(&ate);
  StackRoot _root1(&for_kw);
  StackRoot _root2(&n1);
  StackRoot _root3(&n2);

  ate = this->_Eat(Id::KW_For);
  for_kw = word_::AsKeywordToken(ate);
  this->_GetWord();
  if (this->c_id == Id::Op_DLeftParen) {
    if (!this->parse_opts->parse_dparen()) {
      p_die(str1480, Alloc<loc::Word>(this->cur_word));
    }
    n1 = this->_ParseForExprLoop(for_kw);
    return this->_MaybeParseRedirectList(n1);
  }
  else {
    n2 = this->_ParseForEachLoop(for_kw);
    return this->_MaybeParseRedirectList(n2);
  }
}

syntax_asdl::condition_t* CommandParser::_ParseConditionList() {
  command::CommandList* commands = nullptr;
  StackRoot _root0(&commands);

  this->allow_block = false;
  commands = this->_ParseCommandList();
  this->allow_block = true;
  if (len(commands->children) == 0) {
    p_die(str1481, Alloc<loc::Word>(this->cur_word));
  }
  return Alloc<condition::Shell>(commands->children);
}

command::WhileUntil* CommandParser::ParseWhileUntil(syntax_asdl::Token* keyword) {
  syntax_asdl::expr_t* enode = nullptr;
  syntax_asdl::condition_t* cond = nullptr;
  syntax_asdl::command_t* body_node = nullptr;
  StackRoot _root0(&keyword);
  StackRoot _root1(&enode);
  StackRoot _root2(&cond);
  StackRoot _root3(&body_node);

  this->_SetNext();
  if ((this->parse_opts->parse_paren() and this->w_parser->LookPastSpace() == Id::Op_LParen)) {
    enode = this->w_parser->ParseYshExprForCommand();
    cond = Alloc<condition::YshExpr>(enode);
  }
  else {
    cond = this->_ParseConditionList();
  }
  this->_GetWord();
  if ((this->parse_opts->parse_brace() and this->c_id == Id::Lit_LBrace)) {
    body_node = this->ParseBraceGroup();
  }
  else {
    body_node = this->ParseDoGroup();
  }
  return Alloc<command::WhileUntil>(keyword, cond, body_node);
}

syntax_asdl::CaseArm* CommandParser::ParseCaseArm() {
  syntax_asdl::Token* left_tok = nullptr;
  List<syntax_asdl::word_t*>* pat_words = nullptr;
  syntax_asdl::word_t* ate = nullptr;
  syntax_asdl::Token* middle_tok = nullptr;
  command::CommandList* c_list = nullptr;
  List<syntax_asdl::command_t*>* action_children = nullptr;
  syntax_asdl::Token* dsemi_tok = nullptr;
  StackRoot _root0(&left_tok);
  StackRoot _root1(&pat_words);
  StackRoot _root2(&ate);
  StackRoot _root3(&middle_tok);
  StackRoot _root4(&c_list);
  StackRoot _root5(&action_children);
  StackRoot _root6(&dsemi_tok);

  this->lexer->PushHint(Id::Op_RParen, Id::Right_CasePat);
  left_tok = location::LeftTokenForWord(this->cur_word);
  if (this->c_id == Id::Op_LParen) {
    this->_SetNext();
  }
  pat_words = Alloc<List<syntax_asdl::word_t*>>();
  while (true) {
    this->_GetWord();
    if (this->c_kind != Kind::Word) {
      p_die(str1482, Alloc<loc::Word>(this->cur_word));
    }
    pat_words->append(this->cur_word);
    this->_SetNext();
    this->_GetWord();
    if (this->c_id == Id::Op_Pipe) {
      this->_SetNext();
    }
    else {
      break;
    }
  }
  ate = this->_Eat(Id::Right_CasePat);
  middle_tok = word_::AsOperatorToken(ate);
  this->_NewlineOk();
  this->_GetWord();
  if ((this->c_id != Id::Op_DSemi && this->c_id != Id::Op_SemiAmp && this->c_id != Id::Op_DSemiAmp && this->c_id != Id::KW_Esac)) {
    c_list = this->_ParseCommandTerm();
    action_children = c_list->children;
  }
  else {
    action_children = Alloc<List<syntax_asdl::command_t*>>();
  }
  dsemi_tok = nullptr;
  this->_GetWord();
  if (this->c_id == Id::KW_Esac) {
    ;  // pass
  }
  else {
    if ((this->c_id == Id::Op_DSemi || this->c_id == Id::Op_SemiAmp || this->c_id == Id::Op_DSemiAmp)) {
      dsemi_tok = word_::AsOperatorToken(this->cur_word);
      this->_SetNext();
    }
    else {
      p_die(str1483, Alloc<loc::Word>(this->cur_word));
    }
  }
  this->_NewlineOk();
  return Alloc<CaseArm>(left_tok, Alloc<pat::Words>(pat_words), middle_tok, action_children, dsemi_tok);
}

syntax_asdl::CaseArm* CommandParser::ParseYshCaseArm(int discriminant) {
  syntax_asdl::Token* left_tok = nullptr;
  syntax_asdl::pat_t* pattern = nullptr;
  List<syntax_asdl::word_t*>* pat_words = nullptr;
  syntax_asdl::BraceGroup* action = nullptr;
  StackRoot _root0(&left_tok);
  StackRoot _root1(&pattern);
  StackRoot _root2(&pat_words);
  StackRoot _root3(&action);

  left_tok = nullptr;
  pattern = nullptr;
  if ((discriminant == Id::Op_LParen || discriminant == Id::Arith_Slash)) {
    Tuple2<syntax_asdl::pat_t*, syntax_asdl::Token*> tup14 = this->w_parser->ParseYshCasePattern();
    pattern = tup14.at0();
    left_tok = tup14.at1();
  }
  else {
    pat_words = Alloc<List<syntax_asdl::word_t*>>();
    while (true) {
      this->_GetWord();
      if (this->c_kind != Kind::Word) {
        p_die(str1484, Alloc<loc::Word>(this->cur_word));
      }
      pat_words->append(this->cur_word);
      this->_SetNext();
      if (!left_tok) {
        left_tok = location::LeftTokenForWord(this->cur_word);
      }
      this->_NewlineOk();
      this->_GetWord();
      if (this->c_id == Id::Op_Pipe) {
        this->_SetNext();
        this->_NewlineOk();
      }
      else {
        break;
      }
    }
    pattern = Alloc<pat::Words>(pat_words);
  }
  this->_NewlineOk();
  action = this->ParseBraceGroup();
  return Alloc<CaseArm>(left_tok, pattern, action->left, action->children, action->right);
}

command::Case* CommandParser::ParseYshCase(syntax_asdl::Token* case_kw) {
  syntax_asdl::expr_t* enode = nullptr;
  case_arg::YshExpr* to_match = nullptr;
  syntax_asdl::word_t* ate = nullptr;
  syntax_asdl::Token* arms_start = nullptr;
  int discriminant;
  List<syntax_asdl::CaseArm*>* arms = nullptr;
  syntax_asdl::CaseArm* arm = nullptr;
  syntax_asdl::Token* arms_end = nullptr;
  StackRoot _root0(&case_kw);
  StackRoot _root1(&enode);
  StackRoot _root2(&to_match);
  StackRoot _root3(&ate);
  StackRoot _root4(&arms_start);
  StackRoot _root5(&arms);
  StackRoot _root6(&arm);
  StackRoot _root7(&arms_end);

  enode = this->w_parser->ParseYshExprForCommand();
  to_match = Alloc<case_arg::YshExpr>(enode);
  ate = this->_Eat(Id::Lit_LBrace);
  arms_start = word_::BraceToken(ate);
  discriminant = this->w_parser->NewlineOkForYshCase();
  arms = Alloc<List<syntax_asdl::CaseArm*>>();
  while (discriminant != Id::Op_RBrace) {
    arm = this->ParseYshCaseArm(discriminant);
    arms->append(arm);
    discriminant = this->w_parser->NewlineOkForYshCase();
  }
  ate = this->_Eat(Id::Op_RBrace);
  arms_end = word_::AsOperatorToken(ate);
  arms_end->id = Id::Lit_RBrace;
  return Alloc<command::Case>(case_kw, to_match, arms_start, arms, arms_end);
}

command::Case* CommandParser::ParseOldCase(syntax_asdl::Token* case_kw) {
  syntax_asdl::word_t* w = nullptr;
  bool ok;
  BigStr* s = nullptr;
  bool quoted;
  case_arg::Word* to_match = nullptr;
  syntax_asdl::word_t* ate = nullptr;
  syntax_asdl::Token* arms_start = nullptr;
  List<syntax_asdl::CaseArm*>* arms = nullptr;
  syntax_asdl::CaseArm* arm = nullptr;
  syntax_asdl::Token* arms_end = nullptr;
  StackRoot _root0(&case_kw);
  StackRoot _root1(&w);
  StackRoot _root2(&s);
  StackRoot _root3(&to_match);
  StackRoot _root4(&ate);
  StackRoot _root5(&arms_start);
  StackRoot _root6(&arms);
  StackRoot _root7(&arm);
  StackRoot _root8(&arms_end);

  this->_GetWord();
  w = this->cur_word;
  if (!this->parse_opts->parse_bare_word()) {
    Tuple3<bool, BigStr*, bool> tup15 = word_::StaticEval(w);
    ok = tup15.at0();
    s = tup15.at1();
    quoted = tup15.at2();
    if ((ok and !quoted)) {
      p_die(str1485, Alloc<loc::Word>(w));
    }
  }
  if (w->tag() != word_e::Compound) {
    p_die(str1486, Alloc<loc::Word>(w));
  }
  to_match = Alloc<case_arg::Word>(w);
  this->_SetNext();
  this->_NewlineOk();
  ate = this->_Eat(Id::KW_In);
  arms_start = word_::AsKeywordToken(ate);
  this->_NewlineOk();
  arms = Alloc<List<syntax_asdl::CaseArm*>>();
  while (true) {
    this->_GetWord();
    if (this->c_id == Id::KW_Esac) {
      break;
    }
    if ((this->c_kind != Kind::Word and this->c_id != Id::Op_LParen)) {
      break;
    }
    arm = this->ParseCaseArm();
    arms->append(arm);
  }
  ate = this->_Eat(Id::KW_Esac);
  arms_end = word_::AsKeywordToken(ate);
  return Alloc<command::Case>(case_kw, to_match, arms_start, arms, arms_end);
}

command::Case* CommandParser::ParseCase() {
  syntax_asdl::Token* case_kw = nullptr;
  StackRoot _root0(&case_kw);

  case_kw = word_::AsKeywordToken(this->cur_word);
  this->_SetNext();
  if (this->w_parser->LookPastSpace() == Id::Op_LParen) {
    return this->ParseYshCase(case_kw);
  }
  else {
    return this->ParseOldCase(case_kw);
  }
}

void CommandParser::_ParseYshElifElse(command::If* if_node) {
  List<syntax_asdl::IfArm*>* arms = nullptr;
  syntax_asdl::Token* elif_kw = nullptr;
  syntax_asdl::expr_t* enode = nullptr;
  syntax_asdl::condition_t* cond = nullptr;
  command::CommandList* commands = nullptr;
  syntax_asdl::BraceGroup* body = nullptr;
  syntax_asdl::IfArm* arm = nullptr;
  StackRoot _root0(&if_node);
  StackRoot _root1(&arms);
  StackRoot _root2(&elif_kw);
  StackRoot _root3(&enode);
  StackRoot _root4(&cond);
  StackRoot _root5(&commands);
  StackRoot _root6(&body);
  StackRoot _root7(&arm);

  arms = if_node->arms;
  while (this->c_id == Id::KW_Elif) {
    elif_kw = word_::AsKeywordToken(this->cur_word);
    this->_SetNext();
    if ((this->parse_opts->parse_paren() and this->w_parser->LookPastSpace() == Id::Op_LParen)) {
      enode = this->w_parser->ParseYshExprForCommand();
      cond = Alloc<condition::YshExpr>(enode);
    }
    else {
      this->allow_block = false;
      commands = this->_ParseCommandList();
      this->allow_block = true;
      cond = Alloc<condition::Shell>(commands->children);
    }
    body = this->ParseBraceGroup();
    this->_GetWord();
    arm = Alloc<IfArm>(elif_kw, cond, nullptr, body->children, nullptr);
    arms->append(arm);
  }
  this->_GetWord();
  if (this->c_id == Id::KW_Else) {
    this->_SetNext();
    body = this->ParseBraceGroup();
    if_node->else_action = body->children;
  }
}

command::If* CommandParser::_ParseYshIf(syntax_asdl::Token* if_kw, syntax_asdl::condition_t* cond) {
  command::If* if_node = nullptr;
  syntax_asdl::BraceGroup* body1 = nullptr;
  syntax_asdl::IfArm* arm = nullptr;
  StackRoot _root0(&if_kw);
  StackRoot _root1(&cond);
  StackRoot _root2(&if_node);
  StackRoot _root3(&body1);
  StackRoot _root4(&arm);

  if_node = command::If::CreateNull(true);
  if_node->if_kw = if_kw;
  body1 = this->ParseBraceGroup();
  arm = Alloc<IfArm>(if_kw, cond, nullptr, body1->children, nullptr);
  if_node->arms->append(arm);
  this->_GetWord();
  if ((this->c_id == Id::KW_Elif || this->c_id == Id::KW_Else)) {
    this->_ParseYshElifElse(if_node);
  }
  return if_node;
}

void CommandParser::_ParseElifElse(command::If* if_node) {
  List<syntax_asdl::IfArm*>* arms = nullptr;
  syntax_asdl::Token* elif_kw = nullptr;
  syntax_asdl::condition_t* cond = nullptr;
  syntax_asdl::word_t* ate = nullptr;
  syntax_asdl::Token* then_kw = nullptr;
  command::CommandList* body = nullptr;
  syntax_asdl::IfArm* arm = nullptr;
  syntax_asdl::Token* else_kw = nullptr;
  StackRoot _root0(&if_node);
  StackRoot _root1(&arms);
  StackRoot _root2(&elif_kw);
  StackRoot _root3(&cond);
  StackRoot _root4(&ate);
  StackRoot _root5(&then_kw);
  StackRoot _root6(&body);
  StackRoot _root7(&arm);
  StackRoot _root8(&else_kw);

  arms = if_node->arms;
  this->_GetWord();
  while (this->c_id == Id::KW_Elif) {
    elif_kw = word_::AsKeywordToken(this->cur_word);
    this->_SetNext();
    cond = this->_ParseConditionList();
    ate = this->_Eat(Id::KW_Then);
    then_kw = word_::AsKeywordToken(ate);
    body = this->_ParseCommandList();
    arm = Alloc<IfArm>(elif_kw, cond, then_kw, body->children, then_kw);
    arms->append(arm);
  }
  this->_GetWord();
  if (this->c_id == Id::KW_Else) {
    else_kw = word_::AsKeywordToken(this->cur_word);
    this->_SetNext();
    body = this->_ParseCommandList();
    if_node->else_action = body->children;
  }
  else {
    else_kw = nullptr;
  }
  if_node->else_kw = else_kw;
}

command::If* CommandParser::ParseIf() {
  command::If* if_node = nullptr;
  syntax_asdl::Token* if_kw = nullptr;
  syntax_asdl::expr_t* enode = nullptr;
  syntax_asdl::condition_t* cond = nullptr;
  syntax_asdl::word_t* ate = nullptr;
  syntax_asdl::Token* then_kw = nullptr;
  command::CommandList* body = nullptr;
  syntax_asdl::IfArm* arm = nullptr;
  StackRoot _root0(&if_node);
  StackRoot _root1(&if_kw);
  StackRoot _root2(&enode);
  StackRoot _root3(&cond);
  StackRoot _root4(&ate);
  StackRoot _root5(&then_kw);
  StackRoot _root6(&body);
  StackRoot _root7(&arm);

  if_node = command::If::CreateNull(true);
  if_kw = word_::AsKeywordToken(this->cur_word);
  if_node->if_kw = if_kw;
  this->_SetNext();
  if ((this->parse_opts->parse_paren() and this->w_parser->LookPastSpace() == Id::Op_LParen)) {
    enode = this->w_parser->ParseYshExprForCommand();
    cond = Alloc<condition::YshExpr>(enode);
  }
  else {
    cond = this->_ParseConditionList();
  }
  this->_GetWord();
  if ((this->parse_opts->parse_brace() and this->c_id == Id::Lit_LBrace)) {
    return this->_ParseYshIf(if_kw, cond);
  }
  ate = this->_Eat(Id::KW_Then);
  then_kw = word_::AsKeywordToken(ate);
  body = this->_ParseCommandList();
  arm = Alloc<IfArm>(if_kw, cond, then_kw, body->children, then_kw);
  if_node->arms->append(arm);
  if ((this->c_id == Id::KW_Elif || this->c_id == Id::KW_Else)) {
    this->_ParseElifElse(if_node);
  }
  ate = this->_Eat(Id::KW_Fi);
  if_node->fi_kw = word_::AsKeywordToken(ate);
  return if_node;
}

syntax_asdl::command_t* CommandParser::ParseTime() {
  syntax_asdl::Token* time_kw = nullptr;
  syntax_asdl::command_t* pipeline = nullptr;
  StackRoot _root0(&time_kw);
  StackRoot _root1(&pipeline);

  time_kw = word_::AsKeywordToken(this->cur_word);
  this->_SetNext();
  pipeline = this->ParsePipeline();
  return Alloc<command::TimeBlock>(time_kw, pipeline);
}

syntax_asdl::command_t* CommandParser::ParseCompoundCommand() {
  syntax_asdl::BraceGroup* n1 = nullptr;
  command::Subshell* n2 = nullptr;
  syntax_asdl::Token* keyword = nullptr;
  command::WhileUntil* n3 = nullptr;
  command::If* n4 = nullptr;
  command::Case* n5 = nullptr;
  command::DBracket* n6 = nullptr;
  command::DParen* n7 = nullptr;
  StackRoot _root0(&n1);
  StackRoot _root1(&n2);
  StackRoot _root2(&keyword);
  StackRoot _root3(&n3);
  StackRoot _root4(&n4);
  StackRoot _root5(&n5);
  StackRoot _root6(&n6);
  StackRoot _root7(&n7);

  this->_GetWord();
  if (this->c_id == Id::Lit_LBrace) {
    n1 = this->ParseBraceGroup();
    return this->_MaybeParseRedirectList(n1);
  }
  if (this->c_id == Id::Op_LParen) {
    n2 = this->ParseSubshell();
    return this->_MaybeParseRedirectList(n2);
  }
  if (this->c_id == Id::KW_For) {
    return this->ParseFor();
  }
  if ((this->c_id == Id::KW_While || this->c_id == Id::KW_Until)) {
    keyword = word_::AsKeywordToken(this->cur_word);
    n3 = this->ParseWhileUntil(keyword);
    return this->_MaybeParseRedirectList(n3);
  }
  if (this->c_id == Id::KW_If) {
    n4 = this->ParseIf();
    return this->_MaybeParseRedirectList(n4);
  }
  if (this->c_id == Id::KW_Case) {
    n5 = this->ParseCase();
    return this->_MaybeParseRedirectList(n5);
  }
  if (this->c_id == Id::KW_DLeftBracket) {
    if (!this->parse_opts->parse_dbracket()) {
      p_die(str1487, Alloc<loc::Word>(this->cur_word));
    }
    n6 = this->ParseDBracket();
    return this->_MaybeParseRedirectList(n6);
  }
  if (this->c_id == Id::Op_DLeftParen) {
    if (!this->parse_opts->parse_dparen()) {
      p_die(str1488, Alloc<loc::Word>(this->cur_word));
    }
    n7 = this->ParseDParen();
    return this->_MaybeParseRedirectList(n7);
  }
  if (this->c_id == Id::KW_Time) {
    return this->ParseTime();
  }
  p_die(StrFormat("Unexpected word while parsing compound command (%s)", Id_str(this->c_id)), Alloc<loc::Word>(this->cur_word));
}

command::ShFunction* CommandParser::ParseFunctionDef() {
  CompoundWord* word0 = nullptr;
  BigStr* name = nullptr;
  syntax_asdl::word_part_t* part0 = nullptr;
  Token* blame_tok = nullptr;
  command::ShFunction* func = nullptr;
  StackRoot _root0(&word0);
  StackRoot _root1(&name);
  StackRoot _root2(&part0);
  StackRoot _root3(&blame_tok);
  StackRoot _root4(&func);

  word0 = static_cast<CompoundWord*>(this->cur_word);
  name = word_::ShFunctionName(word0);
  if (len(name) == 0) {
    p_die(str1490, Alloc<loc::Word>(word0));
  }
  part0 = word0->parts->at(0);
  blame_tok = static_cast<Token*>(part0);
  this->_SetNext();
  this->_GetWord();
  this->lexer->PushHint(Id::Op_RParen, Id::Right_ShFunction);
  this->_SetNext();
  this->_GetWord();
  if (this->c_id == Id::Right_ShFunction) {
    this->_SetNext();
    this->_NewlineOk();
    func = command::ShFunction::CreateNull();
    func->name = name;
    {  // with
      ctx_VarChecker ctx{this->var_checker, blame_tok};

      func->body = this->ParseCompoundCommand();
    }
    func->name_tok = location::LeftTokenForCompoundWord(word0);
    return func;
  }
  else {
    p_die(str1491, Alloc<loc::Word>(this->cur_word));
    return nullptr;
  }
}

command::ShFunction* CommandParser::ParseKshFunctionDef() {
  syntax_asdl::Token* keyword_tok = nullptr;
  CompoundWord* cur_word = nullptr;
  BigStr* name = nullptr;
  syntax_asdl::word_t* name_word = nullptr;
  command::ShFunction* func = nullptr;
  StackRoot _root0(&keyword_tok);
  StackRoot _root1(&cur_word);
  StackRoot _root2(&name);
  StackRoot _root3(&name_word);
  StackRoot _root4(&func);

  keyword_tok = word_::AsKeywordToken(this->cur_word);
  this->_SetNext();
  this->_GetWord();
  cur_word = static_cast<CompoundWord*>(this->cur_word);
  name = word_::ShFunctionName(cur_word);
  if (len(name) == 0) {
    p_die(str1492, Alloc<loc::Word>(cur_word));
  }
  name_word = this->cur_word;
  this->_SetNext();
  this->_GetWord();
  if (this->c_id == Id::Op_LParen) {
    this->lexer->PushHint(Id::Op_RParen, Id::Right_ShFunction);
    this->_SetNext();
    this->_Eat(Id::Right_ShFunction);
  }
  this->_NewlineOk();
  func = command::ShFunction::CreateNull();
  func->name = name;
  {  // with
    ctx_VarChecker ctx{this->var_checker, keyword_tok};

    func->body = this->ParseCompoundCommand();
  }
  func->keyword = keyword_tok;
  func->name_tok = location::LeftTokenForWord(name_word);
  return func;
}

syntax_asdl::Proc* CommandParser::ParseYshProc() {
  syntax_asdl::Proc* node = nullptr;
  syntax_asdl::Token* keyword_tok = nullptr;
  proc_sig::Closed* sig = nullptr;
  syntax_asdl::ParamGroup* wp = nullptr;
  syntax_asdl::RestParam* r = nullptr;
  syntax_asdl::ParamGroup* posit = nullptr;
  syntax_asdl::ParamGroup* named = nullptr;
  syntax_asdl::Param* b = nullptr;
  StackRoot _root0(&node);
  StackRoot _root1(&keyword_tok);
  StackRoot _root2(&sig);
  StackRoot _root3(&wp);
  StackRoot _root4(&r);
  StackRoot _root5(&posit);
  StackRoot _root6(&named);
  StackRoot _root7(&b);

  node = Proc::CreateNull(true);
  keyword_tok = word_::AsKeywordToken(this->cur_word);
  node->keyword = keyword_tok;
  {  // with
    ctx_VarChecker ctx{this->var_checker, keyword_tok};

    {  // with
      ctx_CmdMode ctx{this, cmd_mode_e::Proc};

      this->w_parser->ParseProc(node);
      if (node->sig->tag() == proc_sig_e::Closed) {
        sig = static_cast<proc_sig::Closed*>(node->sig);
        wp = sig->word;
        if (wp) {
          for (ListIter<syntax_asdl::Param*> it(wp->params); !it.Done(); it.Next()) {
            syntax_asdl::Param* param = it.Value();
            StackRoot _for(&param          );
            this->var_checker->Check(Id::KW_Var, param->name, param->blame_tok);
          }
          if (wp->rest_of) {
            r = wp->rest_of;
            this->var_checker->Check(Id::KW_Var, r->name, r->blame_tok);
          }
        }
        posit = sig->positional;
        if (posit) {
          for (ListIter<syntax_asdl::Param*> it(posit->params); !it.Done(); it.Next()) {
            syntax_asdl::Param* param = it.Value();
            StackRoot _for(&param          );
            this->var_checker->Check(Id::KW_Var, param->name, param->blame_tok);
          }
          if (posit->rest_of) {
            r = posit->rest_of;
            this->var_checker->Check(Id::KW_Var, r->name, r->blame_tok);
          }
        }
        named = sig->named;
        if (named) {
          for (ListIter<syntax_asdl::Param*> it(named->params); !it.Done(); it.Next()) {
            syntax_asdl::Param* param = it.Value();
            StackRoot _for(&param          );
            this->var_checker->Check(Id::KW_Var, param->name, param->blame_tok);
          }
          if (named->rest_of) {
            r = named->rest_of;
            this->var_checker->Check(Id::KW_Var, r->name, r->blame_tok);
          }
        }
        if (sig->block_param) {
          b = sig->block_param;
          this->var_checker->Check(Id::KW_Var, b->name, b->blame_tok);
        }
      }
      this->_SetNext();
      node->body = this->ParseBraceGroup();
    }
  }
  return node;
}

syntax_asdl::Func* CommandParser::ParseYshFunc() {
  syntax_asdl::Func* node = nullptr;
  syntax_asdl::Token* keyword_tok = nullptr;
  syntax_asdl::ParamGroup* posit = nullptr;
  syntax_asdl::RestParam* r = nullptr;
  syntax_asdl::ParamGroup* named = nullptr;
  StackRoot _root0(&node);
  StackRoot _root1(&keyword_tok);
  StackRoot _root2(&posit);
  StackRoot _root3(&r);
  StackRoot _root4(&named);

  node = Func::CreateNull(true);
  keyword_tok = word_::AsKeywordToken(this->cur_word);
  node->keyword = keyword_tok;
  {  // with
    ctx_VarChecker ctx{this->var_checker, keyword_tok};

    this->w_parser->ParseFunc(node);
    posit = node->positional;
    if (posit) {
      for (ListIter<syntax_asdl::Param*> it(posit->params); !it.Done(); it.Next()) {
        syntax_asdl::Param* param = it.Value();
        StackRoot _for(&param      );
        this->var_checker->Check(Id::KW_Var, param->name, param->blame_tok);
      }
      if (posit->rest_of) {
        r = posit->rest_of;
        this->var_checker->Check(Id::KW_Var, r->name, r->blame_tok);
      }
    }
    named = node->named;
    if (named) {
      for (ListIter<syntax_asdl::Param*> it(named->params); !it.Done(); it.Next()) {
        syntax_asdl::Param* param = it.Value();
        StackRoot _for(&param      );
        this->var_checker->Check(Id::KW_Var, param->name, param->blame_tok);
      }
      if (named->rest_of) {
        r = named->rest_of;
        this->var_checker->Check(Id::KW_Var, r->name, r->blame_tok);
      }
    }
    this->_SetNext();
    {  // with
      ctx_CmdMode ctx{this, cmd_mode_e::Func};

      node->body = this->ParseBraceGroup();
    }
  }
  return node;
}

syntax_asdl::command_t* CommandParser::ParseCoproc() {
  FAIL(kNotImplemented);  // Python NotImplementedError
}

command::Subshell* CommandParser::ParseSubshell() {
  syntax_asdl::Token* left = nullptr;
  command::CommandList* c_list = nullptr;
  syntax_asdl::command_t* child = nullptr;
  syntax_asdl::word_t* ate = nullptr;
  syntax_asdl::Token* right = nullptr;
  StackRoot _root0(&left);
  StackRoot _root1(&c_list);
  StackRoot _root2(&child);
  StackRoot _root3(&ate);
  StackRoot _root4(&right);

  left = word_::AsOperatorToken(this->cur_word);
  this->_SetNext();
  this->lexer->PushHint(Id::Op_RParen, Id::Right_Subshell);
  c_list = this->_ParseCommandList();
  if (len(c_list->children) == 1) {
    child = c_list->children->at(0);
  }
  else {
    child = c_list;
  }
  ate = this->_Eat(Id::Right_Subshell);
  right = word_::AsOperatorToken(ate);
  return Alloc<command::Subshell>(left, child, right);
}

command::DBracket* CommandParser::ParseDBracket() {
  syntax_asdl::Token* left = nullptr;
  bool_parse::BoolParser* b_parser = nullptr;
  syntax_asdl::bool_expr_t* bnode = nullptr;
  syntax_asdl::Token* right = nullptr;
  StackRoot _root0(&left);
  StackRoot _root1(&b_parser);
  StackRoot _root2(&bnode);
  StackRoot _root3(&right);

  left = word_::AsKeywordToken(this->cur_word);
  this->_SetNext();
  b_parser = Alloc<bool_parse::BoolParser>(this->w_parser);
  Tuple2<syntax_asdl::bool_expr_t*, syntax_asdl::Token*> tup16 = b_parser->Parse();
  bnode = tup16.at0();
  right = tup16.at1();
  return Alloc<command::DBracket>(left, bnode, right);
}

command::DParen* CommandParser::ParseDParen() {
  syntax_asdl::Token* left = nullptr;
  syntax_asdl::arith_expr_t* anode = nullptr;
  syntax_asdl::Token* right = nullptr;
  StackRoot _root0(&left);
  StackRoot _root1(&anode);
  StackRoot _root2(&right);

  left = word_::AsOperatorToken(this->cur_word);
  this->_SetNext();
  Tuple2<syntax_asdl::arith_expr_t*, syntax_asdl::Token*> tup17 = this->w_parser->ReadDParen();
  anode = tup17.at0();
  right = tup17.at1();
  return Alloc<command::DParen>(left, anode, right);
}

syntax_asdl::command_t* CommandParser::ParseCommand() {
  int keyword_id;
  syntax_asdl::Token* kw_token = nullptr;
  command::VarDecl* n8 = nullptr;
  command::Mutation* n9 = nullptr;
  syntax_asdl::Token* keyword = nullptr;
  syntax_asdl::expr_t* enode = nullptr;
  CompoundWord* cur_word = nullptr;
  List<syntax_asdl::word_part_t*>* parts = nullptr;
  syntax_asdl::word_part_t* part0 = nullptr;
  Token* tok = nullptr;
  StackRoot _root0(&kw_token);
  StackRoot _root1(&n8);
  StackRoot _root2(&n9);
  StackRoot _root3(&keyword);
  StackRoot _root4(&enode);
  StackRoot _root5(&cur_word);
  StackRoot _root6(&parts);
  StackRoot _root7(&part0);
  StackRoot _root8(&tok);

  if (this->_AtSecondaryKeyword()) {
    p_die(str1493, Alloc<loc::Word>(this->cur_word));
  }
  if (this->c_id == Id::KW_Proc) {
    if (this->parse_opts->parse_proc()) {
      return this->ParseYshProc();
    }
    else {
      p_die(str1494, Alloc<loc::Word>(this->cur_word));
    }
  }
  if (this->c_id == Id::KW_Typed) {
    this->_SetNext();
    this->_GetWord();
    if (this->c_id != Id::KW_Proc) {
      p_die(str1495, Alloc<loc::Word>(this->cur_word));
    }
    if (this->parse_opts->parse_proc()) {
      return this->ParseYshProc();
    }
    else {
      p_die(str1496, Alloc<loc::Word>(this->cur_word));
    }
  }
  if (this->c_id == Id::KW_Func) {
    if (this->parse_opts->parse_func()) {
      return this->ParseYshFunc();
    }
    else {
      p_die(str1497, Alloc<loc::Word>(this->cur_word));
    }
  }
  if ((this->c_id == Id::KW_Const and this->cmd_mode != cmd_mode_e::Shell)) {
    p_die(str1498, Alloc<loc::Word>(this->cur_word));
  }
  if ((this->c_id == Id::KW_Var || this->c_id == Id::KW_Const)) {
    keyword_id = this->c_id;
    kw_token = word_::LiteralToken(this->cur_word);
    this->_SetNext();
    n8 = this->w_parser->ParseVarDecl(kw_token);
    for (ListIter<syntax_asdl::NameType*> it(n8->lhs); !it.Done(); it.Next()) {
      syntax_asdl::NameType* lhs = it.Value();
      StackRoot _for(&lhs    );
      this->var_checker->Check(keyword_id, lhs->name, lhs->left);
    }
    return n8;
  }
  if ((this->c_id == Id::KW_SetVar || this->c_id == Id::KW_SetGlobal)) {
    kw_token = word_::LiteralToken(this->cur_word);
    this->_SetNext();
    n9 = this->w_parser->ParseMutation(kw_token, this->var_checker);
    return n9;
  }
  if ((this->c_id == Id::KW_Call || this->c_id == Id::Lit_Equals)) {
    keyword = word_::LiteralToken(this->cur_word);
    this->_SetNext();
    enode = this->w_parser->ParseCommandExpr();
    return Alloc<command::Expr>(keyword, enode);
  }
  if (this->c_id == Id::KW_Function) {
    return this->ParseKshFunctionDef();
  }
  if ((this->c_id == Id::KW_DLeftBracket || this->c_id == Id::Op_DLeftParen || this->c_id == Id::Op_LParen || this->c_id == Id::Lit_LBrace || this->c_id == Id::KW_For || this->c_id == Id::KW_While || this->c_id == Id::KW_Until || this->c_id == Id::KW_If || this->c_id == Id::KW_Case || this->c_id == Id::KW_Time)) {
    return this->ParseCompoundCommand();
  }
  if (this->c_id == Id::Lit_RBrace) {
    p_die(str1499, Alloc<loc::Word>(this->cur_word));
  }
  if (this->c_kind == Kind::Redir) {
    return this->ParseSimpleCommand();
  }
  if (this->c_kind == Kind::Word) {
    cur_word = static_cast<CompoundWord*>(this->cur_word);
    if ((this->w_parser->LookAheadFuncParens() and !word_::IsVarLike(cur_word))) {
      return this->ParseFunctionDef();
    }
    parts = cur_word->parts;
    if ((this->parse_opts->parse_equals() and len(parts) == 1)) {
      part0 = parts->at(0);
      if (part0->tag() == word_part_e::Literal) {
        tok = static_cast<Token*>(part0);
        if ((tok->id == Id::Lit_Chars and (this->w_parser->LookPastSpace() == Id::Lit_Equals and match::IsValidVarName(lexer::LazyStr(tok))))) {
          if ((len(this->hay_attrs_stack) and this->hay_attrs_stack->at(-1))) {
            enode = this->w_parser->ParseBareDecl();
            this->_SetNext();
            return Alloc<command::VarDecl>(nullptr, NewList<syntax_asdl::NameType*>(std::initializer_list<syntax_asdl::NameType*>{Alloc<NameType>(tok, lexer::TokenVal(tok), nullptr)}), enode);
          }
          else {
            this->_SetNext();
            this->_GetWord();
            p_die(str1500, Alloc<loc::Word>(this->cur_word));
          }
        }
      }
    }
    return this->ParseSimpleCommand();
  }
  if (this->c_kind == Kind::Eof) {
    p_die(str1501, Alloc<loc::Word>(this->cur_word));
  }
  p_die(str1502, Alloc<loc::Word>(this->cur_word));
}

syntax_asdl::command_t* CommandParser::ParsePipeline() {
  syntax_asdl::Token* negated = nullptr;
  syntax_asdl::command_t* child = nullptr;
  List<syntax_asdl::command_t*>* children = nullptr;
  command::Pipeline* node = nullptr;
  List<syntax_asdl::Token*>* ops = nullptr;
  syntax_asdl::Token* op = nullptr;
  StackRoot _root0(&negated);
  StackRoot _root1(&child);
  StackRoot _root2(&children);
  StackRoot _root3(&node);
  StackRoot _root4(&ops);
  StackRoot _root5(&op);

  negated = nullptr;
  this->_GetWord();
  if (this->c_id == Id::KW_Bang) {
    negated = word_::AsKeywordToken(this->cur_word);
    this->_SetNext();
  }
  child = this->ParseCommand();
  children = NewList<syntax_asdl::command_t*>(std::initializer_list<syntax_asdl::command_t*>{child});
  this->_GetWord();
  if ((this->c_id != Id::Op_Pipe && this->c_id != Id::Op_PipeAmp)) {
    if (negated != nullptr) {
      node = Alloc<command::Pipeline>(negated, children, Alloc<List<syntax_asdl::Token*>>());
      return node;
    }
    else {
      return child;
    }
  }
  ops = Alloc<List<syntax_asdl::Token*>>();
  while (true) {
    op = word_::AsOperatorToken(this->cur_word);
    ops->append(op);
    this->_SetNext();
    this->_NewlineOk();
    child = this->ParseCommand();
    children->append(child);
    this->_GetWord();
    if ((this->c_id != Id::Op_Pipe && this->c_id != Id::Op_PipeAmp)) {
      break;
    }
  }
  return Alloc<command::Pipeline>(negated, children, ops);
}

syntax_asdl::command_t* CommandParser::ParseAndOr() {
  this->_GetWord();
  if (this->c_id == Id::Lit_TDot) {
    this->_SetNext();
    {  // with
      word_::ctx_Multiline ctx{this->w_parser};

      return this->_ParseAndOr();
    }
  }
  return this->_ParseAndOr();
}

syntax_asdl::command_t* CommandParser::_ParseAndOr() {
  syntax_asdl::command_t* child = nullptr;
  List<syntax_asdl::Token*>* ops = nullptr;
  List<syntax_asdl::command_t*>* children = nullptr;
  StackRoot _root0(&child);
  StackRoot _root1(&ops);
  StackRoot _root2(&children);

  child = this->ParsePipeline();
  this->_GetWord();
  if ((this->c_id != Id::Op_DPipe && this->c_id != Id::Op_DAmp)) {
    return child;
  }
  ops = Alloc<List<syntax_asdl::Token*>>();
  children = NewList<syntax_asdl::command_t*>(std::initializer_list<syntax_asdl::command_t*>{child});
  while (true) {
    ops->append(word_::AsOperatorToken(this->cur_word));
    this->_SetNext();
    this->_NewlineOk();
    child = this->ParsePipeline();
    children->append(child);
    this->_GetWord();
    if ((this->c_id != Id::Op_DPipe && this->c_id != Id::Op_DAmp)) {
      break;
    }
  }
  return Alloc<command::AndOr>(children, ops);
}

syntax_asdl::command_t* CommandParser::_ParseCommandLine() {
  List<int>* END_LIST = nullptr;
  List<syntax_asdl::command_t*>* children = nullptr;
  bool done;
  syntax_asdl::command_t* child = nullptr;
  Token* tok = nullptr;
  StackRoot _root0(&END_LIST);
  StackRoot _root1(&children);
  StackRoot _root2(&child);
  StackRoot _root3(&tok);

  END_LIST = NewList<int>(std::initializer_list<int>{Id::Op_Newline, Id::Eof_Real});
  children = Alloc<List<syntax_asdl::command_t*>>();
  done = false;
  while (!done) {
    child = this->ParseAndOr();
    this->_GetWord();
    if ((this->c_id == Id::Op_Semi || this->c_id == Id::Op_Amp)) {
      tok = static_cast<Token*>(this->cur_word);
      child = Alloc<command::Sentence>(child, tok);
      this->_SetNext();
      this->_GetWord();
      if (list_contains(END_LIST, this->c_id)) {
        done = true;
      }
    }
    else {
      if (list_contains(END_LIST, this->c_id)) {
        done = true;
      }
      else {
        p_die(StrFormat("Invalid word while parsing command line (%s)", Id_str(this->c_id)), Alloc<loc::Word>(this->cur_word));
      }
    }
    children->append(child);
  }
  if (len(children) > 1) {
    return Alloc<command::CommandList>(children);
  }
  else {
    return children->at(0);
  }
}

command::CommandList* CommandParser::_ParseCommandTerm() {
  List<int>* END_LIST = nullptr;
  List<syntax_asdl::command_t*>* children = nullptr;
  bool done;
  syntax_asdl::command_t* child = nullptr;
  Token* tok = nullptr;
  StackRoot _root0(&END_LIST);
  StackRoot _root1(&children);
  StackRoot _root2(&child);
  StackRoot _root3(&tok);

  END_LIST = NewList<int>(std::initializer_list<int>{this->eof_id, Id::Right_Subshell, Id::Lit_RBrace, Id::Op_DSemi, Id::Op_SemiAmp, Id::Op_DSemiAmp});
  children = Alloc<List<syntax_asdl::command_t*>>();
  done = false;
  while (!done) {
    if (this->_AtSecondaryKeyword()) {
      break;
    }
    child = this->ParseAndOr();
    this->_GetWord();
    if (this->c_id == Id::Op_Newline) {
      this->_SetNext();
      this->_GetWord();
      if (list_contains(END_LIST, this->c_id)) {
        done = true;
      }
    }
    else {
      if ((this->c_id == Id::Op_Semi || this->c_id == Id::Op_Amp)) {
        tok = static_cast<Token*>(this->cur_word);
        child = Alloc<command::Sentence>(child, tok);
        this->_SetNext();
        this->_GetWord();
        if (this->c_id == Id::Op_Newline) {
          this->_SetNext();
          this->_GetWord();
          if (list_contains(END_LIST, this->c_id)) {
            done = true;
          }
        }
        else {
          if (list_contains(END_LIST, this->c_id)) {
            done = true;
          }
        }
      }
      else {
        if (list_contains(END_LIST, this->c_id)) {
          done = true;
        }
        else {
          if ((this->parse_opts->parse_brace() and this->c_id == Id::Lit_LBrace)) {
            done = true;
          }
          else {
            if (this->c_kind != Kind::Word) {
              p_die(str1504, Alloc<loc::Word>(this->cur_word));
            }
          }
        }
      }
    }
    children->append(child);
  }
  return Alloc<command::CommandList>(children);
}

command::CommandList* CommandParser::_ParseCommandList() {
  this->_NewlineOk();
  return this->_ParseCommandTerm();
}

syntax_asdl::command_t* CommandParser::ParseLogicalLine() {
  syntax_asdl::command_t* node = nullptr;
  StackRoot _root0(&node);

  this->_NewlineOk();
  this->_GetWord();
  if (this->c_id == Id::Eof_Real) {
    return nullptr;
  }
  node = this->_ParseCommandLine();
  return node;
}

syntax_asdl::parse_result_t* CommandParser::ParseInteractiveLine() {
  syntax_asdl::command_t* node = nullptr;
  StackRoot _root0(&node);

  this->_GetWord();
  if (this->c_id == Id::Op_Newline) {
    return parse_result::EmptyLine;
  }
  if (this->c_id == Id::Eof_Real) {
    return parse_result::Eof;
  }
  node = this->_ParseCommandLine();
  return Alloc<parse_result::Node>(node);
}

syntax_asdl::command_t* CommandParser::ParseCommandSub() {
  command::CommandList* c_list = nullptr;
  StackRoot _root0(&c_list);

  this->_NewlineOk();
  this->_GetWord();
  if (this->c_kind == Kind::Eof) {
    return command::NoOp;
  }
  c_list = this->_ParseCommandTerm();
  if (len(c_list->children) == 1) {
    return c_list->children->at(0);
  }
  else {
    return c_list;
  }
}

void CommandParser::CheckForPendingHereDocs() {
  syntax_asdl::Redir* node = nullptr;
  redir_param::HereDoc* h = nullptr;
  StackRoot _root0(&node);
  StackRoot _root1(&h);

  if (len(this->pending_here_docs)) {
    node = this->pending_here_docs->at(0);
    h = static_cast<redir_param::HereDoc*>(node->arg);
    p_die(str1505, Alloc<loc::Word>(h->here_begin));
  }
}

}  // define namespace cmd_parse

namespace glob_ {  // define

using id_kind_asdl::Id;
using id_kind_asdl::Id_t;
using syntax_asdl::CompoundWord;
using syntax_asdl::Token;
using syntax_asdl::word_part_e;
using syntax_asdl::glob_part;
using syntax_asdl::glob_part_e;
using syntax_asdl::glob_part_t;
using mylib::print_stderr;

bool LooksLikeGlob(BigStr* s) {
  bool left_bracket;
  int i;
  int n;
  int c;
  StackRoot _root0(&s);

  left_bracket = false;
  i = 0;
  n = len(s);
  while (i < n) {
    c = mylib::ByteAt(s, i);
    if (mylib::ByteEquals(c, str1506)) {
      i += 1;
    }
    else {
      if ((mylib::ByteEquals(c, str1507) or mylib::ByteEquals(c, str1508))) {
        return true;
      }
      else {
        if (mylib::ByteEquals(c, str1509)) {
          left_bracket = true;
        }
        else {
          if ((mylib::ByteEquals(c, str1510) and left_bracket)) {
            return true;
          }
        }
      }
    }
    i += 1;
  }
  return false;
}

bool LooksLikeStaticGlob(syntax_asdl::CompoundWord* w) {
  bool left_bracket;
  int id_;
  StackRoot _root0(&w);

  left_bracket = false;
  for (ListIter<syntax_asdl::word_part_t*> it(w->parts); !it.Done(); it.Next()) {
    syntax_asdl::word_part_t* part = it.Value();
    StackRoot _for(&part  );
    if (part->tag() == word_part_e::Literal) {
      id_ = static_cast<Token*>(part)->id;
      if ((id_ == Id::Lit_Star || id_ == Id::Lit_QMark)) {
        return true;
      }
      else {
        if (id_ == Id::Lit_LBracket) {
          left_bracket = true;
        }
        else {
          if ((id_ == Id::Lit_RBracket and left_bracket)) {
            return true;
          }
        }
      }
    }
  }
  return false;
}
BigStr* GLOB_META_CHARS = str1511;

BigStr* GlobEscape(BigStr* s) {
  StackRoot _root0(&s);

  return pyutil::BackslashEscape(s, GLOB_META_CHARS);
}
BigStr* ERE_META_CHARS = str1512;

BigStr* ExtendedRegexEscape(BigStr* s) {
  StackRoot _root0(&s);

  return pyutil::BackslashEscape(s, ERE_META_CHARS);
}

BigStr* GlobUnescape(BigStr* s) {
  List<int>* unescaped = nullptr;
  int i;
  int n;
  int c;
  int c2;
  StackRoot _root0(&s);
  StackRoot _root1(&unescaped);

  unescaped = Alloc<List<int>>();
  i = 0;
  n = len(s);
  while (i < n) {
    c = mylib::ByteAt(s, i);
    if ((mylib::ByteEquals(c, str1513) and i != (n - 1))) {
      i += 1;
      c2 = mylib::ByteAt(s, i);
      if (mylib::ByteInSet(c2, GLOB_META_CHARS)) {
        unescaped->append(c2);
      }
      else {
        assert(0);  // AssertionError
      }
    }
    else {
      unescaped->append(c);
    }
    i += 1;
  }
  return mylib::JoinBytes(unescaped);
}

_GlobParser::_GlobParser(match::SimpleLexer* lexer) {
  this->lexer = lexer;
  this->token_type = Id::Undefined_Tok;
  this->token_val = str1515;
  this->warnings = Alloc<List<BigStr*>>();
}

void _GlobParser::_Next() {
  Tuple2<int, BigStr*> tup0 = this->lexer->Next();
  this->token_type = tup0.at0();
  this->token_val = tup0.at1();
}

List<syntax_asdl::glob_part_t*>* _GlobParser::_ParseCharClass() {
  glob_part::Literal* first_token = nullptr;
  int balance;
  List<Tuple2<int, BigStr*>*>* tokens = nullptr;
  List<syntax_asdl::glob_part_t*>* parts = nullptr;
  int id_;
  BigStr* s = nullptr;
  bool negated;
  int id1;
  List<BigStr*>* strs = nullptr;
  StackRoot _root0(&first_token);
  StackRoot _root1(&tokens);
  StackRoot _root2(&parts);
  StackRoot _root3(&s);
  StackRoot _root4(&strs);

  first_token = Alloc<glob_part::Literal>(this->token_type, this->token_val);
  balance = 1;
  tokens = Alloc<List<Tuple2<int, BigStr*>*>>();
  while (true) {
    this->_Next();
    if (this->token_type == Id::Eol_Tok) {
      this->warnings->append(str1516);
      parts = NewList<syntax_asdl::glob_part_t*>(std::initializer_list<syntax_asdl::glob_part_t*>{first_token});
      for (ListIter<Tuple2<int, BigStr*>*> it(tokens); !it.Done(); it.Next()) {
        Tuple2<int, BigStr*>* tup1 = it.Value();
        id_ = tup1->at0();
        s = tup1->at1();
        parts->append(Alloc<glob_part::Literal>(id_, s));
      }
      return parts;
    }
    if (this->token_type == Id::Glob_LBracket) {
      balance += 1;
    }
    else {
      if (this->token_type == Id::Glob_RBracket) {
        balance -= 1;
      }
    }
    if (balance == 0) {
      break;
    }
    tokens->append((Alloc<Tuple2<int, BigStr*>>(this->token_type, this->token_val)));
  }
  negated = false;
  if (len(tokens)) {
    Tuple2<int, BigStr*>* tup2 = tokens->at(0);
    id1 = tup2->at0();
    if ((id1 == Id::Glob_Bang || id1 == Id::Glob_Caret)) {
      negated = true;
      tokens = tokens->slice(1);
    }
  }
  strs = Alloc<List<BigStr*>>();
  for (ListIter<Tuple2<int, BigStr*>*> it(tokens); !it.Done(); it.Next()) {
    Tuple2<int, BigStr*>* tup3 = it.Value();
    s = tup3->at1();
    strs->append(s);
  }
  return NewList<syntax_asdl::glob_part_t*>(std::initializer_list<syntax_asdl::glob_part_t*>{Alloc<glob_part::CharClass>(negated, strs)});
}

Tuple2<List<syntax_asdl::glob_part_t*>*, List<BigStr*>*> _GlobParser::Parse() {
  List<syntax_asdl::glob_part_t*>* parts = nullptr;
  int id_;
  BigStr* s = nullptr;
  StackRoot _root0(&parts);
  StackRoot _root1(&s);

  parts = Alloc<List<syntax_asdl::glob_part_t*>>();
  while (true) {
    this->_Next();
    id_ = this->token_type;
    s = this->token_val;
    if (id_ == Id::Eol_Tok) {
      break;
    }
    if ((id_ == Id::Glob_Star || id_ == Id::Glob_QMark)) {
      parts->append(Alloc<glob_part::Operator>(id_));
    }
    else {
      if (id_ == Id::Glob_LBracket) {
        parts->extend(this->_ParseCharClass());
      }
      else {
        parts->append(Alloc<glob_part::Literal>(id_, s));
      }
    }
    if (id_ == Id::Glob_RBracket) {
      this->warnings->append(str1517);
    }
    if (id_ == Id::Glob_BadBackslash) {
      this->warnings->append(str1518);
    }
  }
  return Tuple2<List<syntax_asdl::glob_part_t*>*, List<BigStr*>*>(parts, this->warnings);
}
BigStr* _REGEX_CHARS_TO_ESCAPE = str1519;

BigStr* _GenerateERE(List<syntax_asdl::glob_part_t*>* parts) {
  List<BigStr*>* out = nullptr;
  int tag;
  syntax_asdl::glob_part_t* UP_part = nullptr;
  BigStr* c = nullptr;
  List<BigStr*>* good = nullptr;
  bool literal_hyphen;
  bool literal_rbracket;
  StackRoot _root0(&parts);
  StackRoot _root1(&out);
  StackRoot _root2(&UP_part);
  StackRoot _root3(&c);
  StackRoot _root4(&good);

  out = Alloc<List<BigStr*>>();
  for (ListIter<syntax_asdl::glob_part_t*> it(parts); !it.Done(); it.Next()) {
    syntax_asdl::glob_part_t* part = it.Value();
    StackRoot _for(&part  );
    tag = part->tag();
    UP_part = part;
    if (tag == glob_part_e::Literal) {
      glob_part::Literal* part = static_cast<glob_part::Literal*>(UP_part);
      if (part->id == Id::Glob_EscapedChar) {
        c = part->s->at(1);
        if (str_contains(_REGEX_CHARS_TO_ESCAPE, c)) {
          out->append(str1520);
        }
        out->append(c);
      }
      else {
        if ((part->id == Id::Glob_CleanLiterals || part->id == Id::Glob_Bang)) {
          out->append(part->s);
        }
        else {
          if ((part->id == Id::Glob_OtherLiteral || part->id == Id::Glob_Caret)) {
            c = part->s;
            if (str_contains(_REGEX_CHARS_TO_ESCAPE, c)) {
              out->append(str1521);
            }
            out->append(c);
          }
          else {
            if (part->id == Id::Glob_LBracket) {
              out->append(str1522);
            }
            else {
              if (part->id == Id::Glob_RBracket) {
                out->append(str1523);
              }
              else {
                if (part->id == Id::Glob_BadBackslash) {
                  out->append(str1524);
                }
                else {
                  if (part->id == Id::Glob_Caret) {
                    out->append(str1525);
                  }
                  else {
                    assert(0);  // AssertionError
                  }
                }
              }
            }
          }
        }
      }
    }
    else {
      if (tag == glob_part_e::Operator) {
        glob_part::Operator* part = static_cast<glob_part::Operator*>(UP_part);
        if (part->op_id == Id::Glob_QMark) {
          out->append(str1526);
        }
        else {
          if (part->op_id == Id::Glob_Star) {
            out->append(str1527);
          }
          else {
            assert(0);  // AssertionError
          }
        }
      }
      else {
        if (tag == glob_part_e::CharClass) {
          glob_part::CharClass* part = static_cast<glob_part::CharClass*>(UP_part);
          out->append(str1528);
          if (part->negated) {
            out->append(str1529);
          }
          good = Alloc<List<BigStr*>>();
          literal_hyphen = false;
          literal_rbracket = false;
          for (ListIter<BigStr*> it(part->strs); !it.Done(); it.Next()) {
            BigStr* s = it.Value();
            StackRoot _for(&s          );
            if (str_equals(s, str1530)) {
              literal_hyphen = true;
              continue;
            }
            if (str_equals(s, str1531)) {
              literal_rbracket = true;
              continue;
            }
            good->append(s);
          }
          if (literal_rbracket) {
            out->append(str1532);
          }
          out->extend(good);
          if (literal_hyphen) {
            out->append(str1533);
          }
          out->append(str1534);
        }
      }
    }
  }
  return str1535->join(out);
}

Tuple2<BigStr*, List<BigStr*>*> GlobToERE(BigStr* pat) {
  match::SimpleLexer* lexer = nullptr;
  glob_::_GlobParser* p = nullptr;
  List<syntax_asdl::glob_part_t*>* parts = nullptr;
  List<BigStr*>* warnings = nullptr;
  BigStr* regex = nullptr;
  StackRoot _root0(&pat);
  StackRoot _root1(&lexer);
  StackRoot _root2(&p);
  StackRoot _root3(&parts);
  StackRoot _root4(&warnings);
  StackRoot _root5(&regex);

  lexer = match::GlobLexer(pat);
  p = Alloc<_GlobParser>(lexer);
  Tuple2<List<syntax_asdl::glob_part_t*>*, List<BigStr*>*> tup4 = p->Parse();
  parts = tup4.at0();
  warnings = tup4.at1();
  regex = _GenerateERE(parts);
  return Tuple2<BigStr*, List<BigStr*>*>(regex, warnings);
}

Globber::Globber(optview::Exec* exec_opts) {
  this->exec_opts = exec_opts;
}

int Globber::_Glob(BigStr* arg, List<BigStr*>* out) {
  List<BigStr*>* results = nullptr;
  BigStr* msg = nullptr;
  int n;
  List<BigStr*>* tmp = nullptr;
  StackRoot _root0(&arg);
  StackRoot _root1(&out);
  StackRoot _root2(&results);
  StackRoot _root3(&msg);
  StackRoot _root4(&tmp);

  try {
    results = libc::glob(arg);
  }
  catch (RuntimeError* e) {
    msg = e->message;
    print_stderr(StrFormat("Error expanding glob %r: %s", arg, msg));
    throw ;
  }
  n = len(results);
  if (n) {
    if (!this->exec_opts->dashglob()) {
      tmp = Alloc<List<BigStr*>>();
      for (ListIter<BigStr*> it(results); !it.Done(); it.Next()) {
        BigStr* s = it.Value();
        if (!s->startswith(str1539)) {
          tmp->append(s);
        }
      }
      results = tmp;
      n = len(results);
    }
    out->extend(results);
    return n;
  }
  return 0;
}

int Globber::Expand(BigStr* arg, List<BigStr*>* out) {
  int n;
  StackRoot _root0(&arg);
  StackRoot _root1(&out);

  if (this->exec_opts->noglob()) {
    out->append(arg);
    return 1;
  }
  n = this->_Glob(arg, out);
  if (n) {
    return n;
  }
  if (this->exec_opts->failglob()) {
    return -1;
  }
  if (this->exec_opts->nullglob()) {
    return 0;
  }
  else {
    out->append(GlobUnescape(arg));
    return 1;
  }
}

int Globber::ExpandExtended(BigStr* glob_pat, BigStr* fnmatch_pat, List<BigStr*>* out) {
  List<BigStr*>* tmp = nullptr;
  List<BigStr*>* filtered = nullptr;
  int n;
  StackRoot _root0(&glob_pat);
  StackRoot _root1(&fnmatch_pat);
  StackRoot _root2(&out);
  StackRoot _root3(&tmp);
  StackRoot _root4(&filtered);

  if (this->exec_opts->noglob()) {
    out->append(fnmatch_pat);
    return 1;
  }
  tmp = Alloc<List<BigStr*>>();
  this->_Glob(glob_pat, tmp);
  filtered = Alloc<List<BigStr*>>();
  for (ListIter<BigStr*> it(tmp); !it.Done(); it.Next()) {
    BigStr* s = it.Value();
    if (libc::fnmatch(fnmatch_pat, s)) {
      filtered->append(s);
    }
  }
  n = len(filtered);
  if (n) {
    out->extend(filtered);
    return n;
  }
  if (this->exec_opts->failglob()) {
    return -1;
  }
  if (this->exec_opts->nullglob()) {
    return 0;
  }
  else {
    out->append(GlobUnescape(fnmatch_pat));
    return 1;
  }
}

}  // define namespace glob_

namespace history {  // define

using id_kind_asdl::Id;

Evaluator::Evaluator(py_readline::Readline* readline, parse_lib::ParseContext* parse_ctx, util::_DebugFile* debug_f) {
  this->readline = readline;
  this->parse_ctx = parse_ctx;
  this->debug_f = debug_f;
}

BigStr* Evaluator::Eval(BigStr* line) {
  List<Tuple2<int, BigStr*>*>* tokens = nullptr;
  bool ok;
  int id_;
  int history_len;
  List<BigStr*>* parts = nullptr;
  BigStr* val = nullptr;
  BigStr* out = nullptr;
  BigStr* prev = nullptr;
  BigStr* ch = nullptr;
  reader::FileLineReader* line_reader = nullptr;
  cmd_parse::CommandParser* c_parser = nullptr;
  List<syntax_asdl::CompoundWord*>* words = nullptr;
  syntax_asdl::CompoundWord* w = nullptr;
  syntax_asdl::Token* tok1 = nullptr;
  syntax_asdl::Token* tok2 = nullptr;
  syntax_asdl::CompoundWord* w1 = nullptr;
  syntax_asdl::CompoundWord* w2 = nullptr;
  int begin;
  int end;
  int index;
  int num;
  BigStr* last_char = nullptr;
  BigStr* prefix = nullptr;
  BigStr* substring = nullptr;
  BigStr* cmd = nullptr;
  StackRoot _root0(&line);
  StackRoot _root1(&tokens);
  StackRoot _root2(&parts);
  StackRoot _root3(&val);
  StackRoot _root4(&out);
  StackRoot _root5(&prev);
  StackRoot _root6(&ch);
  StackRoot _root7(&line_reader);
  StackRoot _root8(&c_parser);
  StackRoot _root9(&words);
  StackRoot _root10(&w);
  StackRoot _root11(&tok1);
  StackRoot _root12(&tok2);
  StackRoot _root13(&w1);
  StackRoot _root14(&w2);
  StackRoot _root15(&last_char);
  StackRoot _root16(&prefix);
  StackRoot _root17(&substring);
  StackRoot _root18(&cmd);

  if (!this->readline) {
    return line;
  }
  tokens = match::HistoryTokens(line);
  ok = true;
  for (ListIter<Tuple2<int, BigStr*>*> it(tokens); !it.Done(); it.Next()) {
    Tuple2<int, BigStr*>* tup0 = it.Value();
    id_ = tup0->at0();
    if (id_ != Id::History_Other) {
      ok = false;
      break;
    }
  }
  if (ok) {
    return line;
  }
  history_len = this->readline->get_current_history_length();
  if (history_len <= 0) {
    return line;
  }
  this->debug_f->writeln(StrFormat("history length = %d", history_len));
  parts = Alloc<List<BigStr*>>();
  for (ListIter<Tuple2<int, BigStr*>*> it(tokens); !it.Done(); it.Next()) {
    Tuple2<int, BigStr*>* tup1 = it.Value();
    id_ = tup1->at0();
    val = tup1->at1();
    if (id_ == Id::History_Other) {
      out = val;
    }
    else {
      if (id_ == Id::History_Op) {
        prev = this->readline->get_history_item(history_len);
        ch = val->at(1);
        if (str_equals(ch, str1541)) {
          out = prev;
        }
        else {
          this->parse_ctx->trail->Clear();
          line_reader = reader::StringLineReader(prev, this->parse_ctx->arena);
          c_parser = this->parse_ctx->MakeOshParser(line_reader);
          try {
            c_parser->ParseLogicalLine();
          }
          catch (error::Parse* e) {
            this->debug_f->writeln(StrFormat("Couldn't parse historical command %r: %s", prev, e->UserErrorString()));
          }
          words = this->parse_ctx->trail->words;
          if (str_equals(ch, str1543)) {
            try {
              w = words->at(1);
            }
            catch (IndexError*) {
              throw Alloc<util::HistoryError>(StrFormat("No first word in %r", prev));
            }
            tok1 = location::LeftTokenForWord(w);
            tok2 = location::RightTokenForWord(w);
          }
          else {
            if (str_equals(ch, str1545)) {
              try {
                w = words->at(-1);
              }
              catch (IndexError*) {
                throw Alloc<util::HistoryError>(StrFormat("No last word in %r", prev));
              }
              tok1 = location::LeftTokenForWord(w);
              tok2 = location::RightTokenForWord(w);
            }
            else {
              if (str_equals(ch, str1547)) {
                try {
                  w1 = words->at(1);
                  w2 = words->at(-1);
                }
                catch (IndexError*) {
                  throw Alloc<util::HistoryError>(StrFormat("Couldn't find words in %r", prev));
                }
                tok1 = location::LeftTokenForWord(w1);
                tok2 = location::RightTokenForWord(w2);
              }
              else {
                assert(0);  // AssertionError
              }
            }
          }
          begin = tok1->col;
          end = (tok2->col + tok2->length);
          out = prev->slice(begin, end);
        }
      }
      else {
        if (id_ == Id::History_Num) {
          index = to_int(val->slice(1));
          if (index < 0) {
            num = ((history_len + 1) + index);
          }
          else {
            num = index;
          }
          out = this->readline->get_history_item(num);
          if (out == nullptr) {
            throw Alloc<util::HistoryError>(StrFormat("%s: not found", val));
          }
        }
        else {
          if (id_ == Id::History_Search) {
            last_char = val->at(-1);
            val = val->slice(0, -1);
            prefix = nullptr;
            substring = str1550;
            if (str_equals(val->at(1), str1551)) {
              substring = val->slice(2);
            }
            else {
              prefix = val->slice(1);
            }
            out = nullptr;
            for (int i = history_len; i > 1; i += -1) {
              cmd = this->readline->get_history_item(i);
              if ((prefix != nullptr and cmd->startswith(prefix))) {
                out = cmd;
              }
              if ((len(substring) and str_contains(cmd, substring))) {
                out = cmd;
              }
              if (out != nullptr) {
                out = str_concat(out, last_char);
                break;
              }
            }
            if (out == nullptr) {
              throw Alloc<util::HistoryError>(StrFormat("%r found no results", val));
            }
          }
          else {
            assert(0);  // AssertionError
          }
        }
      }
    }
    parts->append(out);
  }
  line = str1553->join(parts);
  print(StrFormat("! %s", line));
  return line;
}

}  // define namespace history

namespace prompt {  // define

using id_kind_asdl::Id;
using id_kind_asdl::Id_t;
using syntax_asdl::loc;
using syntax_asdl::command_t;
using syntax_asdl::source;
using syntax_asdl::CompoundWord;
using value_asdl::value;
using value_asdl::value_e;
using value_asdl::value_t;
BigStr* _ERROR_FMT = str1555;
BigStr* _UNBALANCED_ERROR = str1556;

_PromptEvaluatorCache::_PromptEvaluatorCache() {
  this->cache = Alloc<Dict<BigStr*, BigStr*>>();
  this->euid = -1;
}

int _PromptEvaluatorCache::_GetEuid() {
  if (this->euid == -1) {
    this->euid = posix::geteuid();
  }
  return this->euid;
}

BigStr* _PromptEvaluatorCache::Get(BigStr* name) {
  BigStr* value = nullptr;
  StackRoot _root0(&name);
  StackRoot _root1(&value);

  if (dict_contains(this->cache, name)) {
    return this->cache->at(name);
  }
  if (str_equals(name, str1557)) {
    value = this->_GetEuid() == 0 ? str1558 : str1559;
  }
  else {
    if (str_equals(name, str1560)) {
      value = libc::gethostname();
    }
    else {
      if (str_equals(name, str1561)) {
        value = pyos::GetUserName(this->_GetEuid());
      }
      else {
        assert(0);  // AssertionError
      }
    }
  }
  this->cache->set(name, value);
  return value;
}

Evaluator::Evaluator(BigStr* lang, BigStr* version_str, parse_lib::ParseContext* parse_ctx, state::Mem* mem) {
  this->word_ev = nullptr;
  this->expr_ev = nullptr;
  this->global_io = nullptr;
  this->lang = lang;
  this->version_str = version_str;
  this->parse_ctx = parse_ctx;
  this->mem = mem;
  this->cache = Alloc<_PromptEvaluatorCache>();
  this->tokens_cache = Alloc<Dict<BigStr*, List<Tuple2<int, BigStr*>*>*>>();
  this->parse_cache = Alloc<Dict<BigStr*, syntax_asdl::CompoundWord*>>();
}

void Evaluator::CheckCircularDeps() {
}

BigStr* Evaluator::PromptVal(BigStr* what) {
  StackRoot _root0(&what);

  if (str_equals(what, str1562)) {
    return StrFormat(_ERROR_FMT, str1563);
  }
  else {
    return this->PromptSubst(what);
  }
}

BigStr* Evaluator::PromptSubst(BigStr* ch, BigStr* arg) {
  BigStr* r = nullptr;
  BigStr* hostname = nullptr;
  double now;
  BigStr* fmt = nullptr;
  BigStr* pwd = nullptr;
  BigStr* home = nullptr;
  value_asdl::value_t* val = nullptr;
  value::Str* str_val = nullptr;
  StackRoot _root0(&ch);
  StackRoot _root1(&arg);
  StackRoot _root2(&r);
  StackRoot _root3(&hostname);
  StackRoot _root4(&fmt);
  StackRoot _root5(&pwd);
  StackRoot _root6(&home);
  StackRoot _root7(&val);
  StackRoot _root8(&str_val);

  if (str_equals(ch, str1564)) {
    r = this->cache->Get(str1565);
  }
  else {
    if (str_equals(ch, str1566)) {
      r = this->cache->Get(str1567);
    }
    else {
      if (str_equals(ch, str1568)) {
        hostname = this->cache->Get(str1569);
        Tuple2<BigStr*, BigStr*> tup0 = mylib::split_once(hostname, str1570);
        r = tup0.at0();
      }
      else {
        if (str_equals(ch, str1571)) {
          r = this->cache->Get(str1572);
        }
        else {
          if (str_equals(ch, str1573)) {
            r = this->lang;
          }
          else {
            if (str_equals(ch, str1574)) {
              r = this->version_str;
            }
            else {
              if (str_equals(ch, str1575)) {
                now = time_::time();
                r = time_::strftime(str1576, time_::localtime(now));
              }
              else {
                if (str_equals(ch, str1577)) {
                  now = time_::time();
                  if (len(arg) == 0) {
                    fmt = str1578;
                  }
                  else {
                    fmt = arg;
                  }
                  r = time_::strftime(fmt, time_::localtime(now));
                }
                else {
                  if (str_equals(ch, str1579)) {
                    try {
                      pwd = state::GetString(this->mem, str1580);
                      home = state::MaybeString(this->mem, str1581);
                      r = ui::PrettyDir(pwd, home);
                    }
                    catch (error::Runtime* e) {
                      r = StrFormat(_ERROR_FMT, e->UserErrorString());
                    }
                  }
                  else {
                    if (str_equals(ch, str1582)) {
                      val = this->mem->GetValue(str1583);
                      if (val->tag() == value_e::Str) {
                        str_val = static_cast<value::Str*>(val);
                        r = os_path::basename(str_val->s);
                      }
                      else {
                        r = StrFormat(_ERROR_FMT, str1584);
                      }
                    }
                    else {
                      r = consts::LookupCharPrompt(ch);
                      if (r == nullptr) {
                        r = StrFormat(_ERROR_FMT, StrFormat("\\%s is invalid or unimplemented in $PS1", ch));
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  }
  return r;
}

BigStr* Evaluator::_ReplaceBackslashCodes(List<Tuple2<int, BigStr*>*>* tokens) {
  List<BigStr*>* ret = nullptr;
  int non_printing;
  int id_;
  BigStr* s = nullptr;
  int i;
  BigStr* ch = nullptr;
  BigStr* arg = nullptr;
  BigStr* r = nullptr;
  StackRoot _root0(&tokens);
  StackRoot _root1(&ret);
  StackRoot _root2(&s);
  StackRoot _root3(&ch);
  StackRoot _root4(&arg);
  StackRoot _root5(&r);

  ret = Alloc<List<BigStr*>>();
  non_printing = 0;
  for (ListIter<Tuple2<int, BigStr*>*> it(tokens); !it.Done(); it.Next()) {
    Tuple2<int, BigStr*>* tup1 = it.Value();
    id_ = tup1->at0();
    s = tup1->at1();
    if ((id_ == Id::PS_Literals || id_ == Id::PS_BadBackslash)) {
      ret->append(s);
    }
    else {
      if (id_ == Id::PS_Octal3) {
        i = to_int(s->slice(1), 8);
        ret->append(chr((i % 256)));
      }
      else {
        if (id_ == Id::PS_LBrace) {
          non_printing += 1;
          ret->append(str1586);
        }
        else {
          if (id_ == Id::PS_RBrace) {
            non_printing -= 1;
            if (non_printing < 0) {
              return StrFormat(_ERROR_FMT, _UNBALANCED_ERROR);
            }
            ret->append(str1587);
          }
          else {
            if (id_ == Id::PS_Subst) {
              ch = s->at(1);
              arg = nullptr;
              if (str_equals(ch, str1588)) {
                arg = s->slice(3, -1);
              }
              r = this->PromptSubst(ch, arg);
              ret->append(r->replace(str1589, str1590));
            }
            else {
              assert(0);  // AssertionError
            }
          }
        }
      }
    }
  }
  if (non_printing != 0) {
    return StrFormat(_ERROR_FMT, _UNBALANCED_ERROR);
  }
  return str1592->join(ret);
}

BigStr* Evaluator::EvalPrompt(value_asdl::value_t* UP_val) {
  List<Tuple2<int, BigStr*>*>* tokens = nullptr;
  BigStr* ps1_str = nullptr;
  syntax_asdl::CompoundWord* ps1_word = nullptr;
  word_parse::WordParser* w_parser = nullptr;
  value::Str* val2 = nullptr;
  StackRoot _root0(&UP_val);
  StackRoot _root1(&tokens);
  StackRoot _root2(&ps1_str);
  StackRoot _root3(&ps1_word);
  StackRoot _root4(&w_parser);
  StackRoot _root5(&val2);

  if (UP_val->tag() != value_e::Str) {
    return str1593;
  }
  value::Str* val = static_cast<value::Str*>(UP_val);
  tokens = this->tokens_cache->get(val->s);
  if (tokens == nullptr) {
    tokens = match::Ps1Tokens(val->s);
    this->tokens_cache->set(val->s, tokens);
  }
  ps1_str = this->_ReplaceBackslashCodes(tokens);
  ps1_word = this->parse_cache->get(ps1_str);
  if (ps1_word == nullptr) {
    w_parser = this->parse_ctx->MakeWordParserForPlugin(ps1_str);
    try {
      ps1_word = w_parser->ReadForPlugin();
    }
    catch (error::Parse* e) {
      ps1_word = word_::ErrorWord(StrFormat("<ERROR: Can't parse PS1: %s>", e->UserErrorString()));
    }
    this->parse_cache->set(ps1_str, ps1_word);
  }
  val2 = this->word_ev->EvalForPlugin(ps1_word);
  return val2->s;
}

BigStr* Evaluator::EvalFirstPrompt() {
  value_asdl::value_t* UP_func_val = nullptr;
  List<value_asdl::value_t*>* pos_args = nullptr;
  value_asdl::value_t* val = nullptr;
  value_asdl::value_t* UP_val = nullptr;
  BigStr* msg = nullptr;
  value_asdl::value_t* ps1_val = nullptr;
  BigStr* prompt_str = nullptr;
  StackRoot _root0(&UP_func_val);
  StackRoot _root1(&pos_args);
  StackRoot _root2(&val);
  StackRoot _root3(&UP_val);
  StackRoot _root4(&msg);
  StackRoot _root5(&ps1_val);
  StackRoot _root6(&prompt_str);

  UP_func_val = this->mem->GetValue(str1595);
  if (UP_func_val->tag() == value_e::Func) {
    value::Func* func_val = static_cast<value::Func*>(UP_func_val);
    pos_args = NewList<value_asdl::value_t*>(std::initializer_list<value_asdl::value_t*>{this->global_io});
    val = this->expr_ev->PluginCall(func_val, pos_args);
    UP_val = val;
    switch (val->tag()) {
      case value_e::Str: {
        value::Str* val = static_cast<value::Str*>(UP_val);
        return val->s;
      }
        break;
      default: {
        msg = StrFormat("renderPrompt() should return Str, got %s", ui::ValType(val));
        return StrFormat(_ERROR_FMT, msg);
      }
    }
  }
  ps1_val = this->mem->GetValue(str1597);
  prompt_str = this->EvalPrompt(ps1_val);
  if (str_equals(this->lang, str1598)) {
    prompt_str = str_concat(str1599, prompt_str);
  }
  return prompt_str;
}
BigStr* PROMPT_COMMAND = str1600;

UserPlugin::UserPlugin(state::Mem* mem, parse_lib::ParseContext* parse_ctx, cmd_eval::CommandEvaluator* cmd_ev, ui::ErrorFormatter* errfmt) {
  this->mem = mem;
  this->parse_ctx = parse_ctx;
  this->cmd_ev = cmd_ev;
  this->errfmt = errfmt;
  this->arena = parse_ctx->arena;
  this->parse_cache = Alloc<Dict<BigStr*, syntax_asdl::command_t*>>();
}

void UserPlugin::Run() {
  value_asdl::value_t* val = nullptr;
  BigStr* prompt_cmd = nullptr;
  syntax_asdl::command_t* node = nullptr;
  reader::FileLineReader* line_reader = nullptr;
  cmd_parse::CommandParser* c_parser = nullptr;
  source::Variable* src = nullptr;
  StackRoot _root0(&val);
  StackRoot _root1(&prompt_cmd);
  StackRoot _root2(&node);
  StackRoot _root3(&line_reader);
  StackRoot _root4(&c_parser);
  StackRoot _root5(&src);

  val = this->mem->GetValue(PROMPT_COMMAND);
  if (val->tag() != value_e::Str) {
    return ;
  }
  prompt_cmd = static_cast<value::Str*>(val)->s;
  node = this->parse_cache->get(prompt_cmd);
  if (node == nullptr) {
    line_reader = reader::StringLineReader(prompt_cmd, this->arena);
    c_parser = this->parse_ctx->MakeOshParser(line_reader);
    src = Alloc<source::Variable>(PROMPT_COMMAND, loc::Missing);
    {  // with
      alloc::ctx_SourceCode ctx{this->arena, src};

      try {
        node = main_loop::ParseWholeFile(c_parser);
      }
      catch (error::Parse* e) {
        this->errfmt->PrettyPrintError(e);
        return ;
      }
    }
    this->parse_cache->set(prompt_cmd, node);
  }
  {  // with
    state::ctx_Registers ctx{this->mem};

    this->cmd_ev->ExecuteAndCatch(node);
  }
}

}  // define namespace prompt

namespace sh_expr_eval {  // define

using id_kind_asdl::Id;
using runtime_asdl::scope_t;
using syntax_asdl::word_t;
using syntax_asdl::CompoundWord;
using syntax_asdl::Token;
using syntax_asdl::loc;
using syntax_asdl::loc_t;
using syntax_asdl::source;
using syntax_asdl::arith_expr;
using syntax_asdl::arith_expr_e;
using syntax_asdl::arith_expr_t;
using syntax_asdl::bool_expr;
using syntax_asdl::bool_expr_e;
using syntax_asdl::bool_expr_t;
using syntax_asdl::sh_lhs;
using syntax_asdl::sh_lhs_e;
using syntax_asdl::sh_lhs_t;
using syntax_asdl::BracedVarSub;
using option_asdl::option_i;
using types_asdl::bool_arg_type_e;
using value_asdl::value;
using value_asdl::value_e;
using value_asdl::value_t;
using value_asdl::sh_lvalue;
using value_asdl::sh_lvalue_e;
using value_asdl::sh_lvalue_t;
using value_asdl::LeftName;
using value_asdl::eggex_ops;
using value_asdl::regex_match;
using value_asdl::RegexMatch;
using error::e_die;
using error::e_die_status;
using error::e_strict;
using error::e_usage;
using mylib::str_cmp;

value_asdl::value_t* OldValue(value_asdl::sh_lvalue_t* lval, state::Mem* mem, optview::Exec* exec_opts) {
  value_asdl::sh_lvalue_t* UP_lval = nullptr;
  BigStr* var_name = nullptr;
  value_asdl::value_t* val = nullptr;
  value_asdl::value_t* UP_val = nullptr;
  value::BashArray* array_val = nullptr;
  BigStr* s = nullptr;
  value::BashAssoc* assoc_val = nullptr;
  StackRoot _root0(&lval);
  StackRoot _root1(&mem);
  StackRoot _root2(&exec_opts);
  StackRoot _root3(&UP_lval);
  StackRoot _root4(&var_name);
  StackRoot _root5(&val);
  StackRoot _root6(&UP_val);
  StackRoot _root7(&array_val);
  StackRoot _root8(&s);
  StackRoot _root9(&assoc_val);

  UP_lval = lval;
  switch (lval->tag()) {
    case sh_lvalue_e::Var: {
      LeftName* lval = static_cast<LeftName*>(UP_lval);
      var_name = lval->name;
    }
      break;
    case sh_lvalue_e::Indexed: {
      sh_lvalue::Indexed* lval = static_cast<sh_lvalue::Indexed*>(UP_lval);
      var_name = lval->name;
    }
      break;
    case sh_lvalue_e::Keyed: {
      sh_lvalue::Keyed* lval = static_cast<sh_lvalue::Keyed*>(UP_lval);
      var_name = lval->name;
    }
      break;
    default: {
      assert(0);  // AssertionError
    }
  }
  val = mem->GetValue(var_name);
  if ((exec_opts and (exec_opts->nounset() and val->tag() == value_e::Undef))) {
    e_die(StrFormat("Undefined variable %r", var_name));
  }
  UP_val = val;
  switch (lval->tag()) {
    case sh_lvalue_e::Var: {
      return val;
    }
      break;
    case sh_lvalue_e::Indexed: {
      sh_lvalue::Indexed* lval = static_cast<sh_lvalue::Indexed*>(UP_lval);
      array_val = nullptr;
      switch (val->tag()) {
        case value_e::Undef: {
          array_val = Alloc<value::BashArray>(Alloc<List<BigStr*>>());
        }
          break;
        case value_e::BashArray: {
          value::BashArray* tmp = static_cast<value::BashArray*>(UP_val);
          array_val = tmp;
        }
          break;
        default: {
          e_die(StrFormat("Can't use [] on value of type %s", ui::ValType(val)));
        }
      }
      s = word_eval::GetArrayItem(array_val->strs, lval->index);
      if (s == nullptr) {
        val = Alloc<value::Str>(str1603);
      }
      else {
        val = Alloc<value::Str>(s);
      }
    }
      break;
    case sh_lvalue_e::Keyed: {
      sh_lvalue::Keyed* lval = static_cast<sh_lvalue::Keyed*>(UP_lval);
      assoc_val = nullptr;
      switch (val->tag()) {
        case value_e::Undef: {
          assert(0);  // AssertionError
        }
          break;
        case value_e::BashAssoc: {
          value::BashAssoc* tmp2 = static_cast<value::BashAssoc*>(UP_val);
          assoc_val = tmp2;
        }
          break;
        default: {
          e_die(StrFormat("Can't use [] on value of type %s", ui::ValType(val)));
        }
      }
      s = assoc_val->d->get(lval->key);
      if (s == nullptr) {
        val = Alloc<value::Str>(str1605);
      }
      else {
        val = Alloc<value::Str>(s);
      }
    }
      break;
    default: {
      assert(0);  // AssertionError
    }
  }
  return val;
}

UnsafeArith::UnsafeArith(state::Mem* mem, optview::Exec* exec_opts, state::MutableOpts* mutable_opts, parse_lib::ParseContext* parse_ctx, sh_expr_eval::ArithEvaluator* arith_ev, ui::ErrorFormatter* errfmt) {
  this->mem = mem;
  this->exec_opts = exec_opts;
  this->mutable_opts = mutable_opts;
  this->parse_ctx = parse_ctx;
  this->arith_ev = arith_ev;
  this->errfmt = errfmt;
  this->arena = this->parse_ctx->arena;
}

value_asdl::sh_lvalue_t* UnsafeArith::ParseLValue(BigStr* s, syntax_asdl::loc_t* location) {
  tdop::TdopParser* a_parser = nullptr;
  syntax_asdl::arith_expr_t* anode = nullptr;
  value_asdl::sh_lvalue_t* lval = nullptr;
  StackRoot _root0(&s);
  StackRoot _root1(&location);
  StackRoot _root2(&a_parser);
  StackRoot _root3(&anode);
  StackRoot _root4(&lval);

  if (!this->parse_ctx->parse_opts->parse_sh_arith()) {
    if (!match::IsValidVarName(s)) {
      e_die(StrFormat("Invalid variable name %r (parse_sh_arith is off)", s), location);
    }
    return Alloc<LeftName>(s, location);
  }
  a_parser = this->parse_ctx->MakeArithParser(s);
  {  // with
    alloc::ctx_SourceCode ctx{this->arena, Alloc<source::ArgvWord>(str1607, location)};

    try {
      anode = a_parser->Parse();
    }
    catch (error::Parse* e) {
      this->errfmt->PrettyPrintError(e);
      e_usage(str1608, location);
    }
  }
  if (this->exec_opts->eval_unsafe_arith()) {
    lval = this->arith_ev->EvalArithLhs(anode);
  }
  else {
    {  // with
      state::ctx_Option ctx{this->mutable_opts, NewList<int>(std::initializer_list<int>{option_i::_allow_command_sub}), false};

      lval = this->arith_ev->EvalArithLhs(anode);
    }
  }
  return lval;
}

syntax_asdl::BracedVarSub* UnsafeArith::ParseVarRef(BigStr* ref_str, syntax_asdl::Token* blame_tok) {
  reader::FileLineReader* line_reader = nullptr;
  lexer::Lexer* lexer = nullptr;
  word_parse::WordParser* w_parser = nullptr;
  source::VarRef* src = nullptr;
  syntax_asdl::BracedVarSub* bvs_part = nullptr;
  StackRoot _root0(&ref_str);
  StackRoot _root1(&blame_tok);
  StackRoot _root2(&line_reader);
  StackRoot _root3(&lexer);
  StackRoot _root4(&w_parser);
  StackRoot _root5(&src);
  StackRoot _root6(&bvs_part);

  line_reader = reader::StringLineReader(ref_str, this->arena);
  lexer = this->parse_ctx->MakeLexer(line_reader);
  w_parser = this->parse_ctx->MakeWordParser(lexer, line_reader);
  src = Alloc<source::VarRef>(blame_tok);
  {  // with
    alloc::ctx_SourceCode ctx{this->arena, src};

    try {
      bvs_part = w_parser->ParseVarRef();
    }
    catch (error::Parse* e) {
      this->errfmt->PrettyPrintError(e);
      e_die(str1609, blame_tok);
    }
  }
  return bvs_part;
}

ArithEvaluator::ArithEvaluator(state::Mem* mem, optview::Exec* exec_opts, state::MutableOpts* mutable_opts, parse_lib::ParseContext* parse_ctx, ui::ErrorFormatter* errfmt) {
  this->word_ev = nullptr;
  this->mem = mem;
  this->exec_opts = exec_opts;
  this->mutable_opts = mutable_opts;
  this->parse_ctx = parse_ctx;
  this->errfmt = errfmt;
}

void ArithEvaluator::CheckCircularDeps() {
}

mops::BigInt ArithEvaluator::_StringToBigInt(BigStr* s, syntax_asdl::loc_t* blame_loc) {
  mops::BigInt integer;
  BigStr* b = nullptr;
  BigStr* digits = nullptr;
  int base;
  int digit;
  alloc::Arena* arena = nullptr;
  tdop::TdopParser* a_parser = nullptr;
  syntax_asdl::arith_expr_t* node2 = nullptr;
  StackRoot _root0(&s);
  StackRoot _root1(&blame_loc);
  StackRoot _root2(&b);
  StackRoot _root3(&digits);
  StackRoot _root4(&arena);
  StackRoot _root5(&a_parser);
  StackRoot _root6(&node2);

  if (s->startswith(str1610)) {
    try {
      integer = mops::FromStr(s, 16);
    }
    catch (ValueError*) {
      e_strict(StrFormat("Invalid hex constant %r", s), blame_loc);
    }
    return integer;
  }
  if (s->startswith(str1612)) {
    try {
      integer = mops::FromStr(s, 8);
    }
    catch (ValueError*) {
      e_strict(StrFormat("Invalid octal constant %r", s), blame_loc);
    }
    return integer;
  }
  Tuple2<BigStr*, BigStr*> tup0 = mylib::split_once(s, str1614);
  b = tup0.at0();
  digits = tup0.at1();
  if (digits != nullptr) {
    try {
      base = to_int(b);
    }
    catch (ValueError*) {
      e_strict(StrFormat("Invalid base for numeric constant %r", b), blame_loc);
    }
    integer = mops::ZERO;
    for (StrIter it(digits); !it.Done(); it.Next()) {
      BigStr* ch = it.Value();
      StackRoot _for(&ch    );
      if (IsLower(ch)) {
        digit = ((ord(ch) - ord(str1616)) + 10);
      }
      else {
        if (IsUpper(ch)) {
          digit = ((ord(ch) - ord(str1617)) + 36);
        }
        else {
          if (str_equals(ch, str1618)) {
            digit = 62;
          }
          else {
            if (str_equals(ch, str1619)) {
              digit = 63;
            }
            else {
              if (ch->isdigit()) {
                digit = to_int(ch);
              }
              else {
                e_strict(StrFormat("Invalid digits for numeric constant %r", digits), blame_loc);
              }
            }
          }
        }
      }
      if (digit >= base) {
        e_strict(StrFormat("Digits %r out of range for base %d", digits, base), blame_loc);
      }
      integer = mops::Add(mops::Mul(integer, mops::BigInt(base)), mops::BigInt(digit));
    }
    return integer;
  }
  try {
    integer = mops::FromStr(s);
  }
  catch (ValueError*) {
    if (this->parse_ctx) {
      arena = this->parse_ctx->arena;
      if (len(s->strip()) == 0) {
        return mops::ZERO;
      }
      a_parser = this->parse_ctx->MakeArithParser(s);
      {  // with
        alloc::ctx_SourceCode ctx{arena, Alloc<source::Variable>(nullptr, blame_loc)};

        try {
          node2 = a_parser->Parse();
        }
        catch (error::Parse* e) {
          this->errfmt->PrettyPrintError(e);
          e_die(str1622, e->location);
        }
      }
      if (node2->tag() == arith_expr_e::Word) {
        e_die(StrFormat("Invalid integer constant %r", s), blame_loc);
      }
      if (this->exec_opts->eval_unsafe_arith()) {
        integer = this->EvalToBigInt(node2);
      }
      else {
        {  // with
          state::ctx_Option ctx{this->mutable_opts, NewList<int>(std::initializer_list<int>{option_i::_allow_command_sub}), false};

          integer = this->EvalToBigInt(node2);
        }
      }
    }
    else {
      if ((len(s->strip()) == 0 or match::IsValidVarName(s))) {
        e_strict(StrFormat("Invalid integer constant %r", s), blame_loc);
      }
      else {
        e_die(StrFormat("Invalid integer constant %r", s), blame_loc);
      }
    }
  }
  return integer;
}

mops::BigInt ArithEvaluator::_ValToIntOrError(value_asdl::value_t* val, syntax_asdl::arith_expr_t* blame) {
  value_asdl::value_t* UP_val = nullptr;
  StackRoot _root0(&val);
  StackRoot _root1(&blame);
  StackRoot _root2(&UP_val);

  try {
    UP_val = val;
    switch (val->tag()) {
      case value_e::Undef: {
        e_strict(str1626, Alloc<loc::Arith>(blame));
      }
        break;
      case value_e::Int: {
        value::Int* val = static_cast<value::Int*>(UP_val);
        return val->i;
      }
        break;
      case value_e::Str: {
        value::Str* val = static_cast<value::Str*>(UP_val);
        return this->_StringToBigInt(val->s, Alloc<loc::Arith>(blame));
      }
        break;
    }
  }
  catch (error::Strict* e) {
    if (this->exec_opts->strict_arith()) {
      throw ;
    }
    else {
      return mops::ZERO;
    }
  }
  e_die(StrFormat("Expected a value convertible to integer, got %s", ui::ValType(val)), Alloc<loc::Arith>(blame));
}

Tuple2<mops::BigInt, value_asdl::sh_lvalue_t*> ArithEvaluator::_EvalLhsAndLookupArith(syntax_asdl::arith_expr_t* node) {
  value_asdl::sh_lvalue_t* lval = nullptr;
  value_asdl::value_t* val = nullptr;
  LeftName* named_lval = nullptr;
  mops::BigInt i;
  StackRoot _root0(&node);
  StackRoot _root1(&lval);
  StackRoot _root2(&val);
  StackRoot _root3(&named_lval);

  lval = this->EvalArithLhs(node);
  val = OldValue(lval, this->mem, this->exec_opts);
  if (((val->tag() == value_e::BashArray || val->tag() == value_e::BashAssoc) and lval->tag() == sh_lvalue_e::Var)) {
    named_lval = static_cast<LeftName*>(lval);
    if (word_eval::ShouldArrayDecay(named_lval->name, this->exec_opts)) {
      if (val->tag() == value_e::BashArray) {
        lval = Alloc<sh_lvalue::Indexed>(named_lval->name, 0, loc::Missing);
      }
      else {
        if (val->tag() == value_e::BashAssoc) {
          lval = Alloc<sh_lvalue::Keyed>(named_lval->name, str1628, loc::Missing);
        }
      }
      val = word_eval::DecayArray(val);
    }
  }
  i = this->_ValToIntOrError(val, node);
  return Tuple2<mops::BigInt, value_asdl::sh_lvalue_t*>(i, lval);
}

void ArithEvaluator::_Store(value_asdl::sh_lvalue_t* lval, mops::BigInt new_int) {
  value::Str* val = nullptr;
  StackRoot _root0(&lval);
  StackRoot _root1(&val);

  val = Alloc<value::Str>(mops::ToStr(new_int));
  state::OshLanguageSetValue(this->mem, lval, val);
}

mops::BigInt ArithEvaluator::EvalToBigInt(syntax_asdl::arith_expr_t* node) {
  value_asdl::value_t* val = nullptr;
  Token* vsub = nullptr;
  mops::BigInt i;
  StackRoot _root0(&node);
  StackRoot _root1(&val);
  StackRoot _root2(&vsub);

  val = this->Eval(node);
  if (((val->tag() == value_e::BashArray || val->tag() == value_e::BashAssoc) and node->tag() == arith_expr_e::VarSub)) {
    vsub = static_cast<Token*>(node);
    if (word_eval::ShouldArrayDecay(lexer::LazyStr(vsub), this->exec_opts)) {
      val = word_eval::DecayArray(val);
    }
  }
  i = this->_ValToIntOrError(val, node);
  return i;
}

int ArithEvaluator::EvalToInt(syntax_asdl::arith_expr_t* node) {
  StackRoot _root0(&node);

  return mops::BigTruncate(this->EvalToBigInt(node));
}

value_asdl::value_t* ArithEvaluator::Eval(syntax_asdl::arith_expr_t* node) {
  syntax_asdl::arith_expr_t* UP_node = nullptr;
  BigStr* var_name = nullptr;
  value_asdl::value_t* val = nullptr;
  int op_id;
  mops::BigInt old_big;
  value_asdl::sh_lvalue_t* lval = nullptr;
  mops::BigInt new_big;
  mops::BigInt result;
  mops::BigInt rhs_big;
  mops::BigInt i;
  mops::BigInt lhs_big;
  value_asdl::value_t* left = nullptr;
  value_asdl::value_t* UP_left = nullptr;
  int small_i;
  BigStr* s = nullptr;
  BigStr* key = nullptr;
  mops::BigInt index;
  mops::BigInt cond;
  StackRoot _root0(&node);
  StackRoot _root1(&UP_node);
  StackRoot _root2(&var_name);
  StackRoot _root3(&val);
  StackRoot _root4(&lval);
  StackRoot _root5(&left);
  StackRoot _root6(&UP_left);
  StackRoot _root7(&s);
  StackRoot _root8(&key);

  UP_node = node;
  switch (node->tag()) {
    case arith_expr_e::EmptyZero: {
      return Alloc<value::Int>(mops::ZERO);
    }
      break;
    case arith_expr_e::EmptyOne: {
      return Alloc<value::Int>(mops::ONE);
    }
      break;
    case arith_expr_e::VarSub: {
      Token* vsub = static_cast<Token*>(UP_node);
      var_name = lexer::LazyStr(vsub);
      val = this->mem->GetValue(var_name);
      if ((val->tag() == value_e::Undef and this->exec_opts->nounset())) {
        e_die(StrFormat("Undefined variable %r", var_name), vsub);
      }
      return val;
    }
      break;
    case arith_expr_e::Word: {
      CompoundWord* w = static_cast<CompoundWord*>(UP_node);
      return this->word_ev->EvalWordToString(w);
    }
      break;
    case arith_expr_e::UnaryAssign: {
      arith_expr::UnaryAssign* node = static_cast<arith_expr::UnaryAssign*>(UP_node);
      op_id = node->op_id;
      Tuple2<mops::BigInt, value_asdl::sh_lvalue_t*> tup1 = this->_EvalLhsAndLookupArith(node->child);
      old_big = tup1.at0();
      lval = tup1.at1();
      if (op_id == Id::Node_PostDPlus) {
        new_big = mops::Add(old_big, mops::ONE);
        result = old_big;
      }
      else {
        if (op_id == Id::Node_PostDMinus) {
          new_big = mops::Sub(old_big, mops::ONE);
          result = old_big;
        }
        else {
          if (op_id == Id::Arith_DPlus) {
            new_big = mops::Add(old_big, mops::ONE);
            result = new_big;
          }
          else {
            if (op_id == Id::Arith_DMinus) {
              new_big = mops::Sub(old_big, mops::ONE);
              result = new_big;
            }
            else {
              assert(0);  // AssertionError
            }
          }
        }
      }
      this->_Store(lval, new_big);
      return Alloc<value::Int>(result);
    }
      break;
    case arith_expr_e::BinaryAssign: {
      arith_expr::BinaryAssign* node = static_cast<arith_expr::BinaryAssign*>(UP_node);
      op_id = node->op_id;
      if (op_id == Id::Arith_Equal) {
        lval = this->EvalArithLhs(node->left);
        rhs_big = this->EvalToBigInt(node->right);
        this->_Store(lval, rhs_big);
        return Alloc<value::Int>(rhs_big);
      }
      Tuple2<mops::BigInt, value_asdl::sh_lvalue_t*> tup2 = this->_EvalLhsAndLookupArith(node->left);
      old_big = tup2.at0();
      lval = tup2.at1();
      rhs_big = this->EvalToBigInt(node->right);
      if (op_id == Id::Arith_PlusEqual) {
        new_big = mops::Add(old_big, rhs_big);
      }
      else {
        if (op_id == Id::Arith_MinusEqual) {
          new_big = mops::Sub(old_big, rhs_big);
        }
        else {
          if (op_id == Id::Arith_StarEqual) {
            new_big = mops::Mul(old_big, rhs_big);
          }
          else {
            if (op_id == Id::Arith_SlashEqual) {
              if (mops::Equal(rhs_big, mops::ZERO)) {
                e_die(str1630);
              }
              new_big = num::IntDivide(old_big, rhs_big);
            }
            else {
              if (op_id == Id::Arith_PercentEqual) {
                if (mops::Equal(rhs_big, mops::ZERO)) {
                  e_die(str1631);
                }
                new_big = num::IntRemainder(old_big, rhs_big);
              }
              else {
                if (op_id == Id::Arith_DGreatEqual) {
                  new_big = mops::RShift(old_big, rhs_big);
                }
                else {
                  if (op_id == Id::Arith_DLessEqual) {
                    new_big = mops::LShift(old_big, rhs_big);
                  }
                  else {
                    if (op_id == Id::Arith_AmpEqual) {
                      new_big = mops::BitAnd(old_big, rhs_big);
                    }
                    else {
                      if (op_id == Id::Arith_PipeEqual) {
                        new_big = mops::BitOr(old_big, rhs_big);
                      }
                      else {
                        if (op_id == Id::Arith_CaretEqual) {
                          new_big = mops::BitXor(old_big, rhs_big);
                        }
                        else {
                          assert(0);  // AssertionError
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
      this->_Store(lval, new_big);
      return Alloc<value::Int>(new_big);
    }
      break;
    case arith_expr_e::Unary: {
      arith_expr::Unary* node = static_cast<arith_expr::Unary*>(UP_node);
      op_id = node->op_id;
      i = this->EvalToBigInt(node->child);
      if (op_id == Id::Node_UnaryPlus) {
        result = i;
      }
      else {
        if (op_id == Id::Node_UnaryMinus) {
          result = mops::Sub(mops::ZERO, i);
        }
        else {
          if (op_id == Id::Arith_Bang) {
            if (mops::Equal(i, mops::ZERO)) {
              result = mops::ONE;
            }
            else {
              result = mops::ZERO;
            }
          }
          else {
            if (op_id == Id::Arith_Tilde) {
              result = mops::BitNot(i);
            }
            else {
              assert(0);  // AssertionError
            }
          }
        }
      }
      return Alloc<value::Int>(result);
    }
      break;
    case arith_expr_e::Binary: {
      arith_expr::Binary* node = static_cast<arith_expr::Binary*>(UP_node);
      op_id = node->op->id;
      if (op_id == Id::Arith_DPipe) {
        lhs_big = this->EvalToBigInt(node->left);
        if (mops::Equal(lhs_big, mops::ZERO)) {
          rhs_big = this->EvalToBigInt(node->right);
          if (mops::Equal(rhs_big, mops::ZERO)) {
            result = mops::ZERO;
          }
          else {
            result = mops::ONE;
          }
        }
        else {
          result = mops::ONE;
        }
        return Alloc<value::Int>(result);
      }
      if (op_id == Id::Arith_DAmp) {
        lhs_big = this->EvalToBigInt(node->left);
        if (mops::Equal(lhs_big, mops::ZERO)) {
          result = mops::ZERO;
        }
        else {
          rhs_big = this->EvalToBigInt(node->right);
          if (mops::Equal(rhs_big, mops::ZERO)) {
            result = mops::ZERO;
          }
          else {
            result = mops::ONE;
          }
        }
        return Alloc<value::Int>(result);
      }
      if (op_id == Id::Arith_LBracket) {
        left = this->Eval(node->left);
        UP_left = left;
        switch (left->tag()) {
          case value_e::BashArray: {
            value::BashArray* array_val = static_cast<value::BashArray*>(UP_left);
            small_i = mops::BigTruncate(this->EvalToBigInt(node->right));
            s = word_eval::GetArrayItem(array_val->strs, small_i);
          }
            break;
          case value_e::BashAssoc: {
            value::BashAssoc* left = static_cast<value::BashAssoc*>(UP_left);
            key = this->EvalWordToString(node->right);
            s = left->d->get(key);
          }
            break;
          case value_e::Str: {
            value::Str* left = static_cast<value::Str*>(UP_left);
            if (this->exec_opts->strict_arith()) {
              e_die(str1632, node->op);
            }
            index = this->EvalToBigInt(node->right);
            s = mops::Equal(index, mops::ZERO) ? left->s : nullptr;
          }
            break;
          case value_e::Undef: {
            if (this->exec_opts->strict_arith()) {
              e_die(str1633, node->op);
            }
            s = nullptr;
          }
            break;
          default: {
            e_die(StrFormat("Value of type %s can't be indexed", ui::ValType(left)), node->op);
          }
        }
        if (s == nullptr) {
          val = value::Undef;
        }
        else {
          val = Alloc<value::Str>(s);
        }
        return val;
      }
      if (op_id == Id::Arith_Comma) {
        this->EvalToBigInt(node->left);
        result = this->EvalToBigInt(node->right);
        return Alloc<value::Int>(result);
      }
      lhs_big = this->EvalToBigInt(node->left);
      rhs_big = this->EvalToBigInt(node->right);
      if (op_id == Id::Arith_Plus) {
        result = mops::Add(lhs_big, rhs_big);
      }
      else {
        if (op_id == Id::Arith_Minus) {
          result = mops::Sub(lhs_big, rhs_big);
        }
        else {
          if (op_id == Id::Arith_Star) {
            result = mops::Mul(lhs_big, rhs_big);
          }
          else {
            if (op_id == Id::Arith_Slash) {
              if (mops::Equal(rhs_big, mops::ZERO)) {
                e_die(str1635, node->op);
              }
              result = num::IntDivide(lhs_big, rhs_big);
            }
            else {
              if (op_id == Id::Arith_Percent) {
                if (mops::Equal(rhs_big, mops::ZERO)) {
                  e_die(str1636, node->op);
                }
                result = num::IntRemainder(lhs_big, rhs_big);
              }
              else {
                if (op_id == Id::Arith_DStar) {
                  if (mops::Greater(mops::ZERO, rhs_big)) {
                    e_die(str1637, Alloc<loc::Arith>(node->right));
                  }
                  result = num::Exponent(lhs_big, rhs_big);
                }
                else {
                  if (op_id == Id::Arith_DEqual) {
                    result = mops::FromBool(mops::Equal(lhs_big, rhs_big));
                  }
                  else {
                    if (op_id == Id::Arith_NEqual) {
                      result = mops::FromBool(!mops::Equal(lhs_big, rhs_big));
                    }
                    else {
                      if (op_id == Id::Arith_Great) {
                        result = mops::FromBool(mops::Greater(lhs_big, rhs_big));
                      }
                      else {
                        if (op_id == Id::Arith_GreatEqual) {
                          result = mops::FromBool((mops::Greater(lhs_big, rhs_big) or mops::Equal(lhs_big, rhs_big)));
                        }
                        else {
                          if (op_id == Id::Arith_Less) {
                            result = mops::FromBool(mops::Greater(rhs_big, lhs_big));
                          }
                          else {
                            if (op_id == Id::Arith_LessEqual) {
                              result = mops::FromBool((mops::Greater(rhs_big, lhs_big) or mops::Equal(lhs_big, rhs_big)));
                            }
                            else {
                              if (op_id == Id::Arith_Pipe) {
                                result = mops::BitOr(lhs_big, rhs_big);
                              }
                              else {
                                if (op_id == Id::Arith_Amp) {
                                  result = mops::BitAnd(lhs_big, rhs_big);
                                }
                                else {
                                  if (op_id == Id::Arith_Caret) {
                                    result = mops::BitXor(lhs_big, rhs_big);
                                  }
                                  else {
                                    if (op_id == Id::Arith_DLess) {
                                      result = mops::LShift(lhs_big, rhs_big);
                                    }
                                    else {
                                      if (op_id == Id::Arith_DGreat) {
                                        result = mops::RShift(lhs_big, rhs_big);
                                      }
                                      else {
                                        assert(0);  // AssertionError
                                      }
                                    }
                                  }
                                }
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
      return Alloc<value::Int>(result);
    }
      break;
    case arith_expr_e::TernaryOp: {
      arith_expr::TernaryOp* node = static_cast<arith_expr::TernaryOp*>(UP_node);
      cond = this->EvalToBigInt(node->cond);
      if (mops::Equal(cond, mops::ZERO)) {
        return this->Eval(node->false_expr);
      }
      else {
        return this->Eval(node->true_expr);
      }
    }
      break;
    default: {
      assert(0);  // AssertionError
    }
  }
  assert(0);  // AssertionError
}

BigStr* ArithEvaluator::EvalWordToString(syntax_asdl::arith_expr_t* node, syntax_asdl::loc_t* blame_loc) {
  syntax_asdl::arith_expr_t* UP_node = nullptr;
  value::Str* val = nullptr;
  StackRoot _root0(&node);
  StackRoot _root1(&blame_loc);
  StackRoot _root2(&UP_node);
  StackRoot _root3(&val);

  UP_node = node;
  if (node->tag() == arith_expr_e::Word) {
    CompoundWord* w = static_cast<CompoundWord*>(UP_node);
    val = this->word_ev->EvalWordToString(w);
    return val->s;
  }
  else {
    e_die(str1639, blame_loc);
  }
}

value_asdl::sh_lvalue_t* ArithEvaluator::EvalShellLhs(syntax_asdl::sh_lhs_t* node, runtime_asdl::scope_t which_scopes) {
  syntax_asdl::sh_lhs_t* UP_node = nullptr;
  value_asdl::sh_lvalue_t* lval = nullptr;
  value_asdl::LeftName* lval1 = nullptr;
  BigStr* key = nullptr;
  sh_lvalue::Keyed* lval2 = nullptr;
  int index;
  sh_lvalue::Indexed* lval3 = nullptr;
  StackRoot _root0(&node);
  StackRoot _root1(&UP_node);
  StackRoot _root2(&lval);
  StackRoot _root3(&lval1);
  StackRoot _root4(&key);
  StackRoot _root5(&lval2);
  StackRoot _root6(&lval3);

  UP_node = node;
  lval = nullptr;
  switch (node->tag()) {
    case sh_lhs_e::Name: {
      sh_lhs::Name* node = static_cast<sh_lhs::Name*>(UP_node);
      lval1 = Alloc<LeftName>(node->name, node->left);
      lval = lval1;
    }
      break;
    case sh_lhs_e::IndexedName: {
      sh_lhs::IndexedName* node = static_cast<sh_lhs::IndexedName*>(UP_node);
      if (this->mem->IsBashAssoc(node->name)) {
        key = this->EvalWordToString(node->index, node->left);
        lval2 = Alloc<sh_lvalue::Keyed>(node->name, key, node->left);
        lval = lval2;
      }
      else {
        index = mops::BigTruncate(this->EvalToBigInt(node->index));
        lval3 = Alloc<sh_lvalue::Indexed>(node->name, index, node->left);
        lval = lval3;
      }
    }
      break;
    default: {
      assert(0);  // AssertionError
    }
  }
  return lval;
}

Tuple2<BigStr*, syntax_asdl::loc_t*> ArithEvaluator::_VarNameOrWord(syntax_asdl::arith_expr_t* anode) {
  syntax_asdl::arith_expr_t* UP_anode = nullptr;
  BigStr* var_name = nullptr;
  BigStr* no_str = nullptr;
  StackRoot _root0(&anode);
  StackRoot _root1(&UP_anode);
  StackRoot _root2(&var_name);
  StackRoot _root3(&no_str);

  UP_anode = anode;
  switch (anode->tag()) {
    case arith_expr_e::VarSub: {
      Token* tok = static_cast<Token*>(UP_anode);
      return Tuple2<BigStr*, syntax_asdl::loc_t*>(lexer::LazyStr(tok), tok);
    }
      break;
    case arith_expr_e::Word: {
      CompoundWord* w = static_cast<CompoundWord*>(UP_anode);
      var_name = this->EvalWordToString(w);
      return Tuple2<BigStr*, syntax_asdl::loc_t*>(var_name, w);
    }
      break;
  }
  no_str = nullptr;
  return Tuple2<BigStr*, syntax_asdl::loc_t*>(no_str, loc::Missing);
}

value_asdl::sh_lvalue_t* ArithEvaluator::EvalArithLhs(syntax_asdl::arith_expr_t* anode) {
  syntax_asdl::arith_expr_t* UP_anode = nullptr;
  BigStr* var_name = nullptr;
  syntax_asdl::loc_t* blame_loc = nullptr;
  syntax_asdl::Token* arith_loc = nullptr;
  BigStr* key = nullptr;
  int index;
  StackRoot _root0(&anode);
  StackRoot _root1(&UP_anode);
  StackRoot _root2(&var_name);
  StackRoot _root3(&blame_loc);
  StackRoot _root4(&arith_loc);
  StackRoot _root5(&key);

  UP_anode = anode;
  if (anode->tag() == arith_expr_e::Binary) {
    arith_expr::Binary* anode = static_cast<arith_expr::Binary*>(UP_anode);
    if (anode->op->id == Id::Arith_LBracket) {
      Tuple2<BigStr*, syntax_asdl::loc_t*> tup3 = this->_VarNameOrWord(anode->left);
      var_name = tup3.at0();
      blame_loc = tup3.at1();
      if (!match::IsValidVarName(var_name)) {
        e_die(StrFormat("Invalid variable name %r", var_name), blame_loc);
      }
      if (var_name != nullptr) {
        if (this->mem->IsBashAssoc(var_name)) {
          arith_loc = location::TokenForArith(anode);
          key = this->EvalWordToString(anode->right, arith_loc);
          return Alloc<sh_lvalue::Keyed>(var_name, key, blame_loc);
        }
        else {
          index = mops::BigTruncate(this->EvalToBigInt(anode->right));
          return Alloc<sh_lvalue::Indexed>(var_name, index, blame_loc);
        }
      }
    }
  }
  Tuple2<BigStr*, syntax_asdl::loc_t*> tup4 = this->_VarNameOrWord(anode);
  var_name = tup4.at0();
  blame_loc = tup4.at1();
  if (var_name != nullptr) {
    return Alloc<LeftName>(var_name, blame_loc);
  }
  e_die_status(2, str1641, blame_loc);
}

BoolEvaluator::BoolEvaluator(state::Mem* mem, optview::Exec* exec_opts, state::MutableOpts* mutable_opts, parse_lib::ParseContext* parse_ctx, ui::ErrorFormatter* errfmt, bool always_strict) : ::sh_expr_eval::ArithEvaluator(mem, exec_opts, mutable_opts, parse_ctx, errfmt) {
  this->always_strict = always_strict;
}

bool BoolEvaluator::_IsDefined(BigStr* s, syntax_asdl::loc_t* blame_loc) {
  List<BigStr*>* m = nullptr;
  BigStr* var_name = nullptr;
  BigStr* index_str = nullptr;
  value_asdl::value_t* val = nullptr;
  value_asdl::value_t* UP_val = nullptr;
  int index;
  StackRoot _root0(&s);
  StackRoot _root1(&blame_loc);
  StackRoot _root2(&m);
  StackRoot _root3(&var_name);
  StackRoot _root4(&index_str);
  StackRoot _root5(&val);
  StackRoot _root6(&UP_val);

  m = util::RegexSearch(consts::TEST_V_RE, s);
  if (m == nullptr) {
    if (this->exec_opts->strict_word_eval()) {
      e_die(str1642, blame_loc);
    }
    return false;
  }
  var_name = m->at(1);
  index_str = m->at(3);
  val = this->mem->GetValue(var_name);
  if (len(index_str) == 0) {
    return val->tag() != value_e::Undef;
  }
  UP_val = val;
  switch (val->tag()) {
    case value_e::BashArray: {
      value::BashArray* val = static_cast<value::BashArray*>(UP_val);
      try {
        index = to_int(index_str);
      }
      catch (ValueError* e) {
        if (this->exec_opts->strict_word_eval()) {
          e_die(StrFormat("-v got BashArray and invalid index %r", index_str), blame_loc);
        }
        return false;
      }
      if (index < 0) {
        if (this->exec_opts->strict_word_eval()) {
          e_die(StrFormat("-v got invalid negative index %s", index_str), blame_loc);
        }
        return false;
      }
      if (index < len(val->strs)) {
        return val->strs->at(index) != nullptr;
      }
      return false;
    }
      break;
    case value_e::BashAssoc: {
      value::BashAssoc* val = static_cast<value::BashAssoc*>(UP_val);
      return dict_contains(val->d, index_str);
    }
      break;
    default: {
      ;  // pass
      if (this->exec_opts->strict_word_eval()) {
        throw Alloc<error::TypeErr>(val, str1645, blame_loc);
      }
      return false;
    }
  }
  assert(0);  // AssertionError
}

mops::BigInt BoolEvaluator::_StringToBigIntOrError(BigStr* s, syntax_asdl::word_t* blame_word) {
  syntax_asdl::loc_t* location = nullptr;
  mops::BigInt i;
  StackRoot _root0(&s);
  StackRoot _root1(&blame_word);
  StackRoot _root2(&location);

  if (blame_word) {
    location = Alloc<loc::Word>(blame_word);
  }
  else {
    location = loc::Missing;
  }
  try {
    i = this->_StringToBigInt(s, location);
  }
  catch (error::Strict* e) {
    if ((this->always_strict or this->exec_opts->strict_arith())) {
      throw ;
    }
    else {
      i = mops::ZERO;
    }
  }
  return i;
}

BigStr* BoolEvaluator::_EvalCompoundWord(syntax_asdl::word_t* word, int eval_flags) {
  value::Str* val = nullptr;
  StackRoot _root0(&word);
  StackRoot _root1(&val);

  val = this->word_ev->EvalWordToString(word, eval_flags);
  return val->s;
}

bool BoolEvaluator::EvalB(syntax_asdl::bool_expr_t* node) {
  syntax_asdl::bool_expr_t* UP_node = nullptr;
  BigStr* s = nullptr;
  bool b;
  int op_id;
  types_asdl::bool_arg_type_t arg_type;
  int index;
  int eval_flags;
  BigStr* s1 = nullptr;
  BigStr* s2 = nullptr;
  mops::BigInt i1;
  mops::BigInt i2;
  int fnmatch_flags;
  int regex_flags;
  List<int>* indices = nullptr;
  StackRoot _root0(&node);
  StackRoot _root1(&UP_node);
  StackRoot _root2(&s);
  StackRoot _root3(&s1);
  StackRoot _root4(&s2);
  StackRoot _root5(&indices);

  UP_node = node;
  switch (node->tag()) {
    case bool_expr_e::WordTest: {
      bool_expr::WordTest* node = static_cast<bool_expr::WordTest*>(UP_node);
      s = this->_EvalCompoundWord(node->w);
      return to_bool(s);
    }
      break;
    case bool_expr_e::LogicalNot: {
      bool_expr::LogicalNot* node = static_cast<bool_expr::LogicalNot*>(UP_node);
      b = this->EvalB(node->child);
      return !b;
    }
      break;
    case bool_expr_e::LogicalAnd: {
      bool_expr::LogicalAnd* node = static_cast<bool_expr::LogicalAnd*>(UP_node);
      if (this->EvalB(node->left)) {
        return this->EvalB(node->right);
      }
      else {
        return false;
      }
    }
      break;
    case bool_expr_e::LogicalOr: {
      bool_expr::LogicalOr* node = static_cast<bool_expr::LogicalOr*>(UP_node);
      if (this->EvalB(node->left)) {
        return true;
      }
      else {
        return this->EvalB(node->right);
      }
    }
      break;
    case bool_expr_e::Unary: {
      bool_expr::Unary* node = static_cast<bool_expr::Unary*>(UP_node);
      op_id = node->op_id;
      s = this->_EvalCompoundWord(node->child);
      arg_type = consts::BoolArgType(op_id);
      if (arg_type == bool_arg_type_e::Path) {
        return bool_stat::DoUnaryOp(op_id, s);
      }
      if (arg_type == bool_arg_type_e::Str) {
        if (op_id == Id::BoolUnary_z) {
          return !to_bool(s);
        }
        if (op_id == Id::BoolUnary_n) {
          return to_bool(s);
        }
        assert(0);  // AssertionError
      }
      if (arg_type == bool_arg_type_e::Other) {
        if (op_id == Id::BoolUnary_t) {
          return bool_stat::isatty(s, node->child);
        }
        if (op_id == Id::BoolUnary_o) {
          index = consts::OptionNum(s);
          if (index == 0) {
            return false;
          }
          else {
            return this->exec_opts->opt0_array->at(index);
          }
        }
        if (op_id == Id::BoolUnary_v) {
          return this->_IsDefined(s, Alloc<loc::Word>(node->child));
        }
        e_die(StrFormat("%s isn't implemented", ui::PrettyId(op_id)));
      }
      assert(0);  // AssertionError
    }
      break;
    case bool_expr_e::Binary: {
      bool_expr::Binary* node = static_cast<bool_expr::Binary*>(UP_node);
      op_id = node->op_id;
      eval_flags = 0;
      switch (op_id) {
        case Id::BoolBinary_GlobEqual: 
        case Id::BoolBinary_GlobDEqual: 
        case Id::BoolBinary_GlobNEqual: {
          eval_flags |= word_eval::QUOTE_FNMATCH;
        }
          break;
        case Id::BoolBinary_EqualTilde: {
          eval_flags |= word_eval::QUOTE_ERE;
        }
          break;
      }
      s1 = this->_EvalCompoundWord(node->left);
      s2 = this->_EvalCompoundWord(node->right, eval_flags);
      arg_type = consts::BoolArgType(op_id);
      if (arg_type == bool_arg_type_e::Path) {
        return bool_stat::DoBinaryOp(op_id, s1, s2);
      }
      if (arg_type == bool_arg_type_e::Int) {
        i1 = this->_StringToBigIntOrError(s1, node->left);
        i2 = this->_StringToBigIntOrError(s2, node->right);
        if (op_id == Id::BoolBinary_eq) {
          return mops::Equal(i1, i2);
        }
        if (op_id == Id::BoolBinary_ne) {
          return !mops::Equal(i1, i2);
        }
        if (op_id == Id::BoolBinary_gt) {
          return mops::Greater(i1, i2);
        }
        if (op_id == Id::BoolBinary_ge) {
          return (mops::Greater(i1, i2) or mops::Equal(i1, i2));
        }
        if (op_id == Id::BoolBinary_lt) {
          return mops::Greater(i2, i1);
        }
        if (op_id == Id::BoolBinary_le) {
          return (mops::Greater(i2, i1) or mops::Equal(i1, i2));
        }
        assert(0);  // AssertionError
      }
      if (arg_type == bool_arg_type_e::Str) {
        fnmatch_flags = this->exec_opts->nocasematch() ? FNM_CASEFOLD : 0;
        if ((op_id == Id::BoolBinary_GlobEqual || op_id == Id::BoolBinary_GlobDEqual)) {
          return libc::fnmatch(s2, s1, fnmatch_flags);
        }
        if (op_id == Id::BoolBinary_GlobNEqual) {
          return !libc::fnmatch(s2, s1, fnmatch_flags);
        }
        if ((op_id == Id::BoolBinary_Equal || op_id == Id::BoolBinary_DEqual)) {
          return str_equals(s1, s2);
        }
        if (op_id == Id::BoolBinary_NEqual) {
          return !(str_equals(s1, s2));
        }
        if (op_id == Id::BoolBinary_EqualTilde) {
          regex_flags = this->exec_opts->nocasematch() ? REG_ICASE : 0;
          try {
            indices = libc::regex_search(s2, regex_flags, s1, 0);
          }
          catch (ValueError* e) {
            e_die_status(2, e->message, Alloc<loc::Word>(node->right));
          }
          if (indices != nullptr) {
            this->mem->SetRegexMatch(Alloc<RegexMatch>(s1, indices, eggex_ops::No));
            return true;
          }
          else {
            this->mem->SetRegexMatch(regex_match::No);
            return false;
          }
        }
        if (op_id == Id::Op_Less) {
          return str_cmp(s1, s2) < 0;
        }
        if (op_id == Id::Op_Great) {
          return str_cmp(s1, s2) > 0;
        }
        assert(0);  // AssertionError
      }
    }
      break;
  }
  assert(0);  // AssertionError
}

}  // define namespace sh_expr_eval

namespace split {  // define

using runtime_asdl::scope_e;
using runtime_asdl::span_e;
using runtime_asdl::emit_i;
using runtime_asdl::char_kind_i;
using runtime_asdl::state_i;
using value_asdl::value;
using value_asdl::value_e;
using value_asdl::value_t;
BigStr* DEFAULT_IFS = str1647;

List<BigStr*>* _SpansToParts(BigStr* s, List<Tuple2<runtime_asdl::span_t, int>*>* spans) {
  List<mylib::BufWriter*>* parts = nullptr;
  int start_index;
  bool join_next;
  bool last_span_was_black;
  runtime_asdl::span_t span_type;
  int end_index;
  mylib::BufWriter* buf = nullptr;
  List<BigStr*>* result = nullptr;
  StackRoot _root0(&s);
  StackRoot _root1(&spans);
  StackRoot _root2(&parts);
  StackRoot _root3(&buf);
  StackRoot _root4(&result);

  parts = Alloc<List<mylib::BufWriter*>>();
  start_index = 0;
  join_next = false;
  last_span_was_black = false;
  for (ListIter<Tuple2<runtime_asdl::span_t, int>*> it(spans); !it.Done(); it.Next()) {
    Tuple2<runtime_asdl::span_t, int>* tup0 = it.Value();
    span_type = tup0->at0();
    end_index = tup0->at1();
    if (span_type == span_e::Black) {
      if ((len(parts) and join_next)) {
        parts->at(-1)->write(s->slice(start_index, end_index));
        join_next = false;
      }
      else {
        buf = Alloc<mylib::BufWriter>();
        buf->write(s->slice(start_index, end_index));
        parts->append(buf);
      }
      last_span_was_black = true;
    }
    else {
      if (span_type == span_e::Backslash) {
        if (last_span_was_black) {
          join_next = true;
        }
        last_span_was_black = false;
      }
      else {
        last_span_was_black = false;
      }
    }
    start_index = end_index;
  }
  result = Alloc<List<BigStr*>>();
  for (ListIter<mylib::BufWriter*> it(parts); !it.Done(); it.Next()) {
    mylib::BufWriter* buf = it.Value();
    result->append(buf->getvalue());
  }
  return result;
}

SplitContext::SplitContext(state::Mem* mem) {
  this->mem = mem;
  this->splitters = Alloc<Dict<BigStr*, split::IfsSplitter*>>();
}

split::IfsSplitter* SplitContext::_GetSplitter(BigStr* ifs) {
  value_asdl::value_t* val = nullptr;
  value_asdl::value_t* UP_val = nullptr;
  split::IfsSplitter* sp = nullptr;
  mylib::BufWriter* ifs_whitespace = nullptr;
  mylib::BufWriter* ifs_other = nullptr;
  StackRoot _root0(&ifs);
  StackRoot _root1(&val);
  StackRoot _root2(&UP_val);
  StackRoot _root3(&sp);
  StackRoot _root4(&ifs_whitespace);
  StackRoot _root5(&ifs_other);

  if (ifs == nullptr) {
    val = this->mem->GetValue(str1648, scope_e::Dynamic);
    UP_val = val;
    switch (val->tag()) {
      case value_e::Undef: {
        ifs = DEFAULT_IFS;
      }
        break;
      case value_e::Str: {
        value::Str* val = static_cast<value::Str*>(UP_val);
        ifs = val->s;
      }
        break;
      default: {
        assert(0);  // AssertionError
      }
    }
  }
  sp = this->splitters->get(ifs);
  if (sp == nullptr) {
    ifs_whitespace = Alloc<mylib::BufWriter>();
    ifs_other = Alloc<mylib::BufWriter>();
    for (StrIter it(ifs); !it.Done(); it.Next()) {
      BigStr* c = it.Value();
      StackRoot _for(&c    );
      if (str_contains(str1650, c)) {
        ifs_whitespace->write(c);
      }
      else {
        ifs_other->write(c);
      }
    }
    sp = Alloc<IfsSplitter>(ifs_whitespace->getvalue(), ifs_other->getvalue());
    this->splitters->set(ifs, sp);
  }
  return sp;
}

BigStr* SplitContext::GetJoinChar() {
  value_asdl::value_t* val = nullptr;
  value_asdl::value_t* UP_val = nullptr;
  StackRoot _root0(&val);
  StackRoot _root1(&UP_val);

  val = this->mem->GetValue(str1651, scope_e::Dynamic);
  UP_val = val;
  switch (val->tag()) {
    case value_e::Undef: {
      return str1652;
    }
      break;
    case value_e::Str: {
      value::Str* val = static_cast<value::Str*>(UP_val);
      if (len(val->s)) {
        return val->s->at(0);
      }
      else {
        return str1653;
      }
    }
      break;
    default: {
      assert(0);  // AssertionError
    }
  }
  assert(0);  // AssertionError
}

BigStr* SplitContext::Escape(BigStr* s) {
  split::IfsSplitter* sp = nullptr;
  StackRoot _root0(&s);
  StackRoot _root1(&sp);

  sp = this->_GetSplitter();
  return sp->Escape(s);
}

List<BigStr*>* SplitContext::SplitForWordEval(BigStr* s, BigStr* ifs) {
  split::IfsSplitter* sp = nullptr;
  List<Tuple2<runtime_asdl::span_t, int>*>* spans = nullptr;
  StackRoot _root0(&s);
  StackRoot _root1(&ifs);
  StackRoot _root2(&sp);
  StackRoot _root3(&spans);

  sp = this->_GetSplitter(ifs);
  spans = sp->Split(s, true);
  return _SpansToParts(s, spans);
}

List<Tuple2<runtime_asdl::span_t, int>*>* SplitContext::SplitForRead(BigStr* line, bool allow_escape, bool do_split) {
  BigStr* ifs = nullptr;
  split::IfsSplitter* sp = nullptr;
  StackRoot _root0(&line);
  StackRoot _root1(&ifs);
  StackRoot _root2(&sp);

  ifs = do_split ? nullptr : str1657;
  sp = this->_GetSplitter(ifs);
  return sp->Split(line, allow_escape);
}

_BaseSplitter::_BaseSplitter(BigStr* escape_chars) {
  this->escape_chars = str_concat(escape_chars, str1658);
}

BigStr* _BaseSplitter::Escape(BigStr* s) {
  StackRoot _root0(&s);

  return pyutil::BackslashEscape(s, this->escape_chars);
}

IfsSplitter::IfsSplitter(BigStr* ifs_whitespace, BigStr* ifs_other) : ::split::_BaseSplitter(str_concat(ifs_whitespace, ifs_other)) {
  this->ifs_whitespace = ifs_whitespace;
  this->ifs_other = ifs_other;
}

List<Tuple2<runtime_asdl::span_t, int>*>* IfsSplitter::Split(BigStr* s, bool allow_escape) {
  BigStr* ws_chars = nullptr;
  BigStr* other_chars = nullptr;
  int n;
  List<Tuple2<runtime_asdl::span_t, int>*>* spans = nullptr;
  int i;
  int state;
  int byte;
  int ch;
  int new_state;
  int action;
  StackRoot _root0(&s);
  StackRoot _root1(&ws_chars);
  StackRoot _root2(&other_chars);
  StackRoot _root3(&spans);

  ws_chars = this->ifs_whitespace;
  other_chars = this->ifs_other;
  n = len(s);
  spans = Alloc<List<Tuple2<runtime_asdl::span_t, int>*>>();
  if (n == 0) {
    return spans;
  }
  i = 0;
  while ((i < n and mylib::ByteInSet(mylib::ByteAt(s, i), ws_chars))) {
    i += 1;
  }
  if (i != 0) {
    spans->append((Alloc<Tuple2<runtime_asdl::span_t, int>>(span_e::Delim, i)));
  }
  if (i == n) {
    return spans;
  }
  state = state_i::Start;
  while (state != state_i::Done) {
    if (i < n) {
      byte = mylib::ByteAt(s, i);
      if (mylib::ByteInSet(byte, ws_chars)) {
        ch = char_kind_i::DE_White;
      }
      else {
        if (mylib::ByteInSet(byte, other_chars)) {
          ch = char_kind_i::DE_Gray;
        }
        else {
          if ((allow_escape and mylib::ByteEquals(byte, str1659))) {
            ch = char_kind_i::Backslash;
          }
          else {
            ch = char_kind_i::Black;
          }
        }
      }
    }
    else {
      if (i == n) {
        ch = char_kind_i::Sentinel;
      }
      else {
        assert(0);  // AssertionError
      }
    }
    Tuple2<int, int> tup1 = consts::IfsEdge(state, ch);
    new_state = tup1.at0();
    action = tup1.at1();
    if (new_state == state_i::Invalid) {
      assert(0);  // AssertionError
    }
    if (action == emit_i::Part) {
      spans->append((Alloc<Tuple2<runtime_asdl::span_t, int>>(span_e::Black, i)));
    }
    else {
      if (action == emit_i::Delim) {
        spans->append((Alloc<Tuple2<runtime_asdl::span_t, int>>(span_e::Delim, i)));
      }
      else {
        if (action == emit_i::Empty) {
          spans->append((Alloc<Tuple2<runtime_asdl::span_t, int>>(span_e::Delim, i)));
          spans->append((Alloc<Tuple2<runtime_asdl::span_t, int>>(span_e::Black, i)));
        }
        else {
          if (action == emit_i::Escape) {
            spans->append((Alloc<Tuple2<runtime_asdl::span_t, int>>(span_e::Backslash, i)));
          }
          else {
            if (action == emit_i::Nothing) {
              ;  // pass
            }
            else {
              assert(0);  // AssertionError
            }
          }
        }
      }
    }
    state = new_state;
    i += 1;
  }
  return spans;
}

}  // define namespace split

namespace string_ops {  // define

using id_kind_asdl::Id;
using syntax_asdl::loc;
using syntax_asdl::Token;
using syntax_asdl::suffix_op;
using error::e_die;
using error::e_strict;
int UTF8_ERR_OVERLONG = -1;
int UTF8_ERR_SURROGATE = -2;
int UTF8_ERR_TOO_LARGE = -3;
int UTF8_ERR_BAD_ENCODING = -4;
int UTF8_ERR_TRUNCATED_BYTES = -5;

BigStr* Utf8Error_str(int error) {
  if (error == UTF8_ERR_OVERLONG) {
    return str1662;
  }
  if (error == UTF8_ERR_SURROGATE) {
    return str1663;
  }
  if (error == UTF8_ERR_TOO_LARGE) {
    return str1664;
  }
  if (error == UTF8_ERR_BAD_ENCODING) {
    return str1665;
  }
  if (error == UTF8_ERR_TRUNCATED_BYTES) {
    return str1666;
  }
  assert(0);  // AssertionError
}

int DecodeUtf8Char(BigStr* s, int start) {
  int codepoint_or_error;
  int _bytes_read;
  StackRoot _root0(&s);

  Tuple2<int, int> tup0 = fastfunc::Utf8DecodeOne(s, start);
  codepoint_or_error = tup0.at0();
  _bytes_read = tup0.at1();
  if (codepoint_or_error < 0) {
    throw Alloc<error::Expr>(StrFormat("%s at offset %d in string of %d bytes", Utf8Error_str(codepoint_or_error), start, len(s)), loc::Missing);
  }
  return codepoint_or_error;
}

int NextUtf8Char(BigStr* s, int i) {
  int codepoint_or_error;
  int bytes_read;
  StackRoot _root0(&s);

  Tuple2<int, int> tup1 = fastfunc::Utf8DecodeOne(s, i);
  codepoint_or_error = tup1.at0();
  bytes_read = tup1.at1();
  if (codepoint_or_error < 0) {
    e_strict(StrFormat("%s at offset %d in string of %d bytes", Utf8Error_str(codepoint_or_error), i, len(s)), loc::Missing);
  }
  return (i + bytes_read);
}
BigStr* _INVALID_START = str1669;

int _Utf8CharLen(int starting_byte) {
  if ((starting_byte >> 7) == 0) {
    return 1;
  }
  else {
    if ((starting_byte >> 5) == 6) {
      return 2;
    }
    else {
      if ((starting_byte >> 4) == 14) {
        return 3;
      }
      else {
        if ((starting_byte >> 3) == 30) {
          return 4;
        }
        else {
          e_strict(_INVALID_START, loc::Missing);
        }
      }
    }
  }
}

int PreviousUtf8Char(BigStr* s, int i) {
  int orig_i;
  int byte_as_int;
  int offset;
  StackRoot _root0(&s);

  orig_i = i;
  while (i > 0) {
    i -= 1;
    byte_as_int = mylib::ByteAt(s, i);
    if ((byte_as_int >> 6) != 2) {
      offset = (orig_i - i);
      if (offset != _Utf8CharLen(byte_as_int)) {
        e_strict(_INVALID_START, loc::Missing);
      }
      return i;
    }
  }
  e_strict(_INVALID_START, loc::Missing);
}

int CountUtf8Chars(BigStr* s) {
  int num_chars;
  int num_bytes;
  int i;
  StackRoot _root0(&s);

  num_chars = 0;
  num_bytes = len(s);
  i = 0;
  while (i < num_bytes) {
    i = NextUtf8Char(s, i);
    num_chars += 1;
  }
  return num_chars;
}

int AdvanceUtf8Chars(BigStr* s, int num_chars, int byte_offset) {
  int num_bytes;
  int i;
  StackRoot _root0(&s);

  num_bytes = len(s);
  i = byte_offset;
  for (int _ = 0; _ < num_chars; ++_) {
    if (i >= num_bytes) {
      return i;
    }
    i = NextUtf8Char(s, i);
  }
  return i;
}
GLOBAL_LIST(SPACES, int, 8, {9 COMMA 10 COMMA 11 COMMA 12 COMMA 13 COMMA 32 COMMA 160 COMMA 65279});

bool _IsSpace(int codepoint) {
  return list_contains(SPACES, codepoint);
}

Tuple2<int, int> StartsWithWhitespaceByteRange(BigStr* s) {
  int len_s;
  int i;
  int codepoint;
  int start;
  int end;
  StackRoot _root0(&s);

  len_s = len(s);
  i = 0;
  while (i < len_s) {
    codepoint = DecodeUtf8Char(s, i);
    if (!_IsSpace(codepoint)) {
      break;
    }
    try {
      i = NextUtf8Char(s, i);
    }
    catch (error::Strict*) {
    }
  }
  start = 0;
  end = i;
  return Tuple2<int, int>(start, end);
}

Tuple2<int, int> EndsWithWhitespaceByteRange(BigStr* s) {
  int len_s;
  int i;
  int prev;
  int codepoint;
  int start;
  int end;
  StackRoot _root0(&s);

  len_s = len(s);
  i = len_s;
  while (i > 0) {
    prev = PreviousUtf8Char(s, i);
    codepoint = DecodeUtf8Char(s, prev);
    if (!_IsSpace(codepoint)) {
      break;
    }
    i = prev;
  }
  start = i;
  end = len_s;
  return Tuple2<int, int>(start, end);
}

BigStr* DoUnarySuffixOp(BigStr* s, syntax_asdl::Token* op_tok, BigStr* arg, bool is_extglob) {
  int id_;
  int n;
  int i;
  StackRoot _root0(&s);
  StackRoot _root1(&op_tok);
  StackRoot _root2(&arg);

  id_ = op_tok->id;
  if ((!is_extglob and !glob_::LooksLikeGlob(arg))) {
    arg = glob_::GlobUnescape(arg);
    if ((id_ == Id::VOp1_Pound || id_ == Id::VOp1_DPound)) {
      if ((len(arg) and s->startswith(arg))) {
        return s->slice(len(arg));
      }
      else {
        return s;
      }
    }
    else {
      if ((id_ == Id::VOp1_Percent || id_ == Id::VOp1_DPercent)) {
        if ((len(arg) and s->endswith(arg))) {
          return s->slice(0, -len(arg));
        }
        else {
          return s;
        }
      }
      else {
        if (id_ == Id::VOp1_Comma) {
          if (!(str_equals(arg, str1670))) {
            e_die(StrFormat("%s can't have an argument", ui::PrettyId(id_)), op_tok);
          }
          if (len(s)) {
            return str_concat(s->at(0)->lower(), s->slice(1));
          }
          else {
            return s;
          }
        }
        else {
          if (id_ == Id::VOp1_DComma) {
            if (!(str_equals(arg, str1672))) {
              e_die(StrFormat("%s can't have an argument", ui::PrettyId(id_)), op_tok);
            }
            return s->lower();
          }
          else {
            if (id_ == Id::VOp1_Caret) {
              if (!(str_equals(arg, str1674))) {
                e_die(StrFormat("%s can't have an argument", ui::PrettyId(id_)), op_tok);
              }
              if (len(s)) {
                return str_concat(s->at(0)->upper(), s->slice(1));
              }
              else {
                return s;
              }
            }
            else {
              if (id_ == Id::VOp1_DCaret) {
                if (!(str_equals(arg, str1676))) {
                  e_die(StrFormat("%s can't have an argument", ui::PrettyId(id_)), op_tok);
                }
                return s->upper();
              }
              else {
                assert(0);  // AssertionError
              }
            }
          }
        }
      }
    }
  }
  n = len(s);
  if (id_ == Id::VOp1_Pound) {
    i = 0;
    while (true) {
      if (libc::fnmatch(arg, s->slice(0, i))) {
        return s->slice(i);
      }
      if (i >= n) {
        break;
      }
      i = NextUtf8Char(s, i);
    }
    return s;
  }
  else {
    if (id_ == Id::VOp1_DPound) {
      i = n;
      while (true) {
        if (libc::fnmatch(arg, s->slice(0, i))) {
          return s->slice(i);
        }
        if (i == 0) {
          break;
        }
        i = PreviousUtf8Char(s, i);
      }
      return s;
    }
    else {
      if (id_ == Id::VOp1_Percent) {
        i = n;
        while (true) {
          if (libc::fnmatch(arg, s->slice(i))) {
            return s->slice(0, i);
          }
          if (i == 0) {
            break;
          }
          i = PreviousUtf8Char(s, i);
        }
        return s;
      }
      else {
        if (id_ == Id::VOp1_DPercent) {
          i = 0;
          while (true) {
            if (libc::fnmatch(arg, s->slice(i))) {
              return s->slice(0, i);
            }
            if (i >= n) {
              break;
            }
            i = NextUtf8Char(s, i);
          }
          return s;
        }
        else {
          FAIL(kNotImplemented);  // Python NotImplementedError
        }
      }
    }
  }
}

List<Tuple2<int, int>*>* _AllMatchPositions(BigStr* s, BigStr* regex) {
  List<Tuple2<int, int>*>* matches = nullptr;
  int pos;
  int n;
  Tuple2<int, int>* m = nullptr;
  int start;
  int end;
  StackRoot _root0(&s);
  StackRoot _root1(&regex);
  StackRoot _root2(&matches);
  StackRoot _root3(&m);

  matches = Alloc<List<Tuple2<int, int>*>>();
  pos = 0;
  n = len(s);
  while (pos < n) {
    m = libc::regex_first_group_match(regex, s, pos);
    if (m == nullptr) {
      break;
    }
    matches->append(m);
    Tuple2<int, int>* tup2 = m;
    start = tup2->at0();
    end = tup2->at1();
    pos = end;
  }
  return matches;
}

BigStr* _PatSubAll(BigStr* s, BigStr* regex, BigStr* replace_str) {
  List<BigStr*>* parts = nullptr;
  int prev_end;
  int start;
  int end;
  StackRoot _root0(&s);
  StackRoot _root1(&regex);
  StackRoot _root2(&replace_str);
  StackRoot _root3(&parts);

  parts = Alloc<List<BigStr*>>();
  prev_end = 0;
  for (ListIter<Tuple2<int, int>*> it(_AllMatchPositions(s, regex)); !it.Done(); it.Next()) {
    Tuple2<int, int>* tup3 = it.Value();
    start = tup3->at0();
    end = tup3->at1();
    parts->append(s->slice(prev_end, start));
    parts->append(replace_str);
    prev_end = end;
  }
  parts->append(s->slice(prev_end));
  return str1678->join(parts);
}

GlobReplacer::GlobReplacer(BigStr* regex, BigStr* replace_str, syntax_asdl::Token* slash_tok) {
  this->regex = regex;
  this->replace_str = replace_str;
  this->slash_tok = slash_tok;
}

BigStr* GlobReplacer::Replace(BigStr* s, suffix_op::PatSub* op) {
  BigStr* regex = nullptr;
  BigStr* msg = nullptr;
  Tuple2<int, int>* m = nullptr;
  int start;
  int end;
  StackRoot _root0(&s);
  StackRoot _root1(&op);
  StackRoot _root2(&regex);
  StackRoot _root3(&msg);
  StackRoot _root4(&m);

  regex = StrFormat("(%s)", this->regex);
  if (op->replace_mode == Id::Lit_Slash) {
    if (len(this->regex) == 0) {
      return s;
    }
    try {
      return _PatSubAll(s, regex, this->replace_str);
    }
    catch (RuntimeError* e) {
      msg = e->message;
      e_die(StrFormat("Error matching regex %r: %s", regex, msg), this->slash_tok);
    }
  }
  if (op->replace_mode == Id::Lit_Pound) {
    regex = str_concat(str1682, regex);
  }
  else {
    if (op->replace_mode == Id::Lit_Percent) {
      regex = str_concat(regex, str1683);
    }
  }
  m = libc::regex_first_group_match(regex, s, 0);
  if (m == nullptr) {
    return s;
  }
  Tuple2<int, int>* tup4 = m;
  start = tup4->at0();
  end = tup4->at1();
  return str_concat(str_concat(s->slice(0, start), this->replace_str), s->slice(end));
}

BigStr* ShellQuoteB(BigStr* s) {
  StackRoot _root0(&s);

  s = s->replace(str1684, str1685)->replace(str1686, str1687);
  return pyutil::BackslashEscape(s, str1688);
}

}  // define namespace string_ops

namespace tdop {  // define

using id_kind_asdl::Id;
using id_kind_asdl::Id_t;
using syntax_asdl::loc;
using syntax_asdl::arith_expr;
using syntax_asdl::arith_expr_e;
using syntax_asdl::arith_expr_t;
using syntax_asdl::word_e;
using syntax_asdl::word_t;
using syntax_asdl::CompoundWord;
using syntax_asdl::Token;
using error::p_die;

bool IsIndexable(syntax_asdl::arith_expr_t* node) {
  StackRoot _root0(&node);

  switch (node->tag()) {
    case arith_expr_e::VarSub: 
    case arith_expr_e::Word: {
      return true;
    }
      break;
  }
  return false;
}

void CheckLhsExpr(syntax_asdl::arith_expr_t* node, syntax_asdl::word_t* blame_word) {
  syntax_asdl::arith_expr_t* UP_node = nullptr;
  StackRoot _root0(&node);
  StackRoot _root1(&blame_word);
  StackRoot _root2(&UP_node);

  UP_node = node;
  if (node->tag() == arith_expr_e::Binary) {
    arith_expr::Binary* node = static_cast<arith_expr::Binary*>(UP_node);
    if ((node->op->id == Id::Arith_LBracket and IsIndexable(node->left))) {
      return ;
    }
  }
  if (IsIndexable(node)) {
    return ;
  }
  p_die(str1689, Alloc<loc::Word>(blame_word));
}

syntax_asdl::arith_expr_t* NullError(tdop::TdopParser* p, syntax_asdl::word_t* t, int bp) {
  StackRoot _root0(&p);
  StackRoot _root1(&t);

  p_die(str1690, Alloc<loc::Word>(t));
  return nullptr;
}

syntax_asdl::arith_expr_t* NullConstant(tdop::TdopParser* p, syntax_asdl::word_t* w, int bp) {
  syntax_asdl::Token* name_tok = nullptr;
  StackRoot _root0(&p);
  StackRoot _root1(&w);
  StackRoot _root2(&name_tok);

  name_tok = word_::LooksLikeArithVar(w);
  if (name_tok) {
    return name_tok;
  }
  return static_cast<CompoundWord*>(w);
}

syntax_asdl::arith_expr_t* NullParen(tdop::TdopParser* p, syntax_asdl::word_t* t, int bp) {
  syntax_asdl::arith_expr_t* r = nullptr;
  StackRoot _root0(&p);
  StackRoot _root1(&t);
  StackRoot _root2(&r);

  r = p->ParseUntil(bp);
  p->Eat(Id::Arith_RParen);
  return r;
}

syntax_asdl::arith_expr_t* NullPrefixOp(tdop::TdopParser* p, syntax_asdl::word_t* w, int bp) {
  syntax_asdl::arith_expr_t* right = nullptr;
  StackRoot _root0(&p);
  StackRoot _root1(&w);
  StackRoot _root2(&right);

  right = p->ParseUntil(bp);
  return Alloc<arith_expr::Unary>(word_::ArithId(w), right);
}

syntax_asdl::arith_expr_t* LeftError(tdop::TdopParser* p, syntax_asdl::word_t* t, syntax_asdl::arith_expr_t* left, int rbp) {
  StackRoot _root0(&p);
  StackRoot _root1(&t);
  StackRoot _root2(&left);

  p_die(str1691, Alloc<loc::Word>(t));
  return nullptr;
}

syntax_asdl::arith_expr_t* LeftBinaryOp(tdop::TdopParser* p, syntax_asdl::word_t* w, syntax_asdl::arith_expr_t* left, int rbp) {
  Token* tok = nullptr;
  StackRoot _root0(&p);
  StackRoot _root1(&w);
  StackRoot _root2(&left);
  StackRoot _root3(&tok);

  tok = static_cast<Token*>(w);
  return Alloc<arith_expr::Binary>(tok, left, p->ParseUntil(rbp));
}

syntax_asdl::arith_expr_t* LeftAssign(tdop::TdopParser* p, syntax_asdl::word_t* w, syntax_asdl::arith_expr_t* left, int rbp) {
  StackRoot _root0(&p);
  StackRoot _root1(&w);
  StackRoot _root2(&left);

  CheckLhsExpr(left, w);
  return Alloc<arith_expr::BinaryAssign>(word_::ArithId(w), left, p->ParseUntil(rbp));
}

TdopParser::TdopParser(tdop::ParserSpec* spec, word_parse::WordParser* w_parser, optview::Parse* parse_opts) {
  this->spec = spec;
  this->w_parser = w_parser;
  this->parse_opts = parse_opts;
  this->cur_word = nullptr;
  this->op_id = Id::Undefined_Tok;
}

int TdopParser::CurrentId() {
  return word_::ArithId(this->cur_word);
}

bool TdopParser::AtToken(int token_type) {
  return this->op_id == token_type;
}

void TdopParser::Eat(int token_type) {
  if (!this->AtToken(token_type)) {
    p_die(StrFormat("Parser expected %s, got %s", ui::PrettyId(token_type), ui::PrettyId(this->op_id)), Alloc<loc::Word>(this->cur_word));
  }
  this->Next();
}

bool TdopParser::Next() {
  this->cur_word = this->w_parser->ReadArithWord();
  this->op_id = word_::ArithId(this->cur_word);
  return true;
}

syntax_asdl::arith_expr_t* TdopParser::ParseUntil(int rbp) {
  syntax_asdl::word_t* t = nullptr;
  tdop::NullInfo* null_info = nullptr;
  syntax_asdl::arith_expr_t* node = nullptr;
  tdop::LeftInfo* left_info = nullptr;
  StackRoot _root0(&t);
  StackRoot _root1(&null_info);
  StackRoot _root2(&node);
  StackRoot _root3(&left_info);

  if ((this->op_id == Id::Eof_Real || this->op_id == Id::Eof_RParen || this->op_id == Id::Eof_Backtick)) {
    p_die(str1693, Alloc<loc::Word>(this->cur_word));
  }
  t = this->cur_word;
  null_info = this->spec->LookupNud(this->op_id);
  this->Next();
  node = null_info->nud(this, t, null_info->bp);
  while (true) {
    t = this->cur_word;
    left_info = this->spec->LookupLed(this->op_id);
    if (rbp >= left_info->lbp) {
      break;
    }
    this->Next();
    node = left_info->led(this, t, node, left_info->rbp);
  }
  return node;
}

syntax_asdl::arith_expr_t* TdopParser::Parse() {
  this->Next();
  if (!this->parse_opts->parse_sh_arith()) {
    p_die(str1694, Alloc<loc::Word>(this->cur_word));
  }
  return this->ParseUntil(0);
}

}  // define namespace tdop

namespace word_ {  // define

using id_kind_asdl::Id;
using id_kind_asdl::Kind;
using id_kind_asdl::Id_t;
using id_kind_asdl::Kind_t;
using syntax_asdl::Token;
using syntax_asdl::CompoundWord;
using syntax_asdl::DoubleQuoted;
using syntax_asdl::SingleQuoted;
using syntax_asdl::word;
using syntax_asdl::word_e;
using syntax_asdl::word_t;
using syntax_asdl::word_str;
using syntax_asdl::word_part;
using syntax_asdl::word_part_t;
using syntax_asdl::word_part_e;
using syntax_asdl::AssocPair;

int LiteralId(syntax_asdl::word_part_t* p) {
  syntax_asdl::word_part_t* UP_part = nullptr;
  StackRoot _root0(&p);
  StackRoot _root1(&UP_part);

  UP_part = p;
  if (p->tag() == word_part_e::Literal) {
    return static_cast<Token*>(UP_part)->id;
  }
  else {
    return Id::Undefined_Tok;
  }
}

Tuple3<bool, BigStr*, bool> _EvalWordPart(syntax_asdl::word_part_t* part) {
  syntax_asdl::word_part_t* UP_part = nullptr;
  BigStr* s = nullptr;
  List<BigStr*>* strs = nullptr;
  bool ok;
  StackRoot _root0(&part);
  StackRoot _root1(&UP_part);
  StackRoot _root2(&s);
  StackRoot _root3(&strs);

  UP_part = part;
  switch (part->tag()) {
    case word_part_e::Literal: {
      Token* tok = static_cast<Token*>(UP_part);
      return Tuple3<bool, BigStr*, bool>(true, lexer::TokenVal(tok), false);
    }
      break;
    case word_part_e::EscapedLiteral: {
      word_part::EscapedLiteral* part = static_cast<word_part::EscapedLiteral*>(UP_part);
      s = lexer::TokenSliceLeft(part->token, 1);
      return Tuple3<bool, BigStr*, bool>(true, s, true);
    }
      break;
    case word_part_e::SingleQuoted: {
      SingleQuoted* part = static_cast<SingleQuoted*>(UP_part);
      return Tuple3<bool, BigStr*, bool>(true, part->sval, true);
    }
      break;
    case word_part_e::DoubleQuoted: {
      DoubleQuoted* part = static_cast<DoubleQuoted*>(UP_part);
      strs = Alloc<List<BigStr*>>();
      for (ListIter<syntax_asdl::word_part_t*> it(part->parts); !it.Done(); it.Next()) {
        syntax_asdl::word_part_t* p = it.Value();
        StackRoot _for(&p      );
        Tuple3<bool, BigStr*, bool> tup0 = _EvalWordPart(p);
        ok = tup0.at0();
        s = tup0.at1();
        if (!ok) {
          return Tuple3<bool, BigStr*, bool>(false, str1695, true);
        }
        strs->append(s);
      }
      return Tuple3<bool, BigStr*, bool>(true, str1696->join(strs), true);
    }
      break;
    case word_part_e::ShArrayLiteral: 
    case word_part_e::BashAssocLiteral: 
    case word_part_e::ZshVarSub: 
    case word_part_e::CommandSub: 
    case word_part_e::SimpleVarSub: 
    case word_part_e::BracedVarSub: 
    case word_part_e::TildeSub: 
    case word_part_e::ArithSub: 
    case word_part_e::ExtGlob: 
    case word_part_e::Splice: 
    case word_part_e::ExprSub: {
      return Tuple3<bool, BigStr*, bool>(false, str1697, false);
    }
      break;
    default: {
      assert(0);  // AssertionError
    }
  }
}

BigStr* FastStrEval(syntax_asdl::CompoundWord* w) {
  syntax_asdl::word_part_t* part0 = nullptr;
  syntax_asdl::word_part_t* UP_part0 = nullptr;
  StackRoot _root0(&w);
  StackRoot _root1(&part0);
  StackRoot _root2(&UP_part0);

  if (len(w->parts) != 1) {
    return nullptr;
  }
  part0 = w->parts->at(0);
  UP_part0 = part0;
  switch (part0->tag()) {
    case word_part_e::Literal: {
      Token* part0 = static_cast<Token*>(UP_part0);
      if ((part0->id == Id::Lit_Chars || part0->id == Id::Lit_LBracket || part0->id == Id::Lit_RBracket)) {
        return lexer::LazyStr(part0);
      }
      else {
        return nullptr;
      }
    }
      break;
    case word_part_e::SingleQuoted: {
      SingleQuoted* part0 = static_cast<SingleQuoted*>(UP_part0);
      return part0->sval;
    }
      break;
    default: {
      return nullptr;
    }
  }
}

Tuple3<bool, BigStr*, bool> StaticEval(syntax_asdl::word_t* UP_w) {
  bool quoted;
  List<BigStr*>* strs = nullptr;
  bool ok;
  BigStr* s = nullptr;
  bool q;
  StackRoot _root0(&UP_w);
  StackRoot _root1(&strs);
  StackRoot _root2(&s);

  quoted = false;
  if (UP_w->tag() != word_e::Compound) {
    return Tuple3<bool, BigStr*, bool>(false, str1698, quoted);
  }
  CompoundWord* w = static_cast<CompoundWord*>(UP_w);
  strs = Alloc<List<BigStr*>>();
  for (ListIter<syntax_asdl::word_part_t*> it(w->parts); !it.Done(); it.Next()) {
    syntax_asdl::word_part_t* part = it.Value();
    StackRoot _for(&part  );
    Tuple3<bool, BigStr*, bool> tup1 = _EvalWordPart(part);
    ok = tup1.at0();
    s = tup1.at1();
    q = tup1.at2();
    if (!ok) {
      return Tuple3<bool, BigStr*, bool>(false, str1699, quoted);
    }
    if (q) {
      quoted = true;
    }
    strs->append(s);
  }
  return Tuple3<bool, BigStr*, bool>(true, str1700->join(strs), quoted);
}

syntax_asdl::CompoundWord* TildeDetect(syntax_asdl::word_t* UP_w) {
  StackRoot _root0(&UP_w);

  if (UP_w->tag() != word_e::Compound) {
    return nullptr;
  }
  CompoundWord* w = static_cast<CompoundWord*>(UP_w);
  return TildeDetect2(w);
}

syntax_asdl::CompoundWord* TildeDetect2(syntax_asdl::CompoundWord* w) {
  syntax_asdl::word_part_t* part0 = nullptr;
  int id0;
  Token* tok0 = nullptr;
  List<syntax_asdl::word_part_t*>* new_parts = nullptr;
  int id1;
  Token* tok1 = nullptr;
  int id2;
  StackRoot _root0(&w);
  StackRoot _root1(&part0);
  StackRoot _root2(&tok0);
  StackRoot _root3(&new_parts);
  StackRoot _root4(&tok1);

  if (len(w->parts) == 0) {
    return nullptr;
  }
  part0 = w->parts->at(0);
  id0 = LiteralId(part0);
  if (id0 != Id::Lit_Tilde) {
    return nullptr;
  }
  tok0 = static_cast<Token*>(part0);
  new_parts = Alloc<List<syntax_asdl::word_part_t*>>();
  if (len(w->parts) == 1) {
    new_parts->append(Alloc<word_part::TildeSub>(tok0, nullptr, nullptr));
    return Alloc<CompoundWord>(new_parts);
  }
  id1 = LiteralId(w->parts->at(1));
  if (id1 == Id::Lit_Slash) {
    new_parts->append(Alloc<word_part::TildeSub>(tok0, nullptr, nullptr));
    new_parts->extend(w->parts->slice(1));
    return Alloc<CompoundWord>(new_parts);
  }
  if (id1 != Id::Lit_Chars) {
    return nullptr;
  }
  tok1 = static_cast<Token*>(w->parts->at(1));
  if (len(w->parts) == 2) {
    new_parts->append(Alloc<word_part::TildeSub>(tok0, tok1, lexer::TokenVal(tok1)));
    return Alloc<CompoundWord>(new_parts);
  }
  id2 = LiteralId(w->parts->at(2));
  if (id2 != Id::Lit_Slash) {
    return nullptr;
  }
  new_parts->append(Alloc<word_part::TildeSub>(tok0, tok1, lexer::TokenVal(tok1)));
  new_parts->extend(w->parts->slice(2));
  return Alloc<CompoundWord>(new_parts);
}

void TildeDetectAssign(syntax_asdl::CompoundWord* w) {
  List<syntax_asdl::word_part_t*>* parts = nullptr;
  bool has_tilde;
  List<syntax_asdl::word_part_t*>* new_parts = nullptr;
  bool tilde_could_be_next;
  int i;
  int n;
  syntax_asdl::word_part_t* part0 = nullptr;
  syntax_asdl::word_part_t* part1 = nullptr;
  syntax_asdl::word_part_t* part2 = nullptr;
  Token* tok0 = nullptr;
  int id1;
  Token* tok1 = nullptr;
  int id2;
  StackRoot _root0(&w);
  StackRoot _root1(&parts);
  StackRoot _root2(&new_parts);
  StackRoot _root3(&part0);
  StackRoot _root4(&part1);
  StackRoot _root5(&part2);
  StackRoot _root6(&tok0);
  StackRoot _root7(&tok1);

  parts = w->parts;
  has_tilde = false;
  for (ListIter<syntax_asdl::word_part_t*> it(parts); !it.Done(); it.Next()) {
    syntax_asdl::word_part_t* part = it.Value();
    StackRoot _for(&part  );
    if (LiteralId(part) == Id::Lit_Tilde) {
      has_tilde = true;
      break;
    }
  }
  if (!has_tilde) {
    return ;
  }
  parts->append(nullptr);
  parts->append(nullptr);
  new_parts = Alloc<List<syntax_asdl::word_part_t*>>();
  tilde_could_be_next = true;
  i = 0;
  n = len(parts);
  while (i < n) {
    part0 = parts->at(i);
    if (part0 == nullptr) {
      break;
    }
    if ((tilde_could_be_next and LiteralId(part0) == Id::Lit_Tilde)) {
      part1 = parts->at((i + 1));
      part2 = parts->at((i + 2));
      tok0 = static_cast<Token*>(part0);
      if (part1 == nullptr) {
        new_parts->append(Alloc<word_part::TildeSub>(tok0, nullptr, nullptr));
        break;
      }
      id1 = LiteralId(part1);
      if ((id1 == Id::Lit_Slash || id1 == Id::Lit_Colon)) {
        new_parts->append(Alloc<word_part::TildeSub>(tok0, nullptr, nullptr));
        new_parts->append(part1);
        i += 2;
        continue;
      }
      if (id1 != Id::Lit_Chars) {
        new_parts->append(part0);
        new_parts->append(part1);
        i += 2;
        continue;
      }
      tok1 = static_cast<Token*>(part1);
      if (part2 == nullptr) {
        new_parts->append(Alloc<word_part::TildeSub>(tok0, tok1, lexer::TokenVal(tok1)));
        break;
      }
      id2 = LiteralId(part2);
      if ((id2 != Id::Lit_Slash && id2 != Id::Lit_Colon)) {
        new_parts->append(part0);
        new_parts->append(part1);
        new_parts->append(part2);
        i += 3;
        continue;
      }
      new_parts->append(Alloc<word_part::TildeSub>(tok0, tok1, lexer::TokenVal(tok1)));
      new_parts->append(part2);
      i += 3;
      tilde_could_be_next = id2 == Id::Lit_Colon;
    }
    else {
      new_parts->append(part0);
      i += 1;
      tilde_could_be_next = LiteralId(part0) == Id::Lit_Colon;
    }
  }
  parts->pop();
  parts->pop();
  w->parts = new_parts;
}

List<syntax_asdl::word_t*>* TildeDetectAll(List<syntax_asdl::word_t*>* words) {
  List<syntax_asdl::word_t*>* out = nullptr;
  syntax_asdl::CompoundWord* t = nullptr;
  StackRoot _root0(&words);
  StackRoot _root1(&out);
  StackRoot _root2(&t);

  out = Alloc<List<syntax_asdl::word_t*>>();
  for (ListIter<syntax_asdl::word_t*> it(words); !it.Done(); it.Next()) {
    syntax_asdl::word_t* w = it.Value();
    StackRoot _for(&w  );
    t = TildeDetect(w);
    if (t) {
      out->append(t);
    }
    else {
      out->append(w);
    }
  }
  return out;
}

bool HasArrayPart(syntax_asdl::CompoundWord* w) {
  StackRoot _root0(&w);

  for (ListIter<syntax_asdl::word_part_t*> it(w->parts); !it.Done(); it.Next()) {
    syntax_asdl::word_part_t* part = it.Value();
    StackRoot _for(&part  );
    if (part->tag() == word_part_e::ShArrayLiteral) {
      return true;
    }
  }
  return false;
}

BigStr* ShFunctionName(syntax_asdl::CompoundWord* w) {
  bool ok;
  BigStr* s = nullptr;
  bool quoted;
  StackRoot _root0(&w);
  StackRoot _root1(&s);

  Tuple3<bool, BigStr*, bool> tup2 = StaticEval(w);
  ok = tup2.at0();
  s = tup2.at1();
  quoted = tup2.at2();
  if ((!ok or quoted)) {
    return str1701;
  }
  return s;
}

syntax_asdl::Token* LooksLikeArithVar(syntax_asdl::word_t* UP_w) {
  syntax_asdl::word_part_t* UP_part0 = nullptr;
  StackRoot _root0(&UP_w);
  StackRoot _root1(&UP_part0);

  if (UP_w->tag() != word_e::Compound) {
    return nullptr;
  }
  CompoundWord* w = static_cast<CompoundWord*>(UP_w);
  if (len(w->parts) != 1) {
    return nullptr;
  }
  UP_part0 = w->parts->at(0);
  if (LiteralId(UP_part0) != Id::Lit_ArithVarLike) {
    return nullptr;
  }
  return static_cast<Token*>(UP_part0);
}

bool IsVarLike(syntax_asdl::CompoundWord* w) {
  StackRoot _root0(&w);

  if (len(w->parts) == 0) {
    return false;
  }
  return LiteralId(w->parts->at(0)) == Id::Lit_VarLike;
}

Tuple3<syntax_asdl::Token*, syntax_asdl::Token*, int> DetectShAssignment(syntax_asdl::CompoundWord* w) {
  syntax_asdl::Token* no_token = nullptr;
  int n;
  syntax_asdl::word_part_t* UP_part0 = nullptr;
  int id0;
  syntax_asdl::word_part_t* UP_part = nullptr;
  StackRoot _root0(&w);
  StackRoot _root1(&no_token);
  StackRoot _root2(&UP_part0);
  StackRoot _root3(&UP_part);

  no_token = nullptr;
  n = len(w->parts);
  if (n == 0) {
    return Tuple3<syntax_asdl::Token*, syntax_asdl::Token*, int>(no_token, no_token, 0);
  }
  UP_part0 = w->parts->at(0);
  id0 = LiteralId(UP_part0);
  if (id0 == Id::Lit_VarLike) {
    Token* tok = static_cast<Token*>(UP_part0);
    return Tuple3<syntax_asdl::Token*, syntax_asdl::Token*, int>(tok, no_token, 1);
  }
  if (id0 == Id::Lit_ArrayLhsOpen) {
    Token* tok0 = static_cast<Token*>(UP_part0);
    if (n < 2) {
      return Tuple3<syntax_asdl::Token*, syntax_asdl::Token*, int>(no_token, no_token, 0);
    }
    for (int i = 1; i < n; ++i) {
      UP_part = w->parts->at(i);
      if (LiteralId(UP_part) == Id::Lit_ArrayLhsClose) {
        Token* tok_close = static_cast<Token*>(UP_part);
        return Tuple3<syntax_asdl::Token*, syntax_asdl::Token*, int>(tok0, tok_close, (i + 1));
      }
    }
  }
  return Tuple3<syntax_asdl::Token*, syntax_asdl::Token*, int>(no_token, no_token, 0);
}

syntax_asdl::AssocPair* DetectAssocPair(syntax_asdl::CompoundWord* w) {
  List<syntax_asdl::word_part_t*>* parts = nullptr;
  int n;
  int id_;
  syntax_asdl::CompoundWord* key = nullptr;
  syntax_asdl::CompoundWord* value = nullptr;
  StackRoot _root0(&w);
  StackRoot _root1(&parts);
  StackRoot _root2(&key);
  StackRoot _root3(&value);

  parts = w->parts;
  if (LiteralId(parts->at(0)) != Id::Lit_LBracket) {
    return nullptr;
  }
  n = len(parts);
  for (int i = 0; i < n; ++i) {
    id_ = LiteralId(parts->at(i));
    if (id_ == Id::Lit_ArrayLhsClose) {
      key = Alloc<CompoundWord>(parts->slice(1, i));
      value = Alloc<CompoundWord>(parts->slice((i + 1)));
      return Alloc<AssocPair>(key, value);
    }
  }
  return nullptr;
}

Tuple2<id_kind_asdl::Kind_t, syntax_asdl::Token*> IsControlFlow(syntax_asdl::CompoundWord* w) {
  syntax_asdl::Token* no_token = nullptr;
  syntax_asdl::word_part_t* UP_part0 = nullptr;
  int token_type;
  id_kind_asdl::Kind_t token_kind;
  StackRoot _root0(&w);
  StackRoot _root1(&no_token);
  StackRoot _root2(&UP_part0);

  no_token = nullptr;
  if (len(w->parts) != 1) {
    return Tuple2<id_kind_asdl::Kind_t, syntax_asdl::Token*>(Kind::Undefined, no_token);
  }
  UP_part0 = w->parts->at(0);
  token_type = LiteralId(UP_part0);
  if (token_type == Id::Undefined_Tok) {
    return Tuple2<id_kind_asdl::Kind_t, syntax_asdl::Token*>(Kind::Undefined, no_token);
  }
  token_kind = consts::GetKind(token_type);
  if (token_kind == Kind::ControlFlow) {
    return Tuple2<id_kind_asdl::Kind_t, syntax_asdl::Token*>(token_kind, static_cast<Token*>(UP_part0));
  }
  return Tuple2<id_kind_asdl::Kind_t, syntax_asdl::Token*>(Kind::Undefined, no_token);
}

syntax_asdl::Token* LiteralToken(syntax_asdl::word_t* UP_w) {
  syntax_asdl::word_part_t* part0 = nullptr;
  StackRoot _root0(&UP_w);
  StackRoot _root1(&part0);

  CompoundWord* w = static_cast<CompoundWord*>(UP_w);
  if (len(w->parts) != 1) {
    return nullptr;
  }
  part0 = w->parts->at(0);
  if (part0->tag() == word_part_e::Literal) {
    return static_cast<Token*>(part0);
  }
  return nullptr;
}

syntax_asdl::Token* BraceToken(syntax_asdl::word_t* UP_w) {
  StackRoot _root0(&UP_w);

  switch (UP_w->tag()) {
    case word_e::Operator: {
      Token* tok = static_cast<Token*>(UP_w);
      return tok;
    }
      break;
    case word_e::Compound: {
      CompoundWord* w = static_cast<CompoundWord*>(UP_w);
      return LiteralToken(w);
    }
      break;
    default: {
      assert(0);  // AssertionError
    }
  }
}

syntax_asdl::Token* AsKeywordToken(syntax_asdl::word_t* UP_w) {
  syntax_asdl::word_part_t* part = nullptr;
  Token* tok = nullptr;
  StackRoot _root0(&UP_w);
  StackRoot _root1(&part);
  StackRoot _root2(&tok);

  CompoundWord* w = static_cast<CompoundWord*>(UP_w);
  part = w->parts->at(0);
  tok = static_cast<Token*>(part);
  return tok;
}

syntax_asdl::Token* AsOperatorToken(syntax_asdl::word_t* word) {
  StackRoot _root0(&word);

  return static_cast<Token*>(word);
}

int ArithId(syntax_asdl::word_t* w) {
  Token* tok = nullptr;
  StackRoot _root0(&w);
  StackRoot _root1(&tok);

  if (w->tag() == word_e::Operator) {
    tok = static_cast<Token*>(w);
    return tok->id;
  }
  return Id::Word_Compound;
}

int BoolId(syntax_asdl::word_t* w) {
  syntax_asdl::word_t* UP_w = nullptr;
  int token_type;
  id_kind_asdl::Kind_t token_kind;
  StackRoot _root0(&w);
  StackRoot _root1(&UP_w);

  UP_w = w;
  switch (w->tag()) {
    case word_e::String: {
      word::String* w = static_cast<word::String*>(UP_w);
      return w->id;
    }
      break;
    case word_e::Operator: {
      Token* tok = static_cast<Token*>(UP_w);
      return tok->id;
    }
      break;
    case word_e::Compound: {
      CompoundWord* w = static_cast<CompoundWord*>(UP_w);
      if (len(w->parts) != 1) {
        return Id::Word_Compound;
      }
      token_type = LiteralId(w->parts->at(0));
      if (token_type == Id::Undefined_Tok) {
        return Id::Word_Compound;
      }
      if ((token_type == Id::KW_Bang || token_type == Id::Lit_DRightBracket)) {
        return token_type;
      }
      token_kind = consts::GetKind(token_type);
      if ((token_kind == Kind::BoolUnary || token_kind == Kind::BoolBinary)) {
        return token_type;
      }
      return Id::Word_Compound;
    }
      break;
    default: {
      assert(0);  // AssertionError
    }
  }
}

int CommandId(syntax_asdl::word_t* w) {
  syntax_asdl::word_t* UP_w = nullptr;
  int token_type;
  id_kind_asdl::Kind_t token_kind;
  StackRoot _root0(&w);
  StackRoot _root1(&UP_w);

  UP_w = w;
  switch (w->tag()) {
    case word_e::Operator: {
      Token* tok = static_cast<Token*>(UP_w);
      return tok->id;
    }
      break;
    case word_e::Compound: {
      CompoundWord* w = static_cast<CompoundWord*>(UP_w);
      if (len(w->parts) != 1) {
        return Id::Word_Compound;
      }
      token_type = LiteralId(w->parts->at(0));
      if (token_type == Id::Undefined_Tok) {
        return Id::Word_Compound;
      }
      if ((token_type == Id::Lit_LBrace || token_type == Id::Lit_RBrace || token_type == Id::Lit_Equals || token_type == Id::Lit_TDot)) {
        return token_type;
      }
      token_kind = consts::GetKind(token_type);
      if (token_kind == Kind::KW) {
        return token_type;
      }
      return Id::Word_Compound;
    }
      break;
    default: {
      assert(0);  // AssertionError
    }
  }
}

id_kind_asdl::Kind_t CommandKind(syntax_asdl::word_t* w) {
  Token* tok = nullptr;
  StackRoot _root0(&w);
  StackRoot _root1(&tok);

  if (w->tag() == word_e::Operator) {
    tok = static_cast<Token*>(w);
    return consts::GetKind(tok->id);
  }
  return Kind::Word;
}

bool IsVarSub(syntax_asdl::word_t* w) {
  StackRoot _root0(&w);

  return false;
}

syntax_asdl::CompoundWord* ErrorWord(BigStr* error_str) {
  syntax_asdl::Token* t = nullptr;
  StackRoot _root0(&error_str);
  StackRoot _root1(&t);

  t = lexer::DummyToken(Id::Lit_Chars, error_str);
  return Alloc<CompoundWord>(NewList<syntax_asdl::word_part_t*>(std::initializer_list<syntax_asdl::word_part_t*>{t}));
}

BigStr* Pretty(syntax_asdl::word_t* w) {
  syntax_asdl::word_t* UP_w = nullptr;
  StackRoot _root0(&w);
  StackRoot _root1(&UP_w);

  UP_w = w;
  if (w->tag() == word_e::String) {
    word::String* w = static_cast<word::String*>(UP_w);
    if (w->id == Id::Eof_Real) {
      return str1702;
    }
    else {
      return repr(w->s);
    }
  }
  else {
    return word_str(w->tag());
  }
}

ctx_EmitDocToken::ctx_EmitDocToken(word_parse::WordParser* w_parser) {
  gHeap.PushRoot(reinterpret_cast<RawObject**>(&(this->w_parser)));
  w_parser->EmitDocToken(true);
  this->w_parser = w_parser;
}

ctx_EmitDocToken::~ctx_EmitDocToken() {
  this->w_parser->EmitDocToken(false);
  gHeap.PopRoot();
}

ctx_Multiline::ctx_Multiline(word_parse::WordParser* w_parser) {
  gHeap.PushRoot(reinterpret_cast<RawObject**>(&(this->w_parser)));
  w_parser->Multiline(true);
  this->w_parser = w_parser;
}

ctx_Multiline::~ctx_Multiline() {
  this->w_parser->Multiline(false);
  gHeap.PopRoot();
}

}  // define namespace word_

namespace word_compile {  // define

using id_kind_asdl::Id;
using id_kind_asdl::Id_t;
using id_kind_asdl::Id_str;
using syntax_asdl::Token;
using syntax_asdl::CharCode;
using syntax_asdl::word_part_e;
using syntax_asdl::word_part_t;
using error::p_die;

syntax_asdl::CharCode* EvalCharLiteralForRegex(syntax_asdl::Token* tok) {
  int id_;
  BigStr* value = nullptr;
  BigStr* s = nullptr;
  int i;
  BigStr* one_char_str = nullptr;
  StackRoot _root0(&tok);
  StackRoot _root1(&value);
  StackRoot _root2(&s);
  StackRoot _root3(&one_char_str);

  id_ = tok->id;
  value = lexer::TokenVal(tok);
  switch (id_) {
    case Id::Char_UBraced: {
      s = lexer::TokenSlice(tok, 3, -1);
      i = to_int(s, 16);
      return Alloc<CharCode>(tok, i, true);
    }
      break;
    case Id::Char_OneChar: {
      one_char_str = consts::LookupCharC(value->at(1));
      return Alloc<CharCode>(tok, ord(one_char_str), false);
    }
      break;
    case Id::Char_Hex: {
      s = lexer::TokenSliceLeft(tok, 2);
      i = to_int(s, 16);
      return Alloc<CharCode>(tok, i, false);
    }
      break;
    case Id::Lit_Chars: 
    case Id::Expr_Name: 
    case Id::Expr_DecInt: {
      return Alloc<CharCode>(tok, ord(value->at(0)), false);
    }
      break;
    default: {
      assert(0);  // AssertionError
    }
  }
}

BigStr* EvalCStringToken(int id_, BigStr* value) {
  int code_point;
  BigStr* c = nullptr;
  BigStr* s = nullptr;
  int i;
  StackRoot _root0(&value);
  StackRoot _root1(&c);
  StackRoot _root2(&s);

  code_point = -1;
  if ((id_ == Id::Lit_Chars || id_ == Id::Lit_CharsWithoutPrefix || id_ == Id::Unknown_Backslash)) {
    return value;
  }
  else {
    if (id_ == Id::Right_SingleQuote) {
      return value;
    }
    else {
      if (id_ == Id::Char_OneChar) {
        c = value->at(1);
        return consts::LookupCharC(c);
      }
      else {
        if (id_ == Id::Char_Stop) {
          return nullptr;
        }
        else {
          if ((id_ == Id::Char_Octal3 || id_ == Id::Char_Octal4)) {
            if (id_ == Id::Char_Octal3) {
              s = value->slice(1);
            }
            else {
              s = value->slice(2);
            }
            i = to_int(s, 8);
            if (i >= 256) {
              i = (i % 256);
            }
            return chr(i);
          }
          else {
            if ((id_ == Id::Char_Hex || id_ == Id::Char_YHex)) {
              s = value->slice(2);
              i = to_int(s, 16);
              return chr(i);
            }
            else {
              if ((id_ == Id::Char_Unicode4 || id_ == Id::Char_Unicode8)) {
                s = value->slice(2);
                code_point = to_int(s, 16);
                return j8::Utf8Encode(code_point);
              }
              else {
                if (id_ == Id::Char_UBraced) {
                  s = value->slice(3, -1);
                  code_point = to_int(s, 16);
                  return j8::Utf8Encode(code_point);
                }
                else {
                  assert(0);  // AssertionError
                }
              }
            }
          }
        }
      }
    }
  }
}

BigStr* EvalSingleQuoted(int id_, List<syntax_asdl::Token*>* tokens) {
  List<BigStr*>* strs = nullptr;
  BigStr* s = nullptr;
  int code_point;
  StackRoot _root0(&tokens);
  StackRoot _root1(&strs);
  StackRoot _root2(&s);

  if ((id_ == Id::Left_SingleQuote || id_ == Id::Left_RSingleQuote || id_ == Id::Left_TSingleQuote || id_ == Id::Left_RTSingleQuote)) {
    strs = Alloc<List<BigStr*>>();
    for (ListIter<syntax_asdl::Token*> it(tokens); !it.Done(); it.Next()) {
      syntax_asdl::Token* t = it.Value();
      strs->append(lexer::TokenVal(t));
    }
  }
  else {
    if ((id_ == Id::Left_DollarSingleQuote || id_ == Id::Left_USingleQuote || id_ == Id::Left_BSingleQuote || id_ == Id::Left_UTSingleQuote || id_ == Id::Left_BTSingleQuote)) {
      strs = Alloc<List<BigStr*>>();
      for (ListIter<syntax_asdl::Token*> it(tokens); !it.Done(); it.Next()) {
        syntax_asdl::Token* t = it.Value();
        StackRoot _for(&t      );
        if (t->id == Id::Char_UBraced) {
          s = lexer::TokenSlice(t, 3, -1);
          code_point = to_int(s, 16);
          if (code_point > 1114111) {
            p_die(str1704, t);
          }
          if ((55296 <= code_point and code_point < 57344)) {
            p_die(StrFormat("%s escape is illegal because it's in the surrogate range", lexer::TokenVal(t)), t);
          }
        }
        strs->append(EvalCStringToken(t->id, lexer::TokenVal(t)));
      }
    }
    else {
      assert(0);  // AssertionError
    }
  }
  return str1706->join(strs);
}

bool _TokenConsistsOf(syntax_asdl::Token* tok, BigStr* byte_set) {
  int start;
  int end;
  int b;
  StackRoot _root0(&tok);
  StackRoot _root1(&byte_set);

  start = tok->col;
  end = (tok->col + tok->length);
  for (int i = start; i < end; ++i) {
    b = mylib::ByteAt(tok->line->content, i);
    if (!mylib::ByteInSet(b, byte_set)) {
      return false;
    }
  }
  return true;
}

bool _IsLeadingSpace(syntax_asdl::Token* tok) {
  StackRoot _root0(&tok);

  return _TokenConsistsOf(tok, str1707);
}

bool _IsTrailingSpace(syntax_asdl::Token* tok) {
  StackRoot _root0(&tok);

  return _TokenConsistsOf(tok, str1708);
}

void RemoveLeadingSpaceDQ(List<syntax_asdl::word_part_t*>* parts) {
  syntax_asdl::word_part_t* UP_first = nullptr;
  syntax_asdl::word_part_t* UP_last = nullptr;
  BigStr* to_strip = nullptr;
  int n;
  bool line_ended;
  Token* lit_tok = nullptr;
  StackRoot _root0(&parts);
  StackRoot _root1(&UP_first);
  StackRoot _root2(&UP_last);
  StackRoot _root3(&to_strip);
  StackRoot _root4(&lit_tok);

  if (len(parts) <= 1) {
    return ;
  }
  UP_first = parts->at(0);
  if (UP_first->tag() == word_part_e::Literal) {
    Token* first = static_cast<Token*>(UP_first);
    if (_IsTrailingSpace(first)) {
      parts->pop(0);
    }
  }
  UP_last = parts->at(-1);
  to_strip = nullptr;
  if (UP_last->tag() == word_part_e::Literal) {
    Token* last = static_cast<Token*>(UP_last);
    if (_IsLeadingSpace(last)) {
      to_strip = lexer::TokenVal(last);
      parts->pop();
    }
  }
  if (to_strip == nullptr) {
    return ;
  }
  n = len(to_strip);
  for (ListIter<syntax_asdl::word_part_t*> it(parts); !it.Done(); it.Next()) {
    syntax_asdl::word_part_t* part = it.Value();
    StackRoot _for(&part  );
    if (part->tag() != word_part_e::Literal) {
      line_ended = false;
      continue;
    }
    lit_tok = static_cast<Token*>(part);
    if ((lit_tok->col == 0 and lexer::TokenStartsWith(lit_tok, to_strip))) {
      lit_tok->col = n;
      lit_tok->length -= n;
      lit_tok->id = Id::Lit_CharsWithoutPrefix;
    }
  }
}

void RemoveLeadingSpaceSQ(List<syntax_asdl::Token*>* tokens) {
  syntax_asdl::Token* first = nullptr;
  syntax_asdl::Token* last = nullptr;
  BigStr* to_strip = nullptr;
  int n;
  StackRoot _root0(&tokens);
  StackRoot _root1(&first);
  StackRoot _root2(&last);
  StackRoot _root3(&to_strip);

  if (len(tokens) <= 1) {
    return ;
  }
  first = tokens->at(0);
  if (first->id == Id::Lit_Chars) {
    if (_IsTrailingSpace(first)) {
      tokens->pop(0);
    }
  }
  last = tokens->at(-1);
  to_strip = nullptr;
  if (last->id == Id::Lit_Chars) {
    if (_IsLeadingSpace(last)) {
      to_strip = lexer::TokenVal(last);
      tokens->pop();
    }
  }
  if (to_strip == nullptr) {
    return ;
  }
  n = len(to_strip);
  for (ListIter<syntax_asdl::Token*> it(tokens); !it.Done(); it.Next()) {
    syntax_asdl::Token* tok = it.Value();
    StackRoot _for(&tok  );
    if ((tok->col == 0 and lexer::TokenStartsWith(tok, to_strip))) {
      tok->col = n;
      tok->length -= n;
      tok->id = Id::Lit_CharsWithoutPrefix;
    }
  }
}

}  // define namespace word_compile

namespace word_eval {  // define

using id_kind_asdl::Id;
using id_kind_asdl::Kind;
using id_kind_asdl::Kind_str;
using syntax_asdl::Token;
using syntax_asdl::SimpleVarSub;
using syntax_asdl::loc;
using syntax_asdl::loc_t;
using syntax_asdl::BracedVarSub;
using syntax_asdl::CommandSub;
using syntax_asdl::bracket_op;
using syntax_asdl::bracket_op_e;
using syntax_asdl::suffix_op;
using syntax_asdl::suffix_op_e;
using syntax_asdl::ShArrayLiteral;
using syntax_asdl::SingleQuoted;
using syntax_asdl::DoubleQuoted;
using syntax_asdl::word_e;
using syntax_asdl::word_t;
using syntax_asdl::CompoundWord;
using syntax_asdl::rhs_word;
using syntax_asdl::rhs_word_e;
using syntax_asdl::rhs_word_t;
using syntax_asdl::word_part;
using syntax_asdl::word_part_e;
using runtime_asdl::part_value;
using runtime_asdl::part_value_e;
using runtime_asdl::part_value_t;
using runtime_asdl::cmd_value;
using runtime_asdl::cmd_value_e;
using runtime_asdl::cmd_value_t;
using runtime_asdl::AssignArg;
using runtime_asdl::a_index;
using runtime_asdl::a_index_e;
using runtime_asdl::VTestPlace;
using runtime_asdl::VarSubState;
using runtime_asdl::Piece;
using option_asdl::option_i;
using option_asdl::builtin_i;
using value_asdl::value;
using value_asdl::value_e;
using value_asdl::value_t;
using value_asdl::sh_lvalue;
using value_asdl::sh_lvalue_t;
using error::e_die;
int QUOTED = (1 << 0);
int IS_SUBST = (1 << 1);
int EXTGLOB_FILES = (1 << 2);
int EXTGLOB_MATCH = (1 << 3);
int EXTGLOB_NESTED = (1 << 4);
int QUOTE_FNMATCH = (1 << 5);
int QUOTE_ERE = (1 << 6);
GLOBAL_LIST(_STRING_AND_ARRAY, BigStr*, 3, {str1712 COMMA str1713 COMMA str1714});

bool ShouldArrayDecay(BigStr* var_name, optview::Exec* exec_opts, bool is_plain_var_sub) {
  StackRoot _root0(&var_name);
  StackRoot _root1(&exec_opts);

  return (!exec_opts->strict_array() or (is_plain_var_sub and list_contains(_STRING_AND_ARRAY, var_name)));
}

value_asdl::value_t* DecayArray(value_asdl::value_t* val) {
  value::BashArray* array_val = nullptr;
  BigStr* s = nullptr;
  value::BashAssoc* assoc_val = nullptr;
  StackRoot _root0(&val);
  StackRoot _root1(&array_val);
  StackRoot _root2(&s);
  StackRoot _root3(&assoc_val);

  if (val->tag() == value_e::BashArray) {
    array_val = static_cast<value::BashArray*>(val);
    s = len(array_val->strs) ? array_val->strs->at(0) : nullptr;
  }
  else {
    if (val->tag() == value_e::BashAssoc) {
      assoc_val = static_cast<value::BashAssoc*>(val);
      s = dict_contains(assoc_val->d, str1715) ? assoc_val->d->at(str1716) : nullptr;
    }
    else {
      assert(0);  // AssertionError
    }
  }
  if (s == nullptr) {
    return value::Undef;
  }
  else {
    return Alloc<value::Str>(s);
  }
}

BigStr* GetArrayItem(List<BigStr*>* strs, int index) {
  int n;
  BigStr* s = nullptr;
  StackRoot _root0(&strs);
  StackRoot _root1(&s);

  n = len(strs);
  if (index < 0) {
    index += n;
  }
  if ((0 <= index and index < n)) {
    s = strs->at(index);
  }
  else {
    s = nullptr;
  }
  return s;
}

bool _DetectMetaBuiltinStr(BigStr* s) {
  StackRoot _root0(&s);

  return (consts::LookupNormalBuiltin(s) == builtin_i::builtin || consts::LookupNormalBuiltin(s) == builtin_i::command);
}

bool _DetectMetaBuiltin(runtime_asdl::part_value_t* val0) {
  runtime_asdl::part_value_t* UP_val0 = nullptr;
  StackRoot _root0(&val0);
  StackRoot _root1(&UP_val0);

  UP_val0 = val0;
  if (val0->tag() == part_value_e::String) {
    Piece* val0 = static_cast<Piece*>(UP_val0);
    if (!val0->quoted) {
      return _DetectMetaBuiltinStr(val0->s);
    }
  }
  return false;
}

runtime_asdl::AssignArg* _SplitAssignArg(BigStr* arg, syntax_asdl::CompoundWord* blame_word) {
  List<BigStr*>* m = nullptr;
  BigStr* var_name = nullptr;
  BigStr* op = nullptr;
  value_asdl::value_t* val = nullptr;
  bool append;
  StackRoot _root0(&arg);
  StackRoot _root1(&blame_word);
  StackRoot _root2(&m);
  StackRoot _root3(&var_name);
  StackRoot _root4(&op);
  StackRoot _root5(&val);

  m = util::RegexSearch(consts::ASSIGN_ARG_RE, arg);
  if (m == nullptr) {
    e_die(StrFormat("Assignment builtin expected NAME=value, got %r", arg), blame_word);
  }
  var_name = m->at(1);
  op = m->at(3);
  if (len(op)) {
    val = Alloc<value::Str>(m->at(4));
    append = str_equals(op->at(0), str1718);
  }
  else {
    val = nullptr;
    append = false;
  }
  return Alloc<AssignArg>(var_name, val, append, blame_word);
}

BigStr* _BackslashEscape(BigStr* s) {
  StackRoot _root0(&s);

  return s->replace(str1719, str1720);
}

runtime_asdl::part_value_t* _ValueToPartValue(value_asdl::value_t* val, bool quoted, syntax_asdl::word_part_t* part_loc) {
  value_asdl::value_t* UP_val = nullptr;
  BigStr* s = nullptr;
  StackRoot _root0(&val);
  StackRoot _root1(&part_loc);
  StackRoot _root2(&UP_val);
  StackRoot _root3(&s);

  UP_val = val;
  switch (val->tag()) {
    case value_e::Undef: {
      return Alloc<Piece>(str1721, quoted, !quoted);
    }
      break;
    case value_e::Str: {
      value::Str* val = static_cast<value::Str*>(UP_val);
      return Alloc<Piece>(val->s, quoted, !quoted);
    }
      break;
    case value_e::BashArray: {
      value::BashArray* val = static_cast<value::BashArray*>(UP_val);
      return Alloc<part_value::Array>(val->strs);
    }
      break;
    case value_e::BashAssoc: {
      value::BashAssoc* val = static_cast<value::BashAssoc*>(UP_val);
      return Alloc<part_value::Array>(val->d->values());
    }
      break;
    case value_e::Null: 
    case value_e::Bool: 
    case value_e::Int: 
    case value_e::Float: 
    case value_e::Eggex: 
    case value_e::List: {
      s = val_ops::Stringify(val, loc::Missing);
      return Alloc<Piece>(s, quoted, !quoted);
    }
      break;
    default: {
      throw Alloc<error::TypeErr>(val, str1722, Alloc<loc::WordPart>(part_loc));
    }
  }
  assert(0);  // AssertionError
}

List<List<runtime_asdl::Piece*>*>* _MakeWordFrames(List<runtime_asdl::part_value_t*>* part_vals) {
  List<runtime_asdl::Piece*>* current = nullptr;
  List<List<runtime_asdl::Piece*>*>* frames = nullptr;
  runtime_asdl::part_value_t* UP_p = nullptr;
  bool is_first;
  runtime_asdl::Piece* piece = nullptr;
  StackRoot _root0(&part_vals);
  StackRoot _root1(&current);
  StackRoot _root2(&frames);
  StackRoot _root3(&UP_p);
  StackRoot _root4(&piece);

  current = Alloc<List<runtime_asdl::Piece*>>();
  frames = NewList<List<runtime_asdl::Piece*>*>(std::initializer_list<List<runtime_asdl::Piece*>*>{current});
  for (ListIter<runtime_asdl::part_value_t*> it(part_vals); !it.Done(); it.Next()) {
    runtime_asdl::part_value_t* p = it.Value();
    StackRoot _for(&p  );
    UP_p = p;
    switch (p->tag()) {
      case part_value_e::String: {
        Piece* p = static_cast<Piece*>(UP_p);
        current->append(p);
      }
        break;
      case part_value_e::Array: {
        part_value::Array* p = static_cast<part_value::Array*>(UP_p);
        is_first = true;
        for (ListIter<BigStr*> it(p->strs); !it.Done(); it.Next()) {
          BigStr* s = it.Value();
          StackRoot _for(&s        );
          if (s == nullptr) {
            continue;
          }
          piece = Alloc<Piece>(s, true, false);
          if (is_first) {
            current->append(piece);
            is_first = false;
          }
          else {
            current = NewList<runtime_asdl::Piece*>(std::initializer_list<runtime_asdl::Piece*>{piece});
            frames->append(current);
          }
        }
      }
        break;
      default: {
        assert(0);  // AssertionError
      }
    }
  }
  return frames;
}

BigStr* _DecayPartValuesToString(List<runtime_asdl::part_value_t*>* part_vals, BigStr* join_char) {
  List<BigStr*>* out = nullptr;
  runtime_asdl::part_value_t* UP_p = nullptr;
  List<BigStr*>* tmp = nullptr;
  StackRoot _root0(&part_vals);
  StackRoot _root1(&join_char);
  StackRoot _root2(&out);
  StackRoot _root3(&UP_p);
  StackRoot _root4(&tmp);

  out = Alloc<List<BigStr*>>();
  for (ListIter<runtime_asdl::part_value_t*> it(part_vals); !it.Done(); it.Next()) {
    runtime_asdl::part_value_t* p = it.Value();
    StackRoot _for(&p  );
    UP_p = p;
    switch (p->tag()) {
      case part_value_e::String: {
        Piece* p = static_cast<Piece*>(UP_p);
        out->append(p->s);
      }
        break;
      case part_value_e::Array: {
        part_value::Array* p = static_cast<part_value::Array*>(UP_p);
        tmp = Alloc<List<BigStr*>>();
        for (ListIter<BigStr*> it(p->strs); !it.Done(); it.Next()) {
          BigStr* s = it.Value();
          if (s != nullptr) {
            tmp->append(s);
          }
        }
        out->append(join_char->join(tmp));
      }
        break;
      default: {
        assert(0);  // AssertionError
      }
    }
  }
  return str1724->join(out);
}

value_asdl::value_t* _PerformSlice(value_asdl::value_t* val, int begin, int length, bool has_length, syntax_asdl::BracedVarSub* part, value::Str* arg0_val) {
  value_asdl::value_t* UP_val = nullptr;
  BigStr* s = nullptr;
  int n;
  int byte_begin;
  int num_iters;
  int byte_end;
  BigStr* substr = nullptr;
  value_asdl::value_t* result = nullptr;
  List<BigStr*>* orig = nullptr;
  int i;
  List<BigStr*>* strs = nullptr;
  int count;
  StackRoot _root0(&val);
  StackRoot _root1(&part);
  StackRoot _root2(&arg0_val);
  StackRoot _root3(&UP_val);
  StackRoot _root4(&s);
  StackRoot _root5(&substr);
  StackRoot _root6(&result);
  StackRoot _root7(&orig);
  StackRoot _root8(&strs);

  UP_val = val;
  switch (val->tag()) {
    case value_e::Str: {
      value::Str* val = static_cast<value::Str*>(UP_val);
      s = val->s;
      n = len(s);
      if (begin < 0) {
        byte_begin = n;
        num_iters = -begin;
        for (int _ = 0; _ < num_iters; ++_) {
          byte_begin = string_ops::PreviousUtf8Char(s, byte_begin);
        }
      }
      else {
        byte_begin = string_ops::AdvanceUtf8Chars(s, begin, 0);
      }
      if (has_length) {
        if (length < 0) {
          byte_end = n;
          num_iters = -length;
          for (int _ = 0; _ < num_iters; ++_) {
            byte_end = string_ops::PreviousUtf8Char(s, byte_end);
          }
        }
        else {
          byte_end = string_ops::AdvanceUtf8Chars(s, length, byte_begin);
        }
      }
      else {
        byte_end = len(s);
      }
      substr = s->slice(byte_begin, byte_end);
      result = Alloc<value::Str>(substr);
    }
      break;
    case value_e::BashArray: {
      value::BashArray* val = static_cast<value::BashArray*>(UP_val);
      if ((has_length and length < 0)) {
        e_die(StrFormat("Array slice can't have negative length: %d", length), Alloc<loc::WordPart>(part));
      }
      if (arg0_val != nullptr) {
        orig = NewList<BigStr*>(std::initializer_list<BigStr*>{arg0_val->s});
        orig->extend(val->strs);
      }
      else {
        orig = val->strs;
      }
      n = len(orig);
      if (begin < 0) {
        i = (n + begin);
      }
      else {
        i = begin;
      }
      strs = Alloc<List<BigStr*>>();
      count = 0;
      while (i < n) {
        if ((has_length and count == length)) {
          break;
        }
        s = orig->at(i);
        if (s != nullptr) {
          strs->append(s);
          count += 1;
        }
        i += 1;
      }
      result = Alloc<value::BashArray>(strs);
    }
      break;
    case value_e::BashAssoc: {
      e_die(str1726, Alloc<loc::WordPart>(part));
    }
      break;
    default: {
      throw Alloc<error::TypeErr>(val, str1727, Alloc<loc::WordPart>(part));
    }
  }
  return result;
}

StringWordEvaluator::StringWordEvaluator() {
  ;  // pass
}

value::Str* StringWordEvaluator::EvalWordToString(syntax_asdl::word_t* w, int eval_flags) {
  StackRoot _root0(&w);

  FAIL(kNotImplemented);  // Python NotImplementedError
}

BigStr* _GetDollarHyphen(optview::Exec* exec_opts) {
  List<BigStr*>* chars = nullptr;
  StackRoot _root0(&exec_opts);
  StackRoot _root1(&chars);

  chars = Alloc<List<BigStr*>>();
  if (exec_opts->interactive()) {
    chars->append(str1728);
  }
  if (exec_opts->errexit()) {
    chars->append(str1729);
  }
  if (exec_opts->noglob()) {
    chars->append(str1730);
  }
  if (exec_opts->noexec()) {
    chars->append(str1731);
  }
  if (exec_opts->nounset()) {
    chars->append(str1732);
  }
  if (exec_opts->xtrace()) {
    chars->append(str1733);
  }
  if (exec_opts->noclobber()) {
    chars->append(str1734);
  }
  return str1735->join(chars);
}

TildeEvaluator::TildeEvaluator(state::Mem* mem, optview::Exec* exec_opts) {
  this->mem = mem;
  this->exec_opts = exec_opts;
}

BigStr* TildeEvaluator::GetMyHomeDir() {
  value_asdl::value_t* val = nullptr;
  value_asdl::value_t* UP_val = nullptr;
  StackRoot _root0(&val);
  StackRoot _root1(&UP_val);

  val = this->mem->GetValue(str1736);
  UP_val = val;
  if (val->tag() == value_e::Str) {
    value::Str* val = static_cast<value::Str*>(UP_val);
    return val->s;
  }
  return pyos::GetMyHomeDir();
}

BigStr* TildeEvaluator::Eval(word_part::TildeSub* part) {
  BigStr* result = nullptr;
  StackRoot _root0(&part);
  StackRoot _root1(&result);

  if (part->user_name == nullptr) {
    result = this->GetMyHomeDir();
  }
  else {
    result = pyos::GetHomeDir(part->user_name);
  }
  if (result == nullptr) {
    if (this->exec_opts->strict_tilde()) {
      e_die(str1737, part->left);
    }
    else {
      result = str1738;
      if (part->user_name != nullptr) {
        result = str_concat(result, part->user_name);
      }
    }
  }
  return result;
}

AbstractWordEvaluator::AbstractWordEvaluator(state::Mem* mem, optview::Exec* exec_opts, state::MutableOpts* mutable_opts, word_eval::TildeEvaluator* tilde_ev, split::SplitContext* splitter, ui::ErrorFormatter* errfmt) {
  this->arith_ev = nullptr;
  this->expr_ev = nullptr;
  this->prompt_ev = nullptr;
  this->unsafe_arith = nullptr;
  this->tilde_ev = tilde_ev;
  this->mem = mem;
  this->exec_opts = exec_opts;
  this->mutable_opts = mutable_opts;
  this->splitter = splitter;
  this->errfmt = errfmt;
  this->globber = Alloc<glob_::Globber>(exec_opts);
}

void AbstractWordEvaluator::CheckCircularDeps() {
  FAIL(kNotImplemented);  // Python NotImplementedError
}

runtime_asdl::part_value_t* AbstractWordEvaluator::_EvalCommandSub(syntax_asdl::CommandSub* cs_part, bool quoted) {
  StackRoot _root0(&cs_part);

  FAIL(kNotImplemented);  // Python NotImplementedError
}

runtime_asdl::part_value_t* AbstractWordEvaluator::_EvalProcessSub(syntax_asdl::CommandSub* cs_part) {
  StackRoot _root0(&cs_part);

  FAIL(kNotImplemented);  // Python NotImplementedError
}

value_asdl::value_t* AbstractWordEvaluator::_EvalVarNum(int var_num) {
  return this->mem->GetArgNum(var_num);
}

value_asdl::value_t* AbstractWordEvaluator::_EvalSpecialVar(int op_id, bool quoted, runtime_asdl::VarSubState* vsub_state) {
  List<BigStr*>* argv = nullptr;
  value_asdl::value_t* val = nullptr;
  StackRoot _root0(&vsub_state);
  StackRoot _root1(&argv);
  StackRoot _root2(&val);

  if ((op_id == Id::VSub_At || op_id == Id::VSub_Star)) {
    argv = this->mem->GetArgv();
    val = Alloc<value::BashArray>(argv);
    if (op_id == Id::VSub_At) {
      vsub_state->join_array = !quoted;
    }
    else {
      vsub_state->join_array = true;
    }
  }
  else {
    if (op_id == Id::VSub_Hyphen) {
      val = Alloc<value::Str>(_GetDollarHyphen(this->exec_opts));
    }
    else {
      val = this->mem->GetSpecialVar(op_id);
    }
  }
  return val;
}

bool AbstractWordEvaluator::_ApplyTestOp(value_asdl::value_t* val, suffix_op::Unary* op, bool quoted, List<runtime_asdl::part_value_t*>* part_vals, runtime_asdl::VTestPlace* vtest_place, syntax_asdl::Token* blame_token) {
  int eval_flags;
  syntax_asdl::Token* tok = nullptr;
  value_asdl::value_t* UP_val = nullptr;
  bool is_falsey;
  List<runtime_asdl::part_value_t*>* assign_part_vals = nullptr;
  BigStr* rhs_str = nullptr;
  value_asdl::sh_lvalue_t* lval = nullptr;
  BigStr* var_name = nullptr;
  runtime_asdl::a_index_t* var_index = nullptr;
  runtime_asdl::a_index_t* UP_var_index = nullptr;
  List<runtime_asdl::part_value_t*>* error_part_vals = nullptr;
  BigStr* error_str = nullptr;
  BigStr* actual = nullptr;
  BigStr* suffix = nullptr;
  StackRoot _root0(&val);
  StackRoot _root1(&op);
  StackRoot _root2(&part_vals);
  StackRoot _root3(&vtest_place);
  StackRoot _root4(&blame_token);
  StackRoot _root5(&tok);
  StackRoot _root6(&UP_val);
  StackRoot _root7(&assign_part_vals);
  StackRoot _root8(&rhs_str);
  StackRoot _root9(&lval);
  StackRoot _root10(&var_name);
  StackRoot _root11(&var_index);
  StackRoot _root12(&UP_var_index);
  StackRoot _root13(&error_part_vals);
  StackRoot _root14(&error_str);
  StackRoot _root15(&actual);
  StackRoot _root16(&suffix);

  eval_flags = IS_SUBST;
  if (quoted) {
    eval_flags |= QUOTED;
  }
  tok = op->op;
  UP_val = val;
  switch (val->tag()) {
    case value_e::Undef: {
      is_falsey = true;
    }
      break;
    case value_e::Str: {
      value::Str* val = static_cast<value::Str*>(UP_val);
      if ((tok->id == Id::VTest_ColonHyphen || tok->id == Id::VTest_ColonEquals || tok->id == Id::VTest_ColonQMark || tok->id == Id::VTest_ColonPlus)) {
        is_falsey = len(val->s) == 0;
      }
      else {
        is_falsey = false;
      }
    }
      break;
    case value_e::BashArray: {
      value::BashArray* val = static_cast<value::BashArray*>(UP_val);
      is_falsey = len(val->strs) == 0;
    }
      break;
    case value_e::BashAssoc: {
      value::BashAssoc* val = static_cast<value::BashAssoc*>(UP_val);
      is_falsey = len(val->d) == 0;
    }
      break;
    default: {
      is_falsey = false;
    }
  }
  if ((tok->id == Id::VTest_ColonHyphen || tok->id == Id::VTest_Hyphen)) {
    if (is_falsey) {
      this->_EvalRhsWordToParts(op->arg_word, part_vals, eval_flags);
      return true;
    }
    else {
      return false;
    }
  }
  else {
    if ((tok->id == Id::VTest_ColonPlus || tok->id == Id::VTest_Plus)) {
      if (is_falsey) {
        return false;
      }
      else {
        this->_EvalRhsWordToParts(op->arg_word, part_vals, eval_flags);
        return true;
      }
    }
    else {
      if ((tok->id == Id::VTest_ColonEquals || tok->id == Id::VTest_Equals)) {
        if (is_falsey) {
          assign_part_vals = Alloc<List<runtime_asdl::part_value_t*>>();
          this->_EvalRhsWordToParts(op->arg_word, assign_part_vals, eval_flags);
          part_vals->extend(assign_part_vals);
          if (vtest_place->name == nullptr) {
            e_die(str1739);
          }
          else {
            rhs_str = _DecayPartValuesToString(assign_part_vals, this->splitter->GetJoinChar());
            if (vtest_place->index == nullptr) {
              lval = location::LName(vtest_place->name);
            }
            else {
              var_name = vtest_place->name;
              var_index = vtest_place->index;
              UP_var_index = var_index;
              switch (var_index->tag()) {
                case a_index_e::Int: {
                  a_index::Int* var_index = static_cast<a_index::Int*>(UP_var_index);
                  lval = Alloc<sh_lvalue::Indexed>(var_name, var_index->i, loc::Missing);
                }
                  break;
                case a_index_e::Str: {
                  a_index::Str* var_index = static_cast<a_index::Str*>(UP_var_index);
                  lval = Alloc<sh_lvalue::Keyed>(var_name, var_index->s, loc::Missing);
                }
                  break;
                default: {
                  assert(0);  // AssertionError
                }
              }
            }
            state::OshLanguageSetValue(this->mem, lval, Alloc<value::Str>(rhs_str));
          }
          return true;
        }
        else {
          return false;
        }
      }
      else {
        if ((tok->id == Id::VTest_ColonQMark || tok->id == Id::VTest_QMark)) {
          if (is_falsey) {
            error_part_vals = Alloc<List<runtime_asdl::part_value_t*>>();
            this->_EvalRhsWordToParts(op->arg_word, error_part_vals, eval_flags);
            error_str = _DecayPartValuesToString(error_part_vals, this->splitter->GetJoinChar());
            if (vtest_place->name == nullptr) {
              var_name = str1740;
            }
            else {
              var_name = vtest_place->name;
            }
            if (val->tag() == value_e::Undef) {
              actual = str1742;
            }
            else {
              actual = str1743;
            }
            if (len(error_str)) {
              suffix = StrFormat(": %r", error_str);
            }
            else {
              suffix = str1745;
            }
            e_die(StrFormat("Var %s is %s%s", var_name, actual, suffix), blame_token);
          }
          else {
            return false;
          }
        }
        else {
          assert(0);  // AssertionError
        }
      }
    }
  }
}

int AbstractWordEvaluator::_Length(value_asdl::value_t* val, syntax_asdl::Token* token) {
  value_asdl::value_t* UP_val = nullptr;
  int length;
  StackRoot _root0(&val);
  StackRoot _root1(&token);
  StackRoot _root2(&UP_val);

  UP_val = val;
  switch (val->tag()) {
    case value_e::Str: {
      value::Str* val = static_cast<value::Str*>(UP_val);
      try {
        length = string_ops::CountUtf8Chars(val->s);
      }
      catch (error::Strict* e) {
        e->location = token;
        if (this->exec_opts->strict_word_eval()) {
          throw ;
        }
        else {
          this->errfmt->PrettyPrintError(e, str1747);
          return -1;
        }
      }
    }
      break;
    case value_e::BashArray: {
      value::BashArray* val = static_cast<value::BashArray*>(UP_val);
      length = 0;
      for (ListIter<BigStr*> it(val->strs); !it.Done(); it.Next()) {
        BigStr* s = it.Value();
        StackRoot _for(&s      );
        if (s != nullptr) {
          length += 1;
        }
      }
    }
      break;
    case value_e::BashAssoc: {
      value::BashAssoc* val = static_cast<value::BashAssoc*>(UP_val);
      length = len(val->d);
    }
      break;
    default: {
      throw Alloc<error::TypeErr>(val, str1748, token);
    }
  }
  return length;
}

value_asdl::value_t* AbstractWordEvaluator::_Keys(value_asdl::value_t* val, syntax_asdl::Token* token) {
  value_asdl::value_t* UP_val = nullptr;
  List<BigStr*>* indices = nullptr;
  int i;
  StackRoot _root0(&val);
  StackRoot _root1(&token);
  StackRoot _root2(&UP_val);
  StackRoot _root3(&indices);

  UP_val = val;
  switch (val->tag()) {
    case value_e::BashArray: {
      value::BashArray* val = static_cast<value::BashArray*>(UP_val);
      indices = Alloc<List<BigStr*>>();
      i = 0;
      for (ListIter<BigStr*> it(val->strs); !it.Done(); it.Next(), ++i) {
        BigStr* s = it.Value();
        StackRoot _for(&s      );
        if (s != nullptr) {
          indices->append(str(i));
        }
      }
      return Alloc<value::BashArray>(indices);
    }
      break;
    case value_e::BashAssoc: {
      value::BashAssoc* val = static_cast<value::BashAssoc*>(UP_val);
      return Alloc<value::BashArray>(val->d->keys());
    }
      break;
    default: {
      throw Alloc<error::TypeErr>(val, str1749, token);
    }
  }
}

value_asdl::value_t* AbstractWordEvaluator::_EvalVarRef(value_asdl::value_t* val, syntax_asdl::Token* blame_tok, bool quoted, runtime_asdl::VarSubState* vsub_state, runtime_asdl::VTestPlace* vtest_place) {
  value_asdl::value_t* UP_val = nullptr;
  syntax_asdl::BracedVarSub* bvs_part = nullptr;
  StackRoot _root0(&val);
  StackRoot _root1(&blame_tok);
  StackRoot _root2(&vsub_state);
  StackRoot _root3(&vtest_place);
  StackRoot _root4(&UP_val);
  StackRoot _root5(&bvs_part);

  UP_val = val;
  switch (val->tag()) {
    case value_e::Undef: {
      return value::Undef;
    }
      break;
    case value_e::Str: {
      value::Str* val = static_cast<value::Str*>(UP_val);
      bvs_part = this->unsafe_arith->ParseVarRef(val->s, blame_tok);
      return this->_VarRefValue(bvs_part, quoted, vsub_state, vtest_place);
    }
      break;
    case value_e::BashArray: {
      e_die(str1750);
    }
      break;
    case value_e::BashAssoc: {
      e_die(str1751);
    }
      break;
    default: {
      throw Alloc<error::TypeErr>(val, str1752, blame_tok);
    }
  }
}

value_asdl::value_t* AbstractWordEvaluator::_ApplyUnarySuffixOp(value_asdl::value_t* val, suffix_op::Unary* op) {
  id_kind_asdl::Kind_t op_kind;
  value::Str* arg_val = nullptr;
  bool has_extglob;
  value_asdl::value_t* UP_val = nullptr;
  BigStr* s = nullptr;
  value_asdl::value_t* new_val = nullptr;
  List<BigStr*>* strs = nullptr;
  StackRoot _root0(&val);
  StackRoot _root1(&op);
  StackRoot _root2(&arg_val);
  StackRoot _root3(&UP_val);
  StackRoot _root4(&s);
  StackRoot _root5(&new_val);
  StackRoot _root6(&strs);

  op_kind = consts::GetKind(op->op->id);
  if (op_kind == Kind::VOp1) {
    Tuple2<value::Str*, bool> tup0 = this->EvalWordToPattern(op->arg_word);
    arg_val = tup0.at0();
    has_extglob = tup0.at1();
    UP_val = val;
    switch (val->tag()) {
      case value_e::Str: {
        value::Str* val = static_cast<value::Str*>(UP_val);
        s = string_ops::DoUnarySuffixOp(val->s, op->op, arg_val->s, has_extglob);
        new_val = Alloc<value::Str>(s);
      }
        break;
      case value_e::BashArray: {
        value::BashArray* val = static_cast<value::BashArray*>(UP_val);
        strs = Alloc<List<BigStr*>>();
        for (ListIter<BigStr*> it(val->strs); !it.Done(); it.Next()) {
          BigStr* s = it.Value();
          StackRoot _for(&s        );
          if (s != nullptr) {
            strs->append(string_ops::DoUnarySuffixOp(s, op->op, arg_val->s, has_extglob));
          }
        }
        new_val = Alloc<value::BashArray>(strs);
      }
        break;
      case value_e::BashAssoc: {
        value::BashAssoc* val = static_cast<value::BashAssoc*>(UP_val);
        strs = Alloc<List<BigStr*>>();
        for (ListIter<BigStr*> it(val->d->values()); !it.Done(); it.Next()) {
          BigStr* s = it.Value();
          StackRoot _for(&s        );
          strs->append(string_ops::DoUnarySuffixOp(s, op->op, arg_val->s, has_extglob));
        }
        new_val = Alloc<value::BashArray>(strs);
      }
        break;
      default: {
        throw Alloc<error::TypeErr>(val, str1753, op->op);
      }
    }
  }
  else {
    assert(0);  // AssertionError
  }
  return new_val;
}

value_asdl::value_t* AbstractWordEvaluator::_PatSub(value_asdl::value_t* val, suffix_op::PatSub* op) {
  value::Str* pat_val = nullptr;
  bool has_extglob;
  value_asdl::value_t* replace_val = nullptr;
  BigStr* replace_str = nullptr;
  BigStr* regex = nullptr;
  List<BigStr*>* warnings = nullptr;
  string_ops::GlobReplacer* replacer = nullptr;
  value::Str* str_val = nullptr;
  BigStr* s = nullptr;
  value::BashArray* array_val = nullptr;
  List<BigStr*>* strs = nullptr;
  value::BashAssoc* assoc_val = nullptr;
  StackRoot _root0(&val);
  StackRoot _root1(&op);
  StackRoot _root2(&pat_val);
  StackRoot _root3(&replace_val);
  StackRoot _root4(&replace_str);
  StackRoot _root5(&regex);
  StackRoot _root6(&warnings);
  StackRoot _root7(&replacer);
  StackRoot _root8(&str_val);
  StackRoot _root9(&s);
  StackRoot _root10(&array_val);
  StackRoot _root11(&strs);
  StackRoot _root12(&assoc_val);

  Tuple2<value::Str*, bool> tup1 = this->EvalWordToPattern(op->pat);
  pat_val = tup1.at0();
  has_extglob = tup1.at1();
  if (has_extglob) {
    e_die(str1754, op->pat);
  }
  if (op->replace) {
    replace_val = this->EvalRhsWord(op->replace);
    replace_str = static_cast<value::Str*>(replace_val)->s;
  }
  else {
    replace_str = str1755;
  }
  Tuple2<BigStr*, List<BigStr*>*> tup2 = glob_::GlobToERE(pat_val->s);
  regex = tup2.at0();
  warnings = tup2.at1();
  if (len(warnings)) {
    ;  // pass
  }
  replacer = Alloc<string_ops::GlobReplacer>(regex, replace_str, op->slash_tok);
  switch (val->tag()) {
    case value_e::Str: {
      str_val = static_cast<value::Str*>(val);
      s = replacer->Replace(str_val->s, op);
      val = Alloc<value::Str>(s);
    }
      break;
    case value_e::BashArray: {
      array_val = static_cast<value::BashArray*>(val);
      strs = Alloc<List<BigStr*>>();
      for (ListIter<BigStr*> it(array_val->strs); !it.Done(); it.Next()) {
        BigStr* s = it.Value();
        StackRoot _for(&s      );
        if (s != nullptr) {
          strs->append(replacer->Replace(s, op));
        }
      }
      val = Alloc<value::BashArray>(strs);
    }
      break;
    case value_e::BashAssoc: {
      assoc_val = static_cast<value::BashAssoc*>(val);
      strs = Alloc<List<BigStr*>>();
      for (ListIter<BigStr*> it(assoc_val->d->values()); !it.Done(); it.Next()) {
        BigStr* s = it.Value();
        StackRoot _for(&s      );
        strs->append(replacer->Replace(s, op));
      }
      val = Alloc<value::BashArray>(strs);
    }
      break;
    default: {
      throw Alloc<error::TypeErr>(val, str1756, op->slash_tok);
    }
  }
  return val;
}

value_asdl::value_t* AbstractWordEvaluator::_Slice(value_asdl::value_t* val, suffix_op::Slice* op, BigStr* var_name, syntax_asdl::BracedVarSub* part) {
  int begin;
  bool has_length;
  int length;
  value::Str* arg0_val = nullptr;
  StackRoot _root0(&val);
  StackRoot _root1(&op);
  StackRoot _root2(&var_name);
  StackRoot _root3(&part);
  StackRoot _root4(&arg0_val);

  begin = this->arith_ev->EvalToInt(op->begin);
  has_length = false;
  length = -1;
  if (op->length) {
    has_length = true;
    length = this->arith_ev->EvalToInt(op->length);
  }
  try {
    arg0_val = nullptr;
    if (var_name == nullptr) {
      arg0_val = this->mem->GetArg0();
    }
    val = _PerformSlice(val, begin, length, has_length, part, arg0_val);
  }
  catch (error::Strict* e) {
    if (this->exec_opts->strict_word_eval()) {
      throw ;
    }
    else {
      this->errfmt->PrettyPrintError(e, str1757);
      switch (val->tag()) {
        case value_e::Str: {
          val = Alloc<value::Str>(str1758);
        }
          break;
        case value_e::BashArray: {
          val = Alloc<value::BashArray>(Alloc<List<BigStr*>>());
        }
          break;
        default: {
          FAIL(kNotImplemented);  // Python NotImplementedError
        }
      }
    }
  }
  return val;
}

Tuple2<value::Str*, bool> AbstractWordEvaluator::_Nullary(value_asdl::value_t* val, syntax_asdl::Token* op, BigStr* var_name) {
  value_asdl::value_t* UP_val = nullptr;
  bool quoted2;
  int op_id;
  BigStr* prompt = nullptr;
  BigStr* p = nullptr;
  value::Str* result = nullptr;
  List<BigStr*>* tmp = nullptr;
  List<BigStr*>* chars = nullptr;
  runtime_asdl::Cell* cell = nullptr;
  StackRoot _root0(&val);
  StackRoot _root1(&op);
  StackRoot _root2(&var_name);
  StackRoot _root3(&UP_val);
  StackRoot _root4(&prompt);
  StackRoot _root5(&p);
  StackRoot _root6(&result);
  StackRoot _root7(&tmp);
  StackRoot _root8(&chars);
  StackRoot _root9(&cell);

  UP_val = val;
  quoted2 = false;
  op_id = op->id;
  if (op_id == Id::VOp0_P) {
    switch (val->tag()) {
      case value_e::Str: {
        value::Str* str_val = static_cast<value::Str*>(UP_val);
        prompt = this->prompt_ev->EvalPrompt(str_val);
        p = prompt->replace(str1759, str1760)->replace(str1761, str1762);
        result = Alloc<value::Str>(p);
      }
        break;
      default: {
        e_die(StrFormat("Can't use @P on %s", ui::ValType(val)), op);
      }
    }
  }
  else {
    if (op_id == Id::VOp0_Q) {
      switch (val->tag()) {
        case value_e::Str: {
          value::Str* str_val = static_cast<value::Str*>(UP_val);
          result = Alloc<value::Str>(j8_lite::MaybeShellEncode(str_val->s));
          quoted2 = true;
        }
          break;
        case value_e::BashArray: {
          value::BashArray* array_val = static_cast<value::BashArray*>(UP_val);
          tmp = Alloc<List<BigStr*>>();
          for (ListIter<BigStr*> it(array_val->strs); !it.Done(); it.Next()) {
            BigStr* s = it.Value();
            tmp->append(j8_lite::MaybeShellEncode(s));
          }
          result = Alloc<value::Str>(str1764->join(tmp));
        }
          break;
        default: {
          e_die(StrFormat("Can't use @Q on %s", ui::ValType(val)), op);
        }
      }
    }
    else {
      if (op_id == Id::VOp0_a) {
        chars = Alloc<List<BigStr*>>();
        switch (val->tag()) {
          case value_e::BashArray: {
            chars->append(str1766);
          }
            break;
          case value_e::BashAssoc: {
            chars->append(str1767);
          }
            break;
        }
        if (var_name != nullptr) {
          cell = this->mem->GetCell(var_name);
          if (cell) {
            if (cell->readonly) {
              chars->append(str1768);
            }
            if (cell->exported) {
              chars->append(str1769);
            }
            if (cell->nameref) {
              chars->append(str1770);
            }
          }
        }
        result = Alloc<value::Str>(str1771->join(chars));
      }
      else {
        e_die(StrFormat("Var op %r not implemented", lexer::TokenVal(op)), op);
      }
    }
  }
  return Tuple2<value::Str*, bool>(result, quoted2);
}

value_asdl::value_t* AbstractWordEvaluator::_WholeArray(value_asdl::value_t* val, syntax_asdl::BracedVarSub* part, bool quoted, runtime_asdl::VarSubState* vsub_state) {
  int op_id;
  value_asdl::value_t* UP_val = nullptr;
  StackRoot _root0(&val);
  StackRoot _root1(&part);
  StackRoot _root2(&vsub_state);
  StackRoot _root3(&UP_val);

  op_id = static_cast<bracket_op::WholeArray*>(part->bracket_op)->op_id;
  if (op_id == Id::Lit_At) {
    vsub_state->join_array = !quoted;
    UP_val = val;
    switch (val->tag()) {
      case value_e::Undef: {
        if (!vsub_state->has_test_op) {
          val = this->_EmptyBashArrayOrError(part->token);
        }
      }
        break;
      case value_e::Str: {
        if (this->exec_opts->strict_array()) {
          e_die(str1773, Alloc<loc::WordPart>(part));
        }
      }
        break;
      case value_e::BashArray: {
        ;  // pass
      }
        break;
    }
  }
  else {
    if (op_id == Id::Arith_Star) {
      vsub_state->join_array = true;
      UP_val = val;
      switch (val->tag()) {
        case value_e::Undef: {
          if (!vsub_state->has_test_op) {
            val = this->_EmptyBashArrayOrError(part->token);
          }
        }
          break;
        case value_e::Str: {
          if (this->exec_opts->strict_array()) {
            e_die(str1774, Alloc<loc::WordPart>(part));
          }
        }
          break;
        case value_e::BashArray: {
          ;  // pass
        }
          break;
      }
    }
    else {
      assert(0);  // AssertionError
    }
  }
  return val;
}

value_asdl::value_t* AbstractWordEvaluator::_ArrayIndex(value_asdl::value_t* val, syntax_asdl::BracedVarSub* part, runtime_asdl::VTestPlace* vtest_place) {
  syntax_asdl::arith_expr_t* anode = nullptr;
  value_asdl::value_t* UP_val = nullptr;
  int index;
  BigStr* s = nullptr;
  BigStr* key = nullptr;
  StackRoot _root0(&val);
  StackRoot _root1(&part);
  StackRoot _root2(&vtest_place);
  StackRoot _root3(&anode);
  StackRoot _root4(&UP_val);
  StackRoot _root5(&s);
  StackRoot _root6(&key);

  anode = static_cast<bracket_op::ArrayIndex*>(part->bracket_op)->expr;
  UP_val = val;
  switch (val->tag()) {
    case value_e::Undef: {
      ;  // pass
    }
      break;
    case value_e::Str: {
      e_die(StrFormat("Can't index string %r with integer", part->var_name), part->token);
    }
      break;
    case value_e::BashArray: {
      value::BashArray* array_val = static_cast<value::BashArray*>(UP_val);
      index = this->arith_ev->EvalToInt(anode);
      vtest_place->index = Alloc<a_index::Int>(index);
      s = GetArrayItem(array_val->strs, index);
      if (s == nullptr) {
        val = value::Undef;
      }
      else {
        val = Alloc<value::Str>(s);
      }
    }
      break;
    case value_e::BashAssoc: {
      value::BashAssoc* assoc_val = static_cast<value::BashAssoc*>(UP_val);
      key = this->arith_ev->EvalWordToString(anode, location::TokenForArith(anode));
      vtest_place->index = Alloc<a_index::Str>(key);
      s = assoc_val->d->get(key);
      if (s == nullptr) {
        val = value::Undef;
      }
      else {
        val = Alloc<value::Str>(s);
      }
    }
      break;
    default: {
      throw Alloc<error::TypeErr>(val, str1776, Alloc<loc::WordPart>(part));
    }
  }
  return val;
}

void AbstractWordEvaluator::_EvalDoubleQuoted(List<syntax_asdl::word_part_t*>* parts, List<runtime_asdl::part_value_t*>* part_vals) {
  runtime_asdl::Piece* v = nullptr;
  StackRoot _root0(&parts);
  StackRoot _root1(&part_vals);
  StackRoot _root2(&v);

  if (len(parts) == 0) {
    v = Alloc<Piece>(str1777, true, false);
    part_vals->append(v);
    return ;
  }
  for (ListIter<syntax_asdl::word_part_t*> it(parts); !it.Done(); it.Next()) {
    syntax_asdl::word_part_t* p = it.Value();
    StackRoot _for(&p  );
    this->_EvalWordPart(p, part_vals, QUOTED);
  }
}

BigStr* AbstractWordEvaluator::EvalDoubleQuotedToString(syntax_asdl::DoubleQuoted* dq_part) {
  List<runtime_asdl::part_value_t*>* part_vals = nullptr;
  StackRoot _root0(&dq_part);
  StackRoot _root1(&part_vals);

  part_vals = Alloc<List<runtime_asdl::part_value_t*>>();
  this->_EvalDoubleQuoted(dq_part->parts, part_vals);
  return this->_ConcatPartVals(part_vals, dq_part->left);
}

value::Str* AbstractWordEvaluator::_DecayArray(value::BashArray* val) {
  BigStr* sep = nullptr;
  List<BigStr*>* tmp = nullptr;
  StackRoot _root0(&val);
  StackRoot _root1(&sep);
  StackRoot _root2(&tmp);

  sep = this->splitter->GetJoinChar();
  tmp = Alloc<List<BigStr*>>();
  for (ListIter<BigStr*> it(val->strs); !it.Done(); it.Next()) {
    BigStr* s = it.Value();
    if (s != nullptr) {
      tmp->append(s);
    }
  }
  return Alloc<value::Str>(sep->join(tmp));
}

value_asdl::value_t* AbstractWordEvaluator::_EmptyStrOrError(value_asdl::value_t* val, syntax_asdl::Token* token) {
  BigStr* tok_str = nullptr;
  BigStr* name = nullptr;
  StackRoot _root0(&val);
  StackRoot _root1(&token);
  StackRoot _root2(&tok_str);
  StackRoot _root3(&name);

  if (val->tag() != value_e::Undef) {
    return val;
  }
  if (!this->exec_opts->nounset()) {
    return Alloc<value::Str>(str1778);
  }
  tok_str = lexer::TokenVal(token);
  name = tok_str->startswith(str1779) ? tok_str->slice(1) : tok_str;
  e_die(StrFormat("Undefined variable %r", name), token);
}

value_asdl::value_t* AbstractWordEvaluator::_EmptyBashArrayOrError(syntax_asdl::Token* token) {
  StackRoot _root0(&token);

  if (this->exec_opts->nounset()) {
    e_die(StrFormat("Undefined array %r", lexer::TokenVal(token)), token);
  }
  else {
    return Alloc<value::BashArray>(Alloc<List<BigStr*>>());
  }
}

value_asdl::value_t* AbstractWordEvaluator::_EvalBracketOp(value_asdl::value_t* val, syntax_asdl::BracedVarSub* part, bool quoted, runtime_asdl::VarSubState* vsub_state, runtime_asdl::VTestPlace* vtest_place) {
  BigStr* var_name = nullptr;
  StackRoot _root0(&val);
  StackRoot _root1(&part);
  StackRoot _root2(&vsub_state);
  StackRoot _root3(&vtest_place);
  StackRoot _root4(&var_name);

  if (part->bracket_op) {
    switch (part->bracket_op->tag()) {
      case bracket_op_e::WholeArray: {
        val = this->_WholeArray(val, part, quoted, vsub_state);
      }
        break;
      case bracket_op_e::ArrayIndex: {
        val = this->_ArrayIndex(val, part, vtest_place);
      }
        break;
      default: {
        assert(0);  // AssertionError
      }
    }
  }
  else {
    var_name = vtest_place->name;
    if ((var_name != nullptr and ((val->tag() == value_e::BashArray || val->tag() == value_e::BashAssoc) and !vsub_state->is_type_query))) {
      if (ShouldArrayDecay(var_name, this->exec_opts, !(part->prefix_op or part->suffix_op))) {
        val = DecayArray(val);
      }
      else {
        e_die(StrFormat("Array %r can't be referred to as a scalar (without @ or *)", var_name), Alloc<loc::WordPart>(part));
      }
    }
  }
  return val;
}

value_asdl::value_t* AbstractWordEvaluator::_VarRefValue(syntax_asdl::BracedVarSub* part, bool quoted, runtime_asdl::VarSubState* vsub_state, runtime_asdl::VTestPlace* vtest_place) {
  value_asdl::value_t* val = nullptr;
  int var_num;
  StackRoot _root0(&part);
  StackRoot _root1(&vsub_state);
  StackRoot _root2(&vtest_place);
  StackRoot _root3(&val);

  if (part->token->id == Id::VSub_Name) {
    vtest_place->name = part->var_name;
    val = this->mem->GetValue(part->var_name);
  }
  else {
    if (part->token->id == Id::VSub_Number) {
      var_num = to_int(part->var_name);
      val = this->_EvalVarNum(var_num);
    }
    else {
      val = this->_EvalSpecialVar(part->token->id, quoted, vsub_state);
    }
  }
  if (this->exec_opts->eval_unsafe_arith()) {
    val = this->_EvalBracketOp(val, part, quoted, vsub_state, vtest_place);
  }
  else {
    {  // with
      state::ctx_Option ctx{this->mutable_opts, NewList<int>(std::initializer_list<int>{option_i::_allow_command_sub}), false};

      val = this->_EvalBracketOp(val, part, quoted, vsub_state, vtest_place);
    }
  }
  return val;
}

void AbstractWordEvaluator::_EvalBracedVarSub(syntax_asdl::BracedVarSub* part, List<runtime_asdl::part_value_t*>* part_vals, bool quoted) {
  BigStr* var_name = nullptr;
  runtime_asdl::VTestPlace* vtest_place = nullptr;
  runtime_asdl::VarSubState* vsub_state = nullptr;
  Token* nullary_op = nullptr;
  List<BigStr*>* names = nullptr;
  BigStr* sep = nullptr;
  value_asdl::value_t* val = nullptr;
  int var_num;
  syntax_asdl::suffix_op_t* suffix_op_ = nullptr;
  syntax_asdl::suffix_op_t* UP_op = nullptr;
  int n;
  syntax_asdl::Token* op_tok = nullptr;
  bool quoted2;
  syntax_asdl::suffix_op_t* op = nullptr;
  value_asdl::value_t* UP_val = nullptr;
  runtime_asdl::part_value_t* part_val = nullptr;
  StackRoot _root0(&part);
  StackRoot _root1(&part_vals);
  StackRoot _root2(&var_name);
  StackRoot _root3(&vtest_place);
  StackRoot _root4(&vsub_state);
  StackRoot _root5(&nullary_op);
  StackRoot _root6(&names);
  StackRoot _root7(&sep);
  StackRoot _root8(&val);
  StackRoot _root9(&suffix_op_);
  StackRoot _root10(&UP_op);
  StackRoot _root11(&op_tok);
  StackRoot _root12(&op);
  StackRoot _root13(&UP_val);
  StackRoot _root14(&part_val);

  var_name = nullptr;
  vtest_place = Alloc<VTestPlace>(var_name, nullptr);
  vsub_state = VarSubState::CreateNull();
  if (part->token->id == Id::VSub_Name) {
    if ((part->prefix_op != nullptr and (part->bracket_op == nullptr and (part->suffix_op != nullptr and part->suffix_op->tag() == suffix_op_e::Nullary)))) {
      nullary_op = static_cast<Token*>(part->suffix_op);
      if (consts::GetKind(nullary_op->id) == Kind::VOp3) {
        names = this->mem->VarNamesStartingWith(part->var_name);
        names->sort();
        if ((quoted and nullary_op->id == Id::VOp3_At)) {
          part_vals->append(Alloc<part_value::Array>(names));
        }
        else {
          sep = this->splitter->GetJoinChar();
          part_vals->append(Alloc<Piece>(sep->join(names), quoted, true));
        }
        return ;
      }
    }
    var_name = part->var_name;
    vtest_place->name = var_name;
    val = this->mem->GetValue(var_name);
  }
  else {
    if (part->token->id == Id::VSub_Number) {
      var_num = to_int(part->var_name);
      val = this->_EvalVarNum(var_num);
    }
    else {
      val = this->_EvalSpecialVar(part->token->id, quoted, vsub_state);
    }
  }
  suffix_op_ = part->suffix_op;
  if (suffix_op_) {
    UP_op = suffix_op_;
    switch (suffix_op_->tag()) {
      case suffix_op_e::Nullary: {
        Token* suffix_op_ = static_cast<Token*>(UP_op);
        if (suffix_op_->id == Id::VOp0_a) {
          vsub_state->is_type_query = true;
        }
      }
        break;
      case suffix_op_e::Unary: {
        suffix_op::Unary* suffix_op_ = static_cast<suffix_op::Unary*>(UP_op);
        if (consts::GetKind(suffix_op_->op->id) == Kind::VTest) {
          vsub_state->has_test_op = true;
        }
      }
        break;
    }
  }
  val = this->_EvalBracketOp(val, part, quoted, vsub_state, vtest_place);
  if (part->prefix_op) {
    if (part->prefix_op->id == Id::VSub_Pound) {
      if (!vsub_state->has_test_op) {
        val = this->_EmptyStrOrError(val, part->token);
      }
      n = this->_Length(val, part->token);
      part_vals->append(Alloc<Piece>(str(n), quoted, false));
      return ;
    }
    else {
      if (part->prefix_op->id == Id::VSub_Bang) {
        if ((part->bracket_op and part->bracket_op->tag() == bracket_op_e::WholeArray)) {
          if (vsub_state->has_test_op) {
            op_tok = static_cast<suffix_op::Unary*>(UP_op)->op;
            e_die(str1783, op_tok);
          }
          val = this->_Keys(val, part->token);
        }
        else {
          vtest_place->name = nullptr;
          vtest_place->index = nullptr;
          val = this->_EvalVarRef(val, part->token, quoted, vsub_state, vtest_place);
          if (!vsub_state->has_test_op) {
            val = this->_EmptyStrOrError(val, part->token);
          }
        }
      }
      else {
        assert(0);  // AssertionError
      }
    }
  }
  else {
    if (!vsub_state->has_test_op) {
      val = this->_EmptyStrOrError(val, part->token);
    }
  }
  quoted2 = false;
  if (suffix_op_) {
    op = suffix_op_;
    switch (suffix_op_->tag()) {
      case suffix_op_e::Nullary: {
        Token* op = static_cast<Token*>(UP_op);
        Tuple2<value::Str*, bool> tup3 = this->_Nullary(val, op, var_name);
        val = tup3.at0();
        quoted2 = tup3.at1();
      }
        break;
      case suffix_op_e::Unary: {
        suffix_op::Unary* op = static_cast<suffix_op::Unary*>(UP_op);
        if (consts::GetKind(op->op->id) == Kind::VTest) {
          if (this->_ApplyTestOp(val, op, quoted, part_vals, vtest_place, part->token)) {
            return ;
          }
        }
        else {
          val = this->_ApplyUnarySuffixOp(val, op);
        }
      }
        break;
      case suffix_op_e::PatSub: {
        suffix_op::PatSub* op = static_cast<suffix_op::PatSub*>(UP_op);
        val = this->_PatSub(val, op);
      }
        break;
      case suffix_op_e::Slice: {
        suffix_op::Slice* op = static_cast<suffix_op::Slice*>(UP_op);
        val = this->_Slice(val, op, var_name, part);
      }
        break;
      case suffix_op_e::Static: {
        suffix_op::Static* op = static_cast<suffix_op::Static*>(UP_op);
        e_die(str1784, op->tok);
      }
        break;
      default: {
        assert(0);  // AssertionError
      }
    }
  }
  UP_val = val;
  if (val->tag() == value_e::BashArray) {
    value::BashArray* array_val = static_cast<value::BashArray*>(UP_val);
    if (vsub_state->join_array) {
      val = this->_DecayArray(array_val);
    }
    else {
      val = array_val;
    }
  }
  part_val = _ValueToPartValue(val, (quoted or quoted2), part);
  part_vals->append(part_val);
}

BigStr* AbstractWordEvaluator::_ConcatPartVals(List<runtime_asdl::part_value_t*>* part_vals, syntax_asdl::loc_t* location) {
  List<BigStr*>* strs = nullptr;
  runtime_asdl::part_value_t* UP_part_val = nullptr;
  BigStr* s = nullptr;
  List<BigStr*>* tmp = nullptr;
  StackRoot _root0(&part_vals);
  StackRoot _root1(&location);
  StackRoot _root2(&strs);
  StackRoot _root3(&UP_part_val);
  StackRoot _root4(&s);
  StackRoot _root5(&tmp);

  strs = Alloc<List<BigStr*>>();
  for (ListIter<runtime_asdl::part_value_t*> it(part_vals); !it.Done(); it.Next()) {
    runtime_asdl::part_value_t* part_val = it.Value();
    StackRoot _for(&part_val  );
    UP_part_val = part_val;
    switch (part_val->tag()) {
      case part_value_e::String: {
        Piece* part_val = static_cast<Piece*>(UP_part_val);
        s = part_val->s;
      }
        break;
      case part_value_e::Array: {
        part_value::Array* part_val = static_cast<part_value::Array*>(UP_part_val);
        if (this->exec_opts->strict_array()) {
          e_die(str1785, location);
        }
        else {
          tmp = Alloc<List<BigStr*>>();
          for (ListIter<BigStr*> it(part_val->strs); !it.Done(); it.Next()) {
            BigStr* s = it.Value();
            if (s != nullptr) {
              tmp->append(s);
            }
          }
          s = str1786->join(tmp);
        }
      }
        break;
      default: {
        assert(0);  // AssertionError
      }
    }
    strs->append(s);
  }
  return str1787->join(strs);
}

BigStr* AbstractWordEvaluator::EvalBracedVarSubToString(syntax_asdl::BracedVarSub* part) {
  List<runtime_asdl::part_value_t*>* part_vals = nullptr;
  StackRoot _root0(&part);
  StackRoot _root1(&part_vals);

  part_vals = Alloc<List<runtime_asdl::part_value_t*>>();
  this->_EvalBracedVarSub(part, part_vals, false);
  return this->_ConcatPartVals(part_vals, part->left);
}

void AbstractWordEvaluator::_EvalSimpleVarSub(syntax_asdl::SimpleVarSub* part, List<runtime_asdl::part_value_t*>* part_vals, bool quoted) {
  syntax_asdl::Token* token = nullptr;
  runtime_asdl::VarSubState* vsub_state = nullptr;
  BigStr* var_name = nullptr;
  value_asdl::value_t* val = nullptr;
  int var_num;
  value_asdl::value_t* UP_val = nullptr;
  runtime_asdl::part_value_t* v = nullptr;
  StackRoot _root0(&part);
  StackRoot _root1(&part_vals);
  StackRoot _root2(&token);
  StackRoot _root3(&vsub_state);
  StackRoot _root4(&var_name);
  StackRoot _root5(&val);
  StackRoot _root6(&UP_val);
  StackRoot _root7(&v);

  token = part->tok;
  vsub_state = VarSubState::CreateNull();
  if (token->id == Id::VSub_DollarName) {
    var_name = lexer::LazyStr(token);
    val = this->mem->GetValue(var_name);
    if ((val->tag() == value_e::BashArray || val->tag() == value_e::BashAssoc)) {
      if (ShouldArrayDecay(var_name, this->exec_opts)) {
        val = DecayArray(val);
      }
      else {
        e_die(StrFormat("Array %r can't be referred to as a scalar (without @ or *)", var_name), token);
      }
    }
  }
  else {
    if (token->id == Id::VSub_Number) {
      var_num = to_int(lexer::LazyStr(token));
      val = this->_EvalVarNum(var_num);
    }
    else {
      val = this->_EvalSpecialVar(token->id, quoted, vsub_state);
    }
  }
  val = this->_EmptyStrOrError(val, token);
  UP_val = val;
  if (val->tag() == value_e::BashArray) {
    value::BashArray* array_val = static_cast<value::BashArray*>(UP_val);
    if (vsub_state->join_array) {
      val = this->_DecayArray(array_val);
    }
    else {
      val = array_val;
    }
  }
  v = _ValueToPartValue(val, quoted, part);
  part_vals->append(v);
}

BigStr* AbstractWordEvaluator::EvalSimpleVarSubToString(syntax_asdl::SimpleVarSub* node) {
  List<runtime_asdl::part_value_t*>* part_vals = nullptr;
  StackRoot _root0(&node);
  StackRoot _root1(&part_vals);

  part_vals = Alloc<List<runtime_asdl::part_value_t*>>();
  this->_EvalSimpleVarSub(node, part_vals, false);
  return this->_ConcatPartVals(part_vals, node->tok);
}

void AbstractWordEvaluator::_EvalExtGlob(word_part::ExtGlob* part, List<runtime_asdl::part_value_t*>* part_vals) {
  syntax_asdl::Token* op = nullptr;
  BigStr* op_str = nullptr;
  int i;
  StackRoot _root0(&part);
  StackRoot _root1(&part_vals);
  StackRoot _root2(&op);
  StackRoot _root3(&op_str);

  op = part->op;
  if (op->id == Id::ExtGlob_Comma) {
    op_str = str1789;
  }
  else {
    op_str = lexer::LazyStr(op);
  }
  part_vals->append(Alloc<Piece>(op_str, false, false));
  i = 0;
  for (ListIter<syntax_asdl::CompoundWord*> it(part->arms); !it.Done(); it.Next(), ++i) {
    syntax_asdl::CompoundWord* w = it.Value();
    StackRoot _for(&w  );
    if (i != 0) {
      part_vals->append(Alloc<Piece>(str1790, false, false));
    }
    this->_EvalWordToParts(w, part_vals, EXTGLOB_NESTED);
  }
  part_vals->append(Alloc<Piece>(str1791, false, false));
}

void AbstractWordEvaluator::_TranslateExtGlob(List<runtime_asdl::part_value_t*>* part_vals, syntax_asdl::CompoundWord* w, List<BigStr*>* glob_parts, List<BigStr*>* fnmatch_parts) {
  int i;
  runtime_asdl::part_value_t* UP_part_val = nullptr;
  BigStr* s = nullptr;
  StackRoot _root0(&part_vals);
  StackRoot _root1(&w);
  StackRoot _root2(&glob_parts);
  StackRoot _root3(&fnmatch_parts);
  StackRoot _root4(&UP_part_val);
  StackRoot _root5(&s);

  i = 0;
  for (ListIter<runtime_asdl::part_value_t*> it(part_vals); !it.Done(); it.Next(), ++i) {
    runtime_asdl::part_value_t* part_val = it.Value();
    StackRoot _for(&part_val  );
    UP_part_val = part_val;
    switch (part_val->tag()) {
      case part_value_e::String: {
        Piece* part_val = static_cast<Piece*>(UP_part_val);
        if ((part_val->quoted and !this->exec_opts->noglob())) {
          s = glob_::GlobEscape(part_val->s);
        }
        else {
          s = part_val->s;
        }
        glob_parts->append(s);
        fnmatch_parts->append(s);
      }
        break;
      case part_value_e::Array: {
        e_die(str1792, w);
      }
        break;
      case part_value_e::ExtGlob: {
        part_value::ExtGlob* part_val = static_cast<part_value::ExtGlob*>(UP_part_val);
        this->_TranslateExtGlob(part_val->part_vals, w, Alloc<List<BigStr*>>(), fnmatch_parts);
        glob_parts->append(str1793);
      }
        break;
      default: {
        assert(0);  // AssertionError
      }
    }
  }
}

void AbstractWordEvaluator::_EvalWordPart(syntax_asdl::word_part_t* part, List<runtime_asdl::part_value_t*>* part_vals, int flags) {
  bool quoted;
  bool is_subst;
  syntax_asdl::word_part_t* UP_part = nullptr;
  runtime_asdl::Piece* v = nullptr;
  int id_;
  runtime_asdl::part_value_t* sv = nullptr;
  BigStr* s = nullptr;
  mops::BigInt num;
  List<runtime_asdl::part_value_t*>* part_vals2 = nullptr;
  value_asdl::value_t* val = nullptr;
  List<BigStr*>* strs = nullptr;
  runtime_asdl::part_value_t* part_val = nullptr;
  StackRoot _root0(&part);
  StackRoot _root1(&part_vals);
  StackRoot _root2(&UP_part);
  StackRoot _root3(&v);
  StackRoot _root4(&sv);
  StackRoot _root5(&s);
  StackRoot _root6(&part_vals2);
  StackRoot _root7(&val);
  StackRoot _root8(&strs);
  StackRoot _root9(&part_val);

  quoted = to_bool((flags & QUOTED));
  is_subst = to_bool((flags & IS_SUBST));
  UP_part = part;
  switch (part->tag()) {
    case word_part_e::ShArrayLiteral: {
      ShArrayLiteral* part = static_cast<ShArrayLiteral*>(UP_part);
      e_die(str1794, Alloc<loc::WordPart>(part));
    }
      break;
    case word_part_e::BashAssocLiteral: {
      word_part::BashAssocLiteral* part = static_cast<word_part::BashAssocLiteral*>(UP_part);
      e_die(str1795, Alloc<loc::WordPart>(part));
    }
      break;
    case word_part_e::Literal: {
      Token* part = static_cast<Token*>(UP_part);
      v = Alloc<Piece>(lexer::LazyStr(part), quoted, is_subst);
      part_vals->append(v);
    }
      break;
    case word_part_e::EscapedLiteral: {
      word_part::EscapedLiteral* part = static_cast<word_part::EscapedLiteral*>(UP_part);
      v = Alloc<Piece>(part->ch, true, false);
      part_vals->append(v);
    }
      break;
    case word_part_e::SingleQuoted: {
      SingleQuoted* part = static_cast<SingleQuoted*>(UP_part);
      v = Alloc<Piece>(part->sval, true, false);
      part_vals->append(v);
    }
      break;
    case word_part_e::DoubleQuoted: {
      DoubleQuoted* part = static_cast<DoubleQuoted*>(UP_part);
      this->_EvalDoubleQuoted(part->parts, part_vals);
    }
      break;
    case word_part_e::CommandSub: {
      CommandSub* part = static_cast<CommandSub*>(UP_part);
      id_ = part->left_token->id;
      if ((id_ == Id::Left_DollarParen || id_ == Id::Left_AtParen || id_ == Id::Left_Backtick)) {
        sv = this->_EvalCommandSub(part, quoted);
      }
      else {
        if ((id_ == Id::Left_ProcSubIn || id_ == Id::Left_ProcSubOut)) {
          sv = this->_EvalProcessSub(part);
        }
        else {
          assert(0);  // AssertionError
        }
      }
      part_vals->append(sv);
    }
      break;
    case word_part_e::SimpleVarSub: {
      SimpleVarSub* part = static_cast<SimpleVarSub*>(UP_part);
      this->_EvalSimpleVarSub(part, part_vals, quoted);
    }
      break;
    case word_part_e::BracedVarSub: {
      BracedVarSub* part = static_cast<BracedVarSub*>(UP_part);
      this->_EvalBracedVarSub(part, part_vals, quoted);
    }
      break;
    case word_part_e::TildeSub: {
      word_part::TildeSub* part = static_cast<word_part::TildeSub*>(UP_part);
      s = this->tilde_ev->Eval(part);
      v = Alloc<Piece>(s, true, false);
      part_vals->append(v);
    }
      break;
    case word_part_e::ArithSub: {
      word_part::ArithSub* part = static_cast<word_part::ArithSub*>(UP_part);
      num = this->arith_ev->EvalToBigInt(part->anode);
      v = Alloc<Piece>(mops::ToStr(num), quoted, !quoted);
      part_vals->append(v);
    }
      break;
    case word_part_e::ExtGlob: {
      word_part::ExtGlob* part = static_cast<word_part::ExtGlob*>(UP_part);
      part_vals2 = Alloc<List<runtime_asdl::part_value_t*>>();
      this->_EvalExtGlob(part, part_vals2);
      part_vals->append(Alloc<part_value::ExtGlob>(part_vals2));
    }
      break;
    case word_part_e::BashRegexGroup: {
      word_part::BashRegexGroup* part = static_cast<word_part::BashRegexGroup*>(UP_part);
      part_vals->append(Alloc<Piece>(str1796, false, false));
      if (part->child) {
        this->_EvalWordToParts(part->child, part_vals, 0);
      }
      part_vals->append(Alloc<Piece>(str1797, false, false));
    }
      break;
    case word_part_e::Splice: {
      word_part::Splice* part = static_cast<word_part::Splice*>(UP_part);
      val = this->mem->GetValue(part->var_name);
      strs = this->expr_ev->SpliceValue(val, part);
      part_vals->append(Alloc<part_value::Array>(strs));
    }
      break;
    case word_part_e::ExprSub: {
      word_part::ExprSub* part = static_cast<word_part::ExprSub*>(UP_part);
      part_val = this->expr_ev->EvalExprSub(part);
      part_vals->append(part_val);
    }
      break;
    case word_part_e::ZshVarSub: {
      word_part::ZshVarSub* part = static_cast<word_part::ZshVarSub*>(UP_part);
      e_die(str1798, part->left);
    }
      break;
    default: {
      assert(0);  // AssertionError
    }
  }
}

void AbstractWordEvaluator::_EvalRhsWordToParts(syntax_asdl::rhs_word_t* w, List<runtime_asdl::part_value_t*>* part_vals, int eval_flags) {
  bool quoted;
  syntax_asdl::rhs_word_t* UP_w = nullptr;
  StackRoot _root0(&w);
  StackRoot _root1(&part_vals);
  StackRoot _root2(&UP_w);

  quoted = to_bool((eval_flags & QUOTED));
  UP_w = w;
  switch (w->tag()) {
    case rhs_word_e::Empty: {
      part_vals->append(Alloc<Piece>(str1799, quoted, !quoted));
    }
      break;
    case rhs_word_e::Compound: {
      CompoundWord* w = static_cast<CompoundWord*>(UP_w);
      this->_EvalWordToParts(w, part_vals, eval_flags);
    }
      break;
    default: {
      assert(0);  // AssertionError
    }
  }
}

void AbstractWordEvaluator::_EvalWordToParts(syntax_asdl::CompoundWord* w, List<runtime_asdl::part_value_t*>* part_vals, int eval_flags) {
  List<runtime_asdl::part_value_t*>* word_part_vals = nullptr;
  bool has_extglob;
  List<BigStr*>* glob_parts = nullptr;
  List<BigStr*>* fnmatch_parts = nullptr;
  BigStr* glob_pat = nullptr;
  BigStr* fnmatch_pat = nullptr;
  List<BigStr*>* results = nullptr;
  int n;
  StackRoot _root0(&w);
  StackRoot _root1(&part_vals);
  StackRoot _root2(&word_part_vals);
  StackRoot _root3(&glob_parts);
  StackRoot _root4(&fnmatch_parts);
  StackRoot _root5(&glob_pat);
  StackRoot _root6(&fnmatch_pat);
  StackRoot _root7(&results);

  word_part_vals = Alloc<List<runtime_asdl::part_value_t*>>();
  has_extglob = false;
  for (ListIter<syntax_asdl::word_part_t*> it(w->parts); !it.Done(); it.Next()) {
    syntax_asdl::word_part_t* p = it.Value();
    StackRoot _for(&p  );
    if (p->tag() == word_part_e::ExtGlob) {
      has_extglob = true;
    }
    this->_EvalWordPart(p, word_part_vals, eval_flags);
  }
  if (has_extglob) {
    if (to_bool((eval_flags & EXTGLOB_FILES))) {
      glob_parts = Alloc<List<BigStr*>>();
      fnmatch_parts = Alloc<List<BigStr*>>();
      this->_TranslateExtGlob(word_part_vals, w, glob_parts, fnmatch_parts);
      glob_pat = str1800->join(glob_parts);
      fnmatch_pat = str1801->join(fnmatch_parts);
      results = Alloc<List<BigStr*>>();
      n = this->globber->ExpandExtended(glob_pat, fnmatch_pat, results);
      if (n < 0) {
        throw Alloc<error::FailGlob>(StrFormat("Extended glob %r matched no files", fnmatch_pat), w);
      }
      part_vals->append(Alloc<part_value::Array>(results));
    }
    else {
      if (to_bool((eval_flags & EXTGLOB_NESTED))) {
        part_vals->extend(word_part_vals);
      }
      else {
        e_die(str1803, w);
      }
    }
  }
  else {
    part_vals->extend(word_part_vals);
  }
}

void AbstractWordEvaluator::_PartValsToString(List<runtime_asdl::part_value_t*>* part_vals, syntax_asdl::CompoundWord* w, int eval_flags, List<BigStr*>* strs) {
  runtime_asdl::part_value_t* UP_part_val = nullptr;
  BigStr* s = nullptr;
  List<BigStr*>* tmp = nullptr;
  StackRoot _root0(&part_vals);
  StackRoot _root1(&w);
  StackRoot _root2(&strs);
  StackRoot _root3(&UP_part_val);
  StackRoot _root4(&s);
  StackRoot _root5(&tmp);

  for (ListIter<runtime_asdl::part_value_t*> it(part_vals); !it.Done(); it.Next()) {
    runtime_asdl::part_value_t* part_val = it.Value();
    StackRoot _for(&part_val  );
    UP_part_val = part_val;
    switch (part_val->tag()) {
      case part_value_e::String: {
        Piece* part_val = static_cast<Piece*>(UP_part_val);
        s = part_val->s;
        if (part_val->quoted) {
          if ((eval_flags & QUOTE_FNMATCH)) {
            s = glob_::GlobEscape(s);
          }
          else {
            if ((eval_flags & QUOTE_ERE)) {
              s = glob_::ExtendedRegexEscape(s);
            }
          }
        }
        strs->append(s);
      }
        break;
      case part_value_e::Array: {
        part_value::Array* part_val = static_cast<part_value::Array*>(UP_part_val);
        if (this->exec_opts->strict_array()) {
          e_die(str1804, w);
        }
        else {
          tmp = Alloc<List<BigStr*>>();
          for (ListIter<BigStr*> it(part_val->strs); !it.Done(); it.Next()) {
            BigStr* s = it.Value();
            if (s != nullptr) {
              tmp->append(s);
            }
          }
          s = str1805->join(tmp);
          strs->append(s);
        }
      }
        break;
      case part_value_e::ExtGlob: {
        part_value::ExtGlob* part_val = static_cast<part_value::ExtGlob*>(UP_part_val);
        if (!to_bool((eval_flags & QUOTE_FNMATCH))) {
          e_die(str1806, w);
        }
        this->_PartValsToString(part_val->part_vals, w, eval_flags, strs);
      }
        break;
      default: {
        assert(0);  // AssertionError
      }
    }
  }
}

value::Str* AbstractWordEvaluator::EvalWordToString(syntax_asdl::word_t* UP_w, int eval_flags) {
  BigStr* fast_str = nullptr;
  List<runtime_asdl::part_value_t*>* part_vals = nullptr;
  List<BigStr*>* strs = nullptr;
  StackRoot _root0(&UP_w);
  StackRoot _root1(&fast_str);
  StackRoot _root2(&part_vals);
  StackRoot _root3(&strs);

  CompoundWord* w = static_cast<CompoundWord*>(UP_w);
  if (eval_flags == 0) {
    fast_str = word_::FastStrEval(w);
    if (fast_str != nullptr) {
      return Alloc<value::Str>(fast_str);
    }
  }
  part_vals = Alloc<List<runtime_asdl::part_value_t*>>();
  for (ListIter<syntax_asdl::word_part_t*> it(w->parts); !it.Done(); it.Next()) {
    syntax_asdl::word_part_t* p = it.Value();
    StackRoot _for(&p  );
    this->_EvalWordPart(p, part_vals, 0);
  }
  strs = Alloc<List<BigStr*>>();
  this->_PartValsToString(part_vals, w, eval_flags, strs);
  return Alloc<value::Str>(str1807->join(strs));
}

Tuple2<value::Str*, bool> AbstractWordEvaluator::EvalWordToPattern(syntax_asdl::rhs_word_t* UP_w) {
  bool has_extglob;
  List<runtime_asdl::part_value_t*>* part_vals = nullptr;
  List<BigStr*>* strs = nullptr;
  StackRoot _root0(&UP_w);
  StackRoot _root1(&part_vals);
  StackRoot _root2(&strs);

  if (UP_w->tag() == rhs_word_e::Empty) {
    return Tuple2<value::Str*, bool>(Alloc<value::Str>(str1808), false);
  }
  CompoundWord* w = static_cast<CompoundWord*>(UP_w);
  has_extglob = false;
  part_vals = Alloc<List<runtime_asdl::part_value_t*>>();
  for (ListIter<syntax_asdl::word_part_t*> it(w->parts); !it.Done(); it.Next()) {
    syntax_asdl::word_part_t* p = it.Value();
    StackRoot _for(&p  );
    this->_EvalWordPart(p, part_vals, 0);
    if (p->tag() == word_part_e::ExtGlob) {
      has_extglob = true;
    }
  }
  strs = Alloc<List<BigStr*>>();
  this->_PartValsToString(part_vals, w, QUOTE_FNMATCH, strs);
  return Tuple2<value::Str*, bool>(Alloc<value::Str>(str1809->join(strs)), has_extglob);
}

value::Str* AbstractWordEvaluator::EvalForPlugin(syntax_asdl::CompoundWord* w) {
  value::Str* val = nullptr;
  StackRoot _root0(&w);
  StackRoot _root1(&val);

  {  // with
    state::ctx_Registers ctx{this->mem};

    try {
      val = this->EvalWordToString(w);
    }
    catch (error::FatalRuntime* e) {
      val = Alloc<value::Str>(StrFormat("<Runtime error: %s>", e->UserErrorString()));
    }
    catch (IOError_OSError* e) {
      val = Alloc<value::Str>(StrFormat("<I/O error: %s>", pyutil::strerror(e)));
    }
    catch (KeyboardInterrupt*) {
      val = Alloc<value::Str>(str1812);
    }
  }
  return val;
}

value_asdl::value_t* AbstractWordEvaluator::EvalRhsWord(syntax_asdl::rhs_word_t* UP_w) {
  syntax_asdl::word_part_t* part0 = nullptr;
  syntax_asdl::word_part_t* UP_part0 = nullptr;
  int tag;
  List<syntax_asdl::word_t*>* array_words = nullptr;
  List<syntax_asdl::CompoundWord*>* words = nullptr;
  List<BigStr*>* strs = nullptr;
  Dict<BigStr*, BigStr*>* d = nullptr;
  value::Str* k = nullptr;
  value::Str* v = nullptr;
  StackRoot _root0(&UP_w);
  StackRoot _root1(&part0);
  StackRoot _root2(&UP_part0);
  StackRoot _root3(&array_words);
  StackRoot _root4(&words);
  StackRoot _root5(&strs);
  StackRoot _root6(&d);
  StackRoot _root7(&k);
  StackRoot _root8(&v);

  if (UP_w->tag() == rhs_word_e::Empty) {
    return Alloc<value::Str>(str1813);
  }
  CompoundWord* w = static_cast<CompoundWord*>(UP_w);
  if (len(w->parts) == 1) {
    part0 = w->parts->at(0);
    UP_part0 = part0;
    tag = part0->tag();
    if (tag == word_part_e::ShArrayLiteral) {
      ShArrayLiteral* part0 = static_cast<ShArrayLiteral*>(UP_part0);
      array_words = part0->words;
      words = braces::BraceExpandWords(array_words);
      strs = this->EvalWordSequence(words);
      return Alloc<value::BashArray>(strs);
    }
    if (tag == word_part_e::BashAssocLiteral) {
      word_part::BashAssocLiteral* part0 = static_cast<word_part::BashAssocLiteral*>(UP_part0);
      d = Alloc<Dict<BigStr*, BigStr*>>();
      for (ListIter<syntax_asdl::AssocPair*> it(part0->pairs); !it.Done(); it.Next()) {
        syntax_asdl::AssocPair* pair = it.Value();
        StackRoot _for(&pair      );
        k = this->EvalWordToString(pair->key);
        v = this->EvalWordToString(pair->value);
        d->set(k->s, v->s);
      }
      return Alloc<value::BashAssoc>(d);
    }
  }
  return this->EvalWordToString(w);
}

void AbstractWordEvaluator::_EvalWordFrame(List<runtime_asdl::Piece*>* frame, List<BigStr*>* argv) {
  bool all_empty;
  bool all_quoted;
  bool any_quoted;
  List<BigStr*>* tmp = nullptr;
  BigStr* a = nullptr;
  bool will_glob;
  List<BigStr*>* frags = nullptr;
  BigStr* frag = nullptr;
  BigStr* flat = nullptr;
  List<BigStr*>* args = nullptr;
  int n;
  StackRoot _root0(&frame);
  StackRoot _root1(&argv);
  StackRoot _root2(&tmp);
  StackRoot _root3(&a);
  StackRoot _root4(&frags);
  StackRoot _root5(&frag);
  StackRoot _root6(&flat);
  StackRoot _root7(&args);

  all_empty = true;
  all_quoted = true;
  any_quoted = false;
  for (ListIter<runtime_asdl::Piece*> it(frame); !it.Done(); it.Next()) {
    runtime_asdl::Piece* piece = it.Value();
    StackRoot _for(&piece  );
    if (len(piece->s)) {
      all_empty = false;
    }
    if (piece->quoted) {
      any_quoted = true;
    }
    else {
      all_quoted = false;
    }
  }
  if ((all_empty and !any_quoted)) {
    return ;
  }
  if (all_quoted) {
    tmp = Alloc<List<BigStr*>>();
    for (ListIter<runtime_asdl::Piece*> it(frame); !it.Done(); it.Next()) {
      runtime_asdl::Piece* piece = it.Value();
      tmp->append(piece->s);
    }
    a = str1814->join(tmp);
    argv->append(a);
    return ;
  }
  will_glob = !this->exec_opts->noglob();
  frags = Alloc<List<BigStr*>>();
  for (ListIter<runtime_asdl::Piece*> it(frame); !it.Done(); it.Next()) {
    runtime_asdl::Piece* piece = it.Value();
    StackRoot _for(&piece  );
    if ((will_glob and piece->quoted)) {
      frag = glob_::GlobEscape(piece->s);
    }
    else {
      frag = _BackslashEscape(piece->s);
    }
    if (piece->do_split) {
      frag = _BackslashEscape(frag);
    }
    else {
      frag = this->splitter->Escape(frag);
    }
    frags->append(frag);
  }
  flat = str1815->join(frags);
  args = this->splitter->SplitForWordEval(flat);
  if ((len(args) == 0 and any_quoted)) {
    argv->append(str1816);
    return ;
  }
  for (ListIter<BigStr*> it(args); !it.Done(); it.Next()) {
    BigStr* a = it.Value();
    StackRoot _for(&a  );
    if (glob_::LooksLikeGlob(a)) {
      n = this->globber->Expand(a, argv);
      if (n < 0) {
        throw Alloc<error::FailGlob>(StrFormat("Pattern %r matched no files", a), loc::Missing);
      }
    }
    else {
      argv->append(glob_::GlobUnescape(a));
    }
  }
}

List<BigStr*>* AbstractWordEvaluator::_EvalWordToArgv(syntax_asdl::CompoundWord* w) {
  List<runtime_asdl::part_value_t*>* part_vals = nullptr;
  List<List<runtime_asdl::Piece*>*>* frames = nullptr;
  List<BigStr*>* argv = nullptr;
  List<BigStr*>* tmp = nullptr;
  StackRoot _root0(&w);
  StackRoot _root1(&part_vals);
  StackRoot _root2(&frames);
  StackRoot _root3(&argv);
  StackRoot _root4(&tmp);

  part_vals = Alloc<List<runtime_asdl::part_value_t*>>();
  this->_EvalWordToParts(w, part_vals, 0);
  frames = _MakeWordFrames(part_vals);
  argv = Alloc<List<BigStr*>>();
  for (ListIter<List<runtime_asdl::Piece*>*> it(frames); !it.Done(); it.Next()) {
    List<runtime_asdl::Piece*>* frame = it.Value();
    StackRoot _for(&frame  );
    if (len(frame)) {
      tmp = Alloc<List<BigStr*>>();
      for (ListIter<runtime_asdl::Piece*> it(frame); !it.Done(); it.Next()) {
        runtime_asdl::Piece* piece = it.Value();
        tmp->append(piece->s);
      }
      argv->append(str1818->join(tmp));
    }
  }
  return argv;
}

cmd_value::Assign* AbstractWordEvaluator::_EvalAssignBuiltin(int builtin_id, BigStr* arg0, List<syntax_asdl::CompoundWord*>* words, int meta_offset) {
  bool eval_to_pairs;
  bool started_pairs;
  List<BigStr*>* flags = nullptr;
  List<syntax_asdl::CompoundWord*>* flag_locs = nullptr;
  List<runtime_asdl::AssignArg*>* assign_args = nullptr;
  int n;
  syntax_asdl::CompoundWord* w = nullptr;
  syntax_asdl::Token* left_token = nullptr;
  syntax_asdl::Token* close_token = nullptr;
  int part_offset;
  BigStr* var_name = nullptr;
  bool append;
  syntax_asdl::rhs_word_t* rhs = nullptr;
  syntax_asdl::CompoundWord* tmp = nullptr;
  value_asdl::value_t* right = nullptr;
  runtime_asdl::AssignArg* arg2 = nullptr;
  List<BigStr*>* argv = nullptr;
  StackRoot _root0(&arg0);
  StackRoot _root1(&words);
  StackRoot _root2(&flags);
  StackRoot _root3(&flag_locs);
  StackRoot _root4(&assign_args);
  StackRoot _root5(&w);
  StackRoot _root6(&left_token);
  StackRoot _root7(&close_token);
  StackRoot _root8(&var_name);
  StackRoot _root9(&rhs);
  StackRoot _root10(&tmp);
  StackRoot _root11(&right);
  StackRoot _root12(&arg2);
  StackRoot _root13(&argv);

  eval_to_pairs = true;
  started_pairs = false;
  flags = NewList<BigStr*>(std::initializer_list<BigStr*>{arg0});
  flag_locs = NewList<syntax_asdl::CompoundWord*>(std::initializer_list<syntax_asdl::CompoundWord*>{words->at(0)});
  assign_args = Alloc<List<runtime_asdl::AssignArg*>>();
  n = len(words);
  for (int i = (meta_offset + 1); i < n; ++i) {
    w = words->at(i);
    if (word_::IsVarLike(w)) {
      started_pairs = true;
    }
    if (started_pairs) {
      Tuple3<syntax_asdl::Token*, syntax_asdl::Token*, int> tup4 = word_::DetectShAssignment(w);
      left_token = tup4.at0();
      close_token = tup4.at1();
      part_offset = tup4.at2();
      if (left_token) {
        if (left_token->id != Id::Lit_VarLike) {
          e_die(str1819, w);
        }
        if (lexer::IsPlusEquals(left_token)) {
          var_name = lexer::TokenSliceRight(left_token, -2);
          append = true;
        }
        else {
          var_name = lexer::TokenSliceRight(left_token, -1);
          append = false;
        }
        if (part_offset == len(w->parts)) {
          rhs = rhs_word::Empty;
        }
        else {
          tmp = Alloc<CompoundWord>(w->parts->slice(part_offset));
          word_::TildeDetectAssign(tmp);
          rhs = tmp;
        }
        {  // with
          state::ctx_AssignBuiltin ctx{this->mutable_opts};

          right = this->EvalRhsWord(rhs);
        }
        arg2 = Alloc<AssignArg>(var_name, right, append, w);
        assign_args->append(arg2);
      }
      else {
        argv = this->_EvalWordToArgv(w);
        for (ListIter<BigStr*> it(argv); !it.Done(); it.Next()) {
          BigStr* arg = it.Value();
          StackRoot _for(&arg        );
          arg2 = _SplitAssignArg(arg, w);
          assign_args->append(arg2);
        }
      }
    }
    else {
      argv = this->_EvalWordToArgv(w);
      for (ListIter<BigStr*> it(argv); !it.Done(); it.Next()) {
        BigStr* arg = it.Value();
        StackRoot _for(&arg      );
        if ((arg->startswith(str1820) or arg->startswith(str1821))) {
          flags->append(arg);
          flag_locs->append(w);
          if ((str_contains(arg, str1822) or str_contains(arg, str1823))) {
            eval_to_pairs = false;
          }
        }
        else {
          if (eval_to_pairs) {
            arg2 = _SplitAssignArg(arg, w);
            assign_args->append(arg2);
            started_pairs = true;
          }
          else {
            flags->append(arg);
          }
        }
      }
    }
  }
  return Alloc<cmd_value::Assign>(builtin_id, flags, flag_locs, assign_args);
}

cmd_value::Assign* AbstractWordEvaluator::_DetectAssignBuiltinStr(BigStr* arg0, List<syntax_asdl::CompoundWord*>* words, int meta_offset) {
  int builtin_id;
  StackRoot _root0(&arg0);
  StackRoot _root1(&words);

  builtin_id = consts::LookupAssignBuiltin(arg0);
  if (builtin_id != consts::NO_INDEX) {
    return this->_EvalAssignBuiltin(builtin_id, arg0, words, meta_offset);
  }
  return nullptr;
}

cmd_value::Assign* AbstractWordEvaluator::_DetectAssignBuiltin(runtime_asdl::part_value_t* val0, List<syntax_asdl::CompoundWord*>* words, int meta_offset) {
  runtime_asdl::part_value_t* UP_val0 = nullptr;
  StackRoot _root0(&val0);
  StackRoot _root1(&words);
  StackRoot _root2(&UP_val0);

  UP_val0 = val0;
  if (val0->tag() == part_value_e::String) {
    Piece* val0 = static_cast<Piece*>(UP_val0);
    if (!val0->quoted) {
      return this->_DetectAssignBuiltinStr(val0->s, words, meta_offset);
    }
  }
  return nullptr;
}

runtime_asdl::cmd_value_t* AbstractWordEvaluator::SimpleEvalWordSequence2(List<syntax_asdl::CompoundWord*>* words, bool allow_assign) {
  List<BigStr*>* strs = nullptr;
  List<syntax_asdl::CompoundWord*>* locs = nullptr;
  int meta_offset;
  int i;
  List<BigStr*>* strs0 = nullptr;
  cmd_value::Assign* cmd_val = nullptr;
  value::Str* val = nullptr;
  int num_appended;
  List<runtime_asdl::part_value_t*>* part_vals = nullptr;
  List<List<runtime_asdl::Piece*>*>* frames = nullptr;
  List<BigStr*>* tmp = nullptr;
  StackRoot _root0(&words);
  StackRoot _root1(&strs);
  StackRoot _root2(&locs);
  StackRoot _root3(&strs0);
  StackRoot _root4(&cmd_val);
  StackRoot _root5(&val);
  StackRoot _root6(&part_vals);
  StackRoot _root7(&frames);
  StackRoot _root8(&tmp);

  strs = Alloc<List<BigStr*>>();
  locs = Alloc<List<syntax_asdl::CompoundWord*>>();
  meta_offset = 0;
  i = 0;
  for (ListIter<syntax_asdl::CompoundWord*> it(words); !it.Done(); it.Next(), ++i) {
    syntax_asdl::CompoundWord* w = it.Value();
    StackRoot _for(&w  );
    if ((i == meta_offset and allow_assign)) {
      strs0 = this->_EvalWordToArgv(w);
      if (len(strs0) == 1) {
        cmd_val = this->_DetectAssignBuiltinStr(strs0->at(0), words, meta_offset);
        if (cmd_val) {
          return cmd_val;
        }
      }
      strs->extend(strs0);
      for (ListIter<BigStr*> it(strs0); !it.Done(); it.Next()) {
        BigStr* _ = it.Value();
        StackRoot _for(&_      );
        locs->append(w);
      }
      continue;
    }
    if (glob_::LooksLikeStaticGlob(w)) {
      val = this->EvalWordToString(w);
      num_appended = this->globber->Expand(val->s, strs);
      if (num_appended < 0) {
        throw Alloc<error::FailGlob>(StrFormat("Pattern %r matched no files", val->s), w);
      }
      for (int _ = 0; _ < num_appended; ++_) {
        locs->append(w);
      }
      continue;
    }
    part_vals = Alloc<List<runtime_asdl::part_value_t*>>();
    this->_EvalWordToParts(w, part_vals, 0);
    frames = _MakeWordFrames(part_vals);
    for (ListIter<List<runtime_asdl::Piece*>*> it(frames); !it.Done(); it.Next()) {
      List<runtime_asdl::Piece*>* frame = it.Value();
      StackRoot _for(&frame    );
      if (len(frame)) {
        tmp = Alloc<List<BigStr*>>();
        for (ListIter<runtime_asdl::Piece*> it(frame); !it.Done(); it.Next()) {
          runtime_asdl::Piece* piece = it.Value();
          tmp->append(piece->s);
        }
        strs->append(str1831->join(tmp));
        locs->append(w);
      }
    }
  }
  return Alloc<cmd_value::Argv>(strs, locs, nullptr, nullptr, nullptr, nullptr);
}

runtime_asdl::cmd_value_t* AbstractWordEvaluator::EvalWordSequence2(List<syntax_asdl::CompoundWord*>* words, bool allow_assign) {
  List<BigStr*>* strs = nullptr;
  List<syntax_asdl::CompoundWord*>* locs = nullptr;
  int meta_offset;
  int n;
  int i;
  BigStr* fast_str = nullptr;
  cmd_value::Assign* cmd_val = nullptr;
  List<runtime_asdl::part_value_t*>* part_vals = nullptr;
  List<List<runtime_asdl::Piece*>*>* frames = nullptr;
  int n_next;
  StackRoot _root0(&words);
  StackRoot _root1(&strs);
  StackRoot _root2(&locs);
  StackRoot _root3(&fast_str);
  StackRoot _root4(&cmd_val);
  StackRoot _root5(&part_vals);
  StackRoot _root6(&frames);

  if (this->exec_opts->simple_word_eval()) {
    return this->SimpleEvalWordSequence2(words, allow_assign);
  }
  strs = Alloc<List<BigStr*>>();
  locs = Alloc<List<syntax_asdl::CompoundWord*>>();
  meta_offset = 0;
  n = 0;
  i = 0;
  for (ListIter<syntax_asdl::CompoundWord*> it(words); !it.Done(); it.Next(), ++i) {
    syntax_asdl::CompoundWord* w = it.Value();
    StackRoot _for(&w  );
    fast_str = word_::FastStrEval(w);
    if (fast_str != nullptr) {
      strs->append(fast_str);
      locs->append(w);
      if ((allow_assign and i == meta_offset)) {
        cmd_val = this->_DetectAssignBuiltinStr(fast_str, words, meta_offset);
        if (cmd_val) {
          return cmd_val;
        }
      }
      if ((i <= meta_offset and _DetectMetaBuiltinStr(fast_str))) {
        meta_offset += 1;
      }
      continue;
    }
    part_vals = Alloc<List<runtime_asdl::part_value_t*>>();
    this->_EvalWordToParts(w, part_vals, EXTGLOB_FILES);
    if (len(part_vals) == 1) {
      if ((allow_assign and i == meta_offset)) {
        cmd_val = this->_DetectAssignBuiltin(part_vals->at(0), words, meta_offset);
        if (cmd_val) {
          return cmd_val;
        }
      }
      if ((i <= meta_offset and _DetectMetaBuiltin(part_vals->at(0)))) {
        meta_offset += 1;
      }
    }
    frames = _MakeWordFrames(part_vals);
    for (ListIter<List<runtime_asdl::Piece*>*> it(frames); !it.Done(); it.Next()) {
      List<runtime_asdl::Piece*>* frame = it.Value();
      StackRoot _for(&frame    );
      this->_EvalWordFrame(frame, strs);
    }
    n_next = len(strs);
    for (int _ = 0; _ < (n_next - n); ++_) {
      locs->append(w);
    }
    n = n_next;
  }
  return Alloc<cmd_value::Argv>(strs, locs, nullptr, nullptr, nullptr, nullptr);
}

List<BigStr*>* AbstractWordEvaluator::EvalWordSequence(List<syntax_asdl::CompoundWord*>* words) {
  runtime_asdl::cmd_value_t* UP_cmd_val = nullptr;
  StackRoot _root0(&words);
  StackRoot _root1(&UP_cmd_val);

  UP_cmd_val = this->EvalWordSequence2(words);
  cmd_value::Argv* cmd_val = static_cast<cmd_value::Argv*>(UP_cmd_val);
  return cmd_val->argv;
}

NormalWordEvaluator::NormalWordEvaluator(state::Mem* mem, optview::Exec* exec_opts, state::MutableOpts* mutable_opts, word_eval::TildeEvaluator* tilde_ev, split::SplitContext* splitter, ui::ErrorFormatter* errfmt) : ::word_eval::AbstractWordEvaluator(mem, exec_opts, mutable_opts, tilde_ev, splitter, errfmt) {
  this->shell_ex = nullptr;
}

void NormalWordEvaluator::CheckCircularDeps() {
}

runtime_asdl::part_value_t* NormalWordEvaluator::_EvalCommandSub(syntax_asdl::CommandSub* cs_part, bool quoted) {
  BigStr* stdout_str = nullptr;
  List<BigStr*>* strs = nullptr;
  StackRoot _root0(&cs_part);
  StackRoot _root1(&stdout_str);
  StackRoot _root2(&strs);

  stdout_str = this->shell_ex->RunCommandSub(cs_part);
  if (cs_part->left_token->id == Id::Left_AtParen) {
    try {
      strs = j8::SplitJ8Lines(stdout_str);
    }
    catch (error::Decode* e) {
      throw Alloc<error::Structured>(4, e->Message(), cs_part->left_token);
    }
    return Alloc<part_value::Array>(strs);
  }
  else {
    return Alloc<Piece>(stdout_str, quoted, !quoted);
  }
}

runtime_asdl::Piece* NormalWordEvaluator::_EvalProcessSub(syntax_asdl::CommandSub* cs_part) {
  BigStr* dev_path = nullptr;
  StackRoot _root0(&cs_part);
  StackRoot _root1(&dev_path);

  dev_path = this->shell_ex->RunProcessSub(cs_part);
  return Alloc<Piece>(dev_path, true, false);
}
BigStr* _DUMMY = str1838;

CompletionWordEvaluator::CompletionWordEvaluator(state::Mem* mem, optview::Exec* exec_opts, state::MutableOpts* mutable_opts, word_eval::TildeEvaluator* tilde_ev, split::SplitContext* splitter, ui::ErrorFormatter* errfmt) : ::word_eval::AbstractWordEvaluator(mem, exec_opts, mutable_opts, tilde_ev, splitter, errfmt) {
}

void CompletionWordEvaluator::CheckCircularDeps() {
}

runtime_asdl::part_value_t* CompletionWordEvaluator::_EvalCommandSub(syntax_asdl::CommandSub* cs_part, bool quoted) {
  StackRoot _root0(&cs_part);

  if (cs_part->left_token->id == Id::Left_AtParen) {
    return Alloc<part_value::Array>(NewList<BigStr*>(std::initializer_list<BigStr*>{_DUMMY}));
  }
  else {
    return Alloc<Piece>(_DUMMY, quoted, !quoted);
  }
}

runtime_asdl::Piece* CompletionWordEvaluator::_EvalProcessSub(syntax_asdl::CommandSub* cs_part) {
  StackRoot _root0(&cs_part);

  return Alloc<Piece>(str1839, true, false);
}

}  // define namespace word_eval

namespace word_parse {  // define

using id_kind_asdl::Id;
using id_kind_asdl::Id_t;
using id_kind_asdl::Id_str;
using id_kind_asdl::Kind;
using types_asdl::lex_mode_t;
using types_asdl::lex_mode_e;
using syntax_asdl::BoolParamBox;
using syntax_asdl::Token;
using syntax_asdl::SimpleVarSub;
using syntax_asdl::loc;
using syntax_asdl::source;
using syntax_asdl::DoubleQuoted;
using syntax_asdl::SingleQuoted;
using syntax_asdl::BracedVarSub;
using syntax_asdl::CommandSub;
using syntax_asdl::ShArrayLiteral;
using syntax_asdl::AssocPair;
using syntax_asdl::bracket_op;
using syntax_asdl::bracket_op_t;
using syntax_asdl::suffix_op;
using syntax_asdl::suffix_op_t;
using syntax_asdl::rhs_word;
using syntax_asdl::rhs_word_e;
using syntax_asdl::rhs_word_t;
using syntax_asdl::word_e;
using syntax_asdl::word_t;
using syntax_asdl::CompoundWord;
using syntax_asdl::word_part;
using syntax_asdl::word_part_t;
using syntax_asdl::y_lhs_e;
using syntax_asdl::arith_expr_t;
using syntax_asdl::command;
using syntax_asdl::expr;
using syntax_asdl::expr_e;
using syntax_asdl::expr_t;
using syntax_asdl::pat_t;
using syntax_asdl::ArgList;
using syntax_asdl::Proc;
using syntax_asdl::Func;
using syntax_asdl::Subscript;
using syntax_asdl::Attribute;
using syntax_asdl::arith_expr;
using error::p_die;
GLOBAL_LIST(KINDS_THAT_END_WORDS, id_kind_asdl::Kind_t, 4, {Kind::Eof COMMA Kind::WS COMMA Kind::Op COMMA Kind::Right});

WordEmitter::WordEmitter() {
  ;  // pass
}

syntax_asdl::word_t* WordEmitter::ReadWord(types_asdl::lex_mode_t lex_mode) {
  FAIL(kNotImplemented);  // Python NotImplementedError
}

WordParser::WordParser(parse_lib::ParseContext* parse_ctx, lexer::Lexer* lexer, reader::_Reader* line_reader) {
  this->parse_ctx = parse_ctx;
  this->lexer = lexer;
  this->line_reader = line_reader;
  this->arena = line_reader->arena;
  this->parse_opts = parse_ctx->parse_opts;
  this->a_parser = Alloc<tdop::TdopParser>(arith_parse::Spec(), this, this->parse_opts);
  this->Reset();
}

void WordParser::Init(types_asdl::lex_mode_t lex_mode) {
  this->next_lex_mode = lex_mode;
}

void WordParser::Reset() {
  this->cur_token = nullptr;
  this->token_kind = Kind::Undefined;
  this->token_type = Id::Undefined_Tok;
  this->next_lex_mode = lex_mode_e::ShCommand;
  this->emit_doc_token = false;
  this->multiline = false;
  this->newline_state = 0;
  this->returned_newline = false;
  this->buffered_word = nullptr;
}

void WordParser::_GetToken() {
  bool is_fake;
  types_asdl::lex_mode_t real_mode;
  if (this->next_lex_mode == lex_mode_e::Undefined) {
    return ;
  }
  is_fake = this->next_lex_mode == lex_mode_e::BashRegexFakeInner;
  real_mode = is_fake ? lex_mode_e::BashRegex : this->next_lex_mode;
  this->cur_token = this->lexer->Read(real_mode);
  if ((is_fake and (this->cur_token->id == Id::WS_Space || this->cur_token->id == Id::BashRegex_AllowedInParens))) {
    this->cur_token->id = Id::Lit_Chars;
  }
  this->token_type = this->cur_token->id;
  this->token_kind = consts::GetKind(this->token_type);
  if (this->token_type == Id::Op_Newline) {
    this->newline_state += 1;
  }
  else {
    if (this->token_kind != Kind::WS) {
      this->newline_state = 0;
    }
  }
  this->parse_ctx->trail->AppendToken(this->cur_token);
  this->next_lex_mode = lex_mode_e::Undefined;
}

void WordParser::_SetNext(types_asdl::lex_mode_t lex_mode) {
  this->next_lex_mode = lex_mode;
}

syntax_asdl::rhs_word_t* WordParser::_ReadVarOpArg(types_asdl::lex_mode_t arg_lex_mode) {
  syntax_asdl::CompoundWord* w = nullptr;
  StackRoot _root0(&w);

  this->_SetNext(arg_lex_mode);
  this->_GetToken();
  w = this->_ReadVarOpArg2(arg_lex_mode, Id::Undefined_Tok, true);
  if ((len(w->parts) == 0 and arg_lex_mode == lex_mode_e::VSub_ArgDQ)) {
    return rhs_word::Empty;
  }
  return w;
}

syntax_asdl::CompoundWord* WordParser::_ReadVarOpArg2(types_asdl::lex_mode_t arg_lex_mode, int eof_type, bool empty_ok) {
  syntax_asdl::CompoundWord* w = nullptr;
  syntax_asdl::CompoundWord* tilde = nullptr;
  StackRoot _root0(&w);
  StackRoot _root1(&tilde);

  w = this->_ReadCompoundWord3(arg_lex_mode, eof_type, empty_ok);
  tilde = word_::TildeDetect(w);
  if (tilde) {
    w = tilde;
  }
  return w;
}

suffix_op::Slice* WordParser::_ReadSliceVarOp() {
  int cur_id;
  syntax_asdl::arith_expr_t* begin = nullptr;
  syntax_asdl::arith_expr_t* no_length = nullptr;
  syntax_asdl::Token* colon_tok = nullptr;
  syntax_asdl::arith_expr_t* length = nullptr;
  StackRoot _root0(&begin);
  StackRoot _root1(&no_length);
  StackRoot _root2(&colon_tok);
  StackRoot _root3(&length);

  this->_NextNonSpace();
  cur_id = this->token_type;
  if ((cur_id == Id::Arith_RBrace || cur_id == Id::Arith_Colon)) {
    begin = arith_expr::EmptyZero;
  }
  else {
    begin = this->a_parser->Parse();
    cur_id = this->a_parser->CurrentId();
  }
  if (cur_id == Id::Arith_RBrace) {
    no_length = nullptr;
    return Alloc<suffix_op::Slice>(begin, no_length);
  }
  else {
    if (cur_id == Id::Arith_Colon) {
      colon_tok = this->cur_token;
      this->_NextNonSpace();
      if (this->token_type == Id::Arith_RBrace) {
        if (this->parse_opts->strict_parse_slice()) {
          p_die(str1840, colon_tok);
        }
        length = arith_expr::EmptyZero;
      }
      else {
        length = this->_ReadArithExpr(Id::Arith_RBrace);
      }
      return Alloc<suffix_op::Slice>(begin, length);
    }
    else {
      p_die(str1841, this->cur_token);
    }
  }
  assert(0);  // AssertionError
}

suffix_op::PatSub* WordParser::_ReadPatSubVarOp() {
  syntax_asdl::Token* slash_tok = nullptr;
  int replace_mode;
  syntax_asdl::CompoundWord* pat = nullptr;
  bool empty_ok;
  syntax_asdl::rhs_word_t* replace = nullptr;
  StackRoot _root0(&slash_tok);
  StackRoot _root1(&pat);
  StackRoot _root2(&replace);

  slash_tok = this->cur_token;
  replace_mode = Id::Undefined_Tok;
  this->_SetNext(lex_mode_e::VSub_ArgUnquoted);
  this->_GetToken();
  if (this->token_type == Id::Right_DollarBrace) {
    pat = Alloc<CompoundWord>(Alloc<List<syntax_asdl::word_part_t*>>());
    return Alloc<suffix_op::PatSub>(pat, rhs_word::Empty, replace_mode, slash_tok);
  }
  if ((this->token_type == Id::Lit_Slash || this->token_type == Id::Lit_Pound || this->token_type == Id::Lit_Percent)) {
    replace_mode = this->token_type;
    this->_SetNext(lex_mode_e::VSub_ArgUnquoted);
  }
  empty_ok = replace_mode != Id::Lit_Slash;
  pat = this->_ReadVarOpArg2(lex_mode_e::VSub_ArgUnquoted, Id::Lit_Slash, empty_ok);
  if (this->token_type == Id::Lit_Slash) {
    replace = this->_ReadVarOpArg(lex_mode_e::VSub_ArgUnquoted);
  }
  else {
    replace = rhs_word::Empty;
  }
  this->_GetToken();
  if (this->token_type != Id::Right_DollarBrace) {
    p_die(StrFormat("Expected } after replacement string, got %s", ui::PrettyId(this->token_type)), this->cur_token);
  }
  return Alloc<suffix_op::PatSub>(pat, replace, replace_mode, slash_tok);
}

syntax_asdl::bracket_op_t* WordParser::_ReadSubscript() {
  int next_id;
  syntax_asdl::bracket_op_t* op = nullptr;
  syntax_asdl::arith_expr_t* anode = nullptr;
  StackRoot _root0(&op);
  StackRoot _root1(&anode);

  next_id = this->lexer->LookPastSpace(lex_mode_e::Arith);
  if ((next_id == Id::Lit_At || next_id == Id::Arith_Star)) {
    op = Alloc<bracket_op::WholeArray>(next_id);
    this->_SetNext(lex_mode_e::Arith);
    this->_GetToken();
    this->_SetNext(lex_mode_e::Arith);
    this->_GetToken();
  }
  else {
    this->_SetNext(lex_mode_e::Arith);
    anode = this->_ReadArithExpr(Id::Arith_RBracket);
    op = Alloc<bracket_op::ArrayIndex>(anode);
  }
  if (this->token_type != Id::Arith_RBracket) {
    p_die(str1843, this->cur_token);
  }
  this->_SetNext(lex_mode_e::VSub_2);
  this->_GetToken();
  return op;
}

syntax_asdl::BracedVarSub* WordParser::_ParseVarOf() {
  syntax_asdl::Token* name_token = nullptr;
  syntax_asdl::bracket_op_t* bracket_op = nullptr;
  syntax_asdl::BracedVarSub* part = nullptr;
  StackRoot _root0(&name_token);
  StackRoot _root1(&bracket_op);
  StackRoot _root2(&part);

  this->_GetToken();
  name_token = this->cur_token;
  this->_SetNext(lex_mode_e::VSub_2);
  this->_GetToken();
  if (this->token_type == Id::VOp2_LBracket) {
    bracket_op = this->_ReadSubscript();
  }
  else {
    bracket_op = nullptr;
  }
  part = BracedVarSub::CreateNull();
  part->token = name_token;
  part->var_name = lexer::TokenVal(name_token);
  part->bracket_op = bracket_op;
  return part;
}

syntax_asdl::BracedVarSub* WordParser::_ParseVarExpr(types_asdl::lex_mode_t arg_lex_mode, bool allow_query) {
  syntax_asdl::BracedVarSub* part = nullptr;
  id_kind_asdl::Kind_t op_kind;
  syntax_asdl::Token* tok = nullptr;
  syntax_asdl::rhs_word_t* arg_word = nullptr;
  syntax_asdl::rhs_word_t* UP_arg_word = nullptr;
  bool ok;
  BigStr* arg = nullptr;
  bool quoted;
  syntax_asdl::suffix_op_t* patsub_op = nullptr;
  StackRoot _root0(&part);
  StackRoot _root1(&tok);
  StackRoot _root2(&arg_word);
  StackRoot _root3(&UP_arg_word);
  StackRoot _root4(&arg);
  StackRoot _root5(&patsub_op);

  part = this->_ParseVarOf();
  this->_GetToken();
  if (this->token_type == Id::Right_DollarBrace) {
    return part;
  }
  op_kind = this->token_kind;
  if (op_kind == Kind::VTest) {
    tok = this->cur_token;
    arg_word = this->_ReadVarOpArg(arg_lex_mode);
    if (this->token_type != Id::Right_DollarBrace) {
      p_die(str1844, this->cur_token);
    }
    part->suffix_op = Alloc<suffix_op::Unary>(tok, arg_word);
  }
  else {
    if (op_kind == Kind::VOpYsh) {
      tok = this->cur_token;
      arg_word = this->_ReadVarOpArg(arg_lex_mode);
      if (this->token_type != Id::Right_DollarBrace) {
        p_die(str1845, this->cur_token);
      }
      UP_arg_word = arg_word;
      switch (arg_word->tag()) {
        case rhs_word_e::Empty: {
          ;  // pass
        }
          break;
        case rhs_word_e::Compound: {
          CompoundWord* arg_word = static_cast<CompoundWord*>(UP_arg_word);
          Tuple3<bool, BigStr*, bool> tup0 = word_::StaticEval(arg_word);
          ok = tup0.at0();
          arg = tup0.at1();
          quoted = tup0.at2();
          if ((!ok or quoted)) {
            p_die(str1846, Alloc<loc::Word>(arg_word));
          }
        }
          break;
      }
      part->suffix_op = Alloc<suffix_op::Static>(tok, arg);
    }
    else {
      if (op_kind == Kind::VOp0) {
        part->suffix_op = this->cur_token;
        this->_SetNext(lex_mode_e::VSub_2);
        this->_GetToken();
      }
      else {
        if (op_kind == Kind::VOp1) {
          tok = this->cur_token;
          arg_word = this->_ReadVarOpArg(lex_mode_e::VSub_ArgUnquoted);
          if (this->token_type != Id::Right_DollarBrace) {
            p_die(str1847, this->cur_token);
          }
          part->suffix_op = Alloc<suffix_op::Unary>(tok, arg_word);
        }
        else {
          if (op_kind == Kind::VOp2) {
            if (this->token_type == Id::VOp2_Slash) {
              patsub_op = this->_ReadPatSubVarOp();
              part->suffix_op = patsub_op;
            }
            else {
              if (this->token_type == Id::VOp2_Colon) {
                part->suffix_op = this->_ReadSliceVarOp();
                if (this->token_type != Id::Arith_RBrace) {
                  p_die(str1848, this->cur_token);
                }
              }
              else {
                p_die(StrFormat("Unexpected token in ${} (%s)", str1850), this->cur_token);
              }
            }
          }
          else {
            if (op_kind == Kind::VOp3) {
              if (allow_query) {
                part->suffix_op = this->cur_token;
                this->_SetNext(lex_mode_e::VSub_2);
                this->_GetToken();
              }
              else {
                p_die(StrFormat("Unexpected token in ${} (%s)", str1852), this->cur_token);
              }
            }
          }
        }
      }
    }
  }
  if ((this->token_type != Id::Right_DollarBrace && this->token_type != Id::Arith_RBrace)) {
    p_die(str1853, this->cur_token);
  }
  return part;
}

word_part::ZshVarSub* WordParser::_ReadZshVarSub(syntax_asdl::Token* left_token) {
  syntax_asdl::CompoundWord* w = nullptr;
  StackRoot _root0(&left_token);
  StackRoot _root1(&w);

  this->_SetNext(lex_mode_e::VSub_Zsh);
  w = this->_ReadCompoundWord3(lex_mode_e::VSub_Zsh, Id::Right_DollarBrace, true);
  this->_GetToken();
  return Alloc<word_part::ZshVarSub>(left_token, w, this->cur_token);
}

Tuple2<syntax_asdl::BracedVarSub*, syntax_asdl::Token*> WordParser::ReadBracedVarSub(syntax_asdl::Token* left_token) {
  syntax_asdl::BracedVarSub* part = nullptr;
  syntax_asdl::Token* last_token = nullptr;
  StackRoot _root0(&left_token);
  StackRoot _root1(&part);
  StackRoot _root2(&last_token);

  part = this->_ReadBracedVarSub(left_token, false);
  last_token = this->cur_token;
  return Tuple2<syntax_asdl::BracedVarSub*, syntax_asdl::Token*>(part, last_token);
}

syntax_asdl::BracedVarSub* WordParser::_ReadBracedVarSub(syntax_asdl::Token* left_token, bool d_quoted) {
  types_asdl::lex_mode_t arg_lex_mode;
  int ty;
  syntax_asdl::Token* first_tok = nullptr;
  int next_id;
  syntax_asdl::BracedVarSub* part = nullptr;
  StackRoot _root0(&left_token);
  StackRoot _root1(&first_tok);
  StackRoot _root2(&part);

  if (d_quoted) {
    arg_lex_mode = lex_mode_e::VSub_ArgDQ;
  }
  else {
    arg_lex_mode = lex_mode_e::VSub_ArgUnquoted;
  }
  this->_SetNext(lex_mode_e::VSub_1);
  this->_GetToken();
  ty = this->token_type;
  first_tok = this->cur_token;
  if (ty == Id::VSub_Pound) {
    next_id = this->lexer->LookPastSpace(lex_mode_e::VSub_1);
    if ((next_id != Id::Unknown_Tok && next_id != Id::Right_DollarBrace)) {
      this->_SetNext(lex_mode_e::VSub_1);
      part = this->_ParseVarOf();
      this->_GetToken();
      if (this->token_type != Id::Right_DollarBrace) {
        p_die(str1854, this->cur_token);
      }
      part->prefix_op = first_tok;
    }
    else {
      part = this->_ParseVarExpr(arg_lex_mode);
    }
  }
  else {
    if (ty == Id::VSub_Bang) {
      next_id = this->lexer->LookPastSpace(lex_mode_e::VSub_1);
      if ((next_id != Id::Unknown_Tok && next_id != Id::Right_DollarBrace)) {
        this->_SetNext(lex_mode_e::VSub_1);
        part = this->_ParseVarExpr(arg_lex_mode, true);
        part->prefix_op = first_tok;
      }
      else {
        part = this->_ParseVarExpr(arg_lex_mode);
      }
    }
    else {
      if (ty == Id::VSub_Dot) {
        p_die(str1855, this->cur_token);
      }
      else {
        if (this->token_kind == Kind::VSub) {
          part = this->_ParseVarExpr(arg_lex_mode);
        }
        else {
          p_die(str1856, this->cur_token);
        }
      }
    }
  }
  part->left = left_token;
  part->right = this->cur_token;
  return part;
}

syntax_asdl::SingleQuoted* WordParser::_ReadSingleQuoted(syntax_asdl::Token* left_token, types_asdl::lex_mode_t lex_mode) {
  List<syntax_asdl::Token*>* tokens = nullptr;
  syntax_asdl::Token* right_quote = nullptr;
  BigStr* sval = nullptr;
  syntax_asdl::SingleQuoted* node = nullptr;
  StackRoot _root0(&left_token);
  StackRoot _root1(&tokens);
  StackRoot _root2(&right_quote);
  StackRoot _root3(&sval);
  StackRoot _root4(&node);

  tokens = Alloc<List<syntax_asdl::Token*>>();
  right_quote = this->ReadSingleQuoted(lex_mode, left_token, tokens, false);
  sval = word_compile::EvalSingleQuoted(left_token->id, tokens);
  node = Alloc<SingleQuoted>(left_token, sval, right_quote);
  return node;
}

syntax_asdl::Token* WordParser::ReadSingleQuoted(types_asdl::lex_mode_t lex_mode, syntax_asdl::Token* left_token, List<syntax_asdl::Token*>* out_tokens, bool is_ysh_expr) {
  List<syntax_asdl::Token*>* tokens = nullptr;
  bool no_backslashes;
  int expected_end_tokens;
  int num_end_tokens;
  syntax_asdl::Token* tok = nullptr;
  bool is_u_string;
  StackRoot _root0(&left_token);
  StackRoot _root1(&out_tokens);
  StackRoot _root2(&tokens);
  StackRoot _root3(&tok);

  tokens = Alloc<List<syntax_asdl::Token*>>();
  no_backslashes = (is_ysh_expr and left_token->id == Id::Left_SingleQuote);
  expected_end_tokens = (left_token->id == Id::Left_TSingleQuote || left_token->id == Id::Left_RTSingleQuote || left_token->id == Id::Left_UTSingleQuote || left_token->id == Id::Left_BTSingleQuote) ? 3 : 1;
  num_end_tokens = 0;
  while (num_end_tokens < expected_end_tokens) {
    this->_SetNext(lex_mode);
    this->_GetToken();
    if ((this->token_kind == Kind::Lit || this->token_kind == Kind::Char)) {
      tok = this->cur_token;
      if ((no_backslashes and lexer::TokenContains(tok, str1857))) {
        p_die(str1858, tok);
      }
      if (is_ysh_expr) {
        if (this->token_type == Id::Char_Octal3) {
          p_die(str1859, tok);
        }
        if ((this->token_type == Id::Char_Hex and this->cur_token->length != 4)) {
          p_die(str1860, tok);
        }
      }
      tokens->append(tok);
    }
    else {
      if (this->token_kind == Kind::Unknown) {
        tok = this->cur_token;
        if ((is_ysh_expr or !this->parse_opts->parse_backslash())) {
          p_die(str1861, tok);
        }
        tokens->append(tok);
      }
      else {
        if (this->token_kind == Kind::Eof) {
          p_die(str1862, left_token);
        }
        else {
          if (this->token_kind == Kind::Right) {
            num_end_tokens += 1;
            tokens->append(this->cur_token);
          }
          else {
            assert(0);  // AssertionError
          }
        }
      }
    }
    if (this->token_kind != Kind::Right) {
      num_end_tokens = 0;
    }
  }
  if (expected_end_tokens == 1) {
    tokens->pop();
  }
  else {
    if (expected_end_tokens == 3) {
      tokens->pop();
      tokens->pop();
      tokens->pop();
    }
  }
  if ((left_token->id == Id::Left_TSingleQuote || left_token->id == Id::Left_RTSingleQuote || left_token->id == Id::Left_UTSingleQuote || left_token->id == Id::Left_BTSingleQuote)) {
    word_compile::RemoveLeadingSpaceSQ(tokens);
  }
  is_u_string = (left_token->id == Id::Left_USingleQuote || left_token->id == Id::Left_UTSingleQuote);
  for (ListIter<syntax_asdl::Token*> it(tokens); !it.Done(); it.Next()) {
    syntax_asdl::Token* tok = it.Value();
    StackRoot _for(&tok  );
    if ((is_u_string and tok->id == Id::Char_YHex)) {
      p_die(StrFormat("%s escapes not allowed in u'' strings", lexer::TokenVal(tok)), tok);
    }
  }
  out_tokens->extend(tokens);
  return this->cur_token;
}

syntax_asdl::word_part_t* WordParser::_ReadDoubleQuotedLeftParts() {
  if ((this->token_type == Id::Left_DollarParen || this->token_type == Id::Left_Backtick)) {
    return this->_ReadCommandSub(this->token_type, true);
  }
  if (this->token_type == Id::Left_DollarBrace) {
    return this->_ReadBracedVarSub(this->cur_token, true);
  }
  if (this->token_type == Id::Left_DollarDParen) {
    return this->_ReadArithSub();
  }
  if (this->token_type == Id::Left_DollarBracket) {
    return this->_ReadExprSub(lex_mode_e::DQ);
  }
  assert(0);  // AssertionError
}

syntax_asdl::CompoundWord* WordParser::_ReadYshSingleQuoted(int left_id) {
  types_asdl::lex_mode_t lexer_mode;
  int triple_left_id;
  syntax_asdl::Token* left_tok = nullptr;
  syntax_asdl::SingleQuoted* sq_part = nullptr;
  StackRoot _root0(&left_tok);
  StackRoot _root1(&sq_part);

  if (left_id == Id::Left_RSingleQuote) {
    lexer_mode = lex_mode_e::SQ_Raw;
    triple_left_id = Id::Left_RTSingleQuote;
  }
  else {
    if (left_id == Id::Left_USingleQuote) {
      lexer_mode = lex_mode_e::J8_Str;
      triple_left_id = Id::Left_UTSingleQuote;
    }
    else {
      if (left_id == Id::Left_BSingleQuote) {
        lexer_mode = lex_mode_e::J8_Str;
        triple_left_id = Id::Left_BTSingleQuote;
      }
      else {
        assert(0);  // AssertionError
      }
    }
  }
  left_tok = this->cur_token;
  left_tok->id = left_id;
  sq_part = this->_ReadSingleQuoted(left_tok, lexer_mode);
  if ((len(sq_part->sval) == 0 and str_equals(this->lexer->ByteLookAhead(), str1864))) {
    this->_SetNext(lex_mode_e::ShCommand);
    this->_GetToken();
    left_tok = this->cur_token;
    left_tok->id = triple_left_id;
    sq_part = this->_ReadSingleQuoted(left_tok, lexer_mode);
  }
  this->_SetNext(lex_mode_e::ShCommand);
  this->_GetToken();
  if (!list_contains(KINDS_THAT_END_WORDS, this->token_kind)) {
    p_die(str1865, this->cur_token);
  }
  return Alloc<CompoundWord>(NewList<syntax_asdl::word_part_t*>(std::initializer_list<syntax_asdl::word_part_t*>{sq_part}));
}

syntax_asdl::word_part_t* WordParser::_ReadUnquotedLeftParts(syntax_asdl::BoolParamBox* triple_out) {
  syntax_asdl::DoubleQuoted* dq_part = nullptr;
  syntax_asdl::Token* left_dq_token = nullptr;
  types_asdl::lex_mode_t lexer_mode;
  int triple_left_id;
  syntax_asdl::SingleQuoted* sq_part = nullptr;
  syntax_asdl::Token* left_sq_token = nullptr;
  StackRoot _root0(&triple_out);
  StackRoot _root1(&dq_part);
  StackRoot _root2(&left_dq_token);
  StackRoot _root3(&sq_part);
  StackRoot _root4(&left_sq_token);

  if ((this->token_type == Id::Left_DoubleQuote || this->token_type == Id::Left_DollarDoubleQuote)) {
    dq_part = this->_ReadDoubleQuoted(this->cur_token);
    if ((triple_out and (len(dq_part->parts) == 0 and str_equals(this->lexer->ByteLookAhead(), str1866)))) {
      this->_SetNext(lex_mode_e::ShCommand);
      this->_GetToken();
      left_dq_token = this->cur_token;
      left_dq_token->id = Id::Left_TDoubleQuote;
      triple_out->b = true;
      return this->_ReadDoubleQuoted(left_dq_token);
    }
    return dq_part;
  }
  if ((this->token_type == Id::Left_SingleQuote || this->token_type == Id::Left_RSingleQuote || this->token_type == Id::Left_DollarSingleQuote)) {
    if (this->token_type == Id::Left_SingleQuote) {
      lexer_mode = lex_mode_e::SQ_Raw;
      triple_left_id = Id::Left_TSingleQuote;
    }
    else {
      if (this->token_type == Id::Left_RSingleQuote) {
        lexer_mode = lex_mode_e::SQ_Raw;
        triple_left_id = Id::Left_RTSingleQuote;
      }
      else {
        lexer_mode = lex_mode_e::SQ_C;
        triple_left_id = Id::Undefined_Tok;
      }
    }
    sq_part = this->_ReadSingleQuoted(this->cur_token, lexer_mode);
    if ((triple_left_id != Id::Undefined_Tok and (triple_out != nullptr and (len(sq_part->sval) == 0 and str_equals(this->lexer->ByteLookAhead(), str1867))))) {
      this->_SetNext(lex_mode_e::ShCommand);
      this->_GetToken();
      left_sq_token = this->cur_token;
      left_sq_token->id = triple_left_id;
      triple_out->b = true;
      return this->_ReadSingleQuoted(left_sq_token, lexer_mode);
    }
    return sq_part;
  }
  if ((this->token_type == Id::Left_DollarParen || this->token_type == Id::Left_Backtick || this->token_type == Id::Left_ProcSubIn || this->token_type == Id::Left_ProcSubOut)) {
    return this->_ReadCommandSub(this->token_type, false);
  }
  if (this->token_type == Id::Left_DollarBrace) {
    return this->_ReadBracedVarSub(this->cur_token, false);
  }
  if (this->token_type == Id::Left_DollarDParen) {
    return this->_ReadArithSub();
  }
  if (this->token_type == Id::Left_DollarBracket) {
    return this->_ReadExprSub(lex_mode_e::ShCommand);
  }
  if (this->token_type == Id::Left_DollarBraceZsh) {
    return this->_ReadZshVarSub(this->cur_token);
  }
  assert(0);  // AssertionError
}

word_part::ExtGlob* WordParser::_ReadExtGlob() {
  syntax_asdl::Token* left_token = nullptr;
  syntax_asdl::Token* right_token = nullptr;
  List<syntax_asdl::CompoundWord*>* arms = nullptr;
  bool read_word;
  syntax_asdl::CompoundWord* w = nullptr;
  StackRoot _root0(&left_token);
  StackRoot _root1(&right_token);
  StackRoot _root2(&arms);
  StackRoot _root3(&w);

  left_token = this->cur_token;
  right_token = nullptr;
  arms = Alloc<List<syntax_asdl::CompoundWord*>>();
  this->lexer->PushHint(Id::Op_RParen, Id::Right_ExtGlob);
  this->_SetNext(lex_mode_e::ExtGlob);
  read_word = false;
  while (true) {
    this->_GetToken();
    if (this->token_type == Id::Right_ExtGlob) {
      if (!read_word) {
        arms->append(Alloc<CompoundWord>(Alloc<List<syntax_asdl::word_part_t*>>()));
      }
      right_token = this->cur_token;
      break;
    }
    else {
      if (this->token_type == Id::Op_Pipe) {
        if (!read_word) {
          arms->append(Alloc<CompoundWord>(Alloc<List<syntax_asdl::word_part_t*>>()));
        }
        read_word = false;
        this->_SetNext(lex_mode_e::ExtGlob);
      }
      else {
        if ((this->token_kind == Kind::Lit || this->token_kind == Kind::Left || this->token_kind == Kind::VSub || this->token_kind == Kind::ExtGlob)) {
          w = this->_ReadCompoundWord(lex_mode_e::ExtGlob);
          arms->append(w);
          read_word = true;
        }
        else {
          if (this->token_kind == Kind::Eof) {
            p_die(str1868, left_token);
          }
          else {
            assert(0);  // AssertionError
          }
        }
      }
    }
  }
  return Alloc<word_part::ExtGlob>(left_token, arms, right_token);
}

word_part::BashRegexGroup* WordParser::_ReadBashRegexGroup() {
  syntax_asdl::Token* left_token = nullptr;
  syntax_asdl::Token* right_token = nullptr;
  List<syntax_asdl::CompoundWord*>* arms = nullptr;
  syntax_asdl::CompoundWord* w = nullptr;
  StackRoot _root0(&left_token);
  StackRoot _root1(&right_token);
  StackRoot _root2(&arms);
  StackRoot _root3(&w);

  left_token = this->cur_token;
  right_token = nullptr;
  arms = Alloc<List<syntax_asdl::CompoundWord*>>();
  this->lexer->PushHint(Id::Op_RParen, Id::Right_BashRegexGroup);
  this->_SetNext(lex_mode_e::BashRegexFakeInner);
  this->_GetToken();
  if (this->token_type == Id::Right_BashRegexGroup) {
    return Alloc<word_part::BashRegexGroup>(left_token, nullptr, this->cur_token);
  }
  if ((this->token_kind == Kind::Lit || this->token_kind == Kind::Left || this->token_kind == Kind::VSub || this->token_kind == Kind::BashRegex)) {
    w = this->_ReadCompoundWord(lex_mode_e::BashRegexFakeInner);
    arms->append(w);
    this->_GetToken();
    if (this->token_type != Id::Right_BashRegexGroup) {
      p_die(str1869, this->cur_token);
    }
    return Alloc<word_part::BashRegexGroup>(left_token, w, this->cur_token);
  }
  p_die(str1870, this->cur_token);
}

void WordParser::_ReadLikeDQ(syntax_asdl::Token* left_token, bool is_ysh_expr, List<syntax_asdl::word_part_t*>* out_parts) {
  int expected_end_tokens;
  int num_end_tokens;
  syntax_asdl::Token* tok = nullptr;
  BigStr* ch = nullptr;
  syntax_asdl::word_part_t* part = nullptr;
  StackRoot _root0(&left_token);
  StackRoot _root1(&out_parts);
  StackRoot _root2(&tok);
  StackRoot _root3(&ch);
  StackRoot _root4(&part);

  if (left_token) {
    if ((left_token->id == Id::Left_TDoubleQuote || left_token->id == Id::Left_DollarTDoubleQuote)) {
      expected_end_tokens = 3;
    }
    else {
      expected_end_tokens = 1;
    }
  }
  else {
    expected_end_tokens = 1000;
  }
  num_end_tokens = 0;
  while (num_end_tokens < expected_end_tokens) {
    this->_SetNext(lex_mode_e::DQ);
    this->_GetToken();
    if (this->token_kind == Kind::Lit) {
      if (this->token_type == Id::Lit_EscapedChar) {
        tok = this->cur_token;
        ch = lexer::TokenSliceLeft(tok, 1);
        part = Alloc<word_part::EscapedLiteral>(tok, ch);
      }
      else {
        if (this->token_type == Id::Lit_BadBackslash) {
          if ((is_ysh_expr or !this->parse_opts->parse_backslash())) {
            p_die(str1871, this->cur_token);
          }
        }
        else {
          if (this->token_type == Id::Lit_Dollar) {
            if ((is_ysh_expr or !this->parse_opts->parse_dollar())) {
              p_die(str1872, this->cur_token);
            }
          }
        }
        part = this->cur_token;
      }
      out_parts->append(part);
    }
    else {
      if (this->token_kind == Kind::Left) {
        if ((this->token_type == Id::Left_Backtick and is_ysh_expr)) {
          p_die(str1873, this->cur_token);
        }
        part = this->_ReadDoubleQuotedLeftParts();
        out_parts->append(part);
      }
      else {
        if (this->token_kind == Kind::VSub) {
          tok = this->cur_token;
          part = Alloc<SimpleVarSub>(tok);
          out_parts->append(part);
        }
        else {
          if (this->token_kind == Kind::Right) {
            if (left_token) {
              num_end_tokens += 1;
            }
            out_parts->append(this->cur_token);
          }
          else {
            if (this->token_kind == Kind::Eof) {
              if (left_token) {
                p_die(str1874, left_token);
              }
              else {
                break;
              }
            }
            else {
              assert(0);  // AssertionError
            }
          }
        }
      }
    }
    if (this->token_kind != Kind::Right) {
      num_end_tokens = 0;
    }
  }
  if (expected_end_tokens == 1) {
    out_parts->pop();
  }
  else {
    if (expected_end_tokens == 3) {
      out_parts->pop();
      out_parts->pop();
      out_parts->pop();
    }
  }
  if ((left_token and (left_token->id == Id::Left_TDoubleQuote || left_token->id == Id::Left_DollarTDoubleQuote))) {
    word_compile::RemoveLeadingSpaceDQ(out_parts);
  }
}

syntax_asdl::DoubleQuoted* WordParser::_ReadDoubleQuoted(syntax_asdl::Token* left_token) {
  List<syntax_asdl::word_part_t*>* parts = nullptr;
  syntax_asdl::Token* right_quote = nullptr;
  StackRoot _root0(&left_token);
  StackRoot _root1(&parts);
  StackRoot _root2(&right_quote);

  parts = Alloc<List<syntax_asdl::word_part_t*>>();
  this->_ReadLikeDQ(left_token, false, parts);
  right_quote = this->cur_token;
  return Alloc<DoubleQuoted>(left_token, parts, right_quote);
}

syntax_asdl::Token* WordParser::ReadDoubleQuoted(syntax_asdl::Token* left_token, List<syntax_asdl::word_part_t*>* parts) {
  StackRoot _root0(&left_token);
  StackRoot _root1(&parts);

  this->_ReadLikeDQ(left_token, true, parts);
  return this->cur_token;
}

syntax_asdl::CommandSub* WordParser::_ReadCommandSub(int left_id, bool d_quoted) {
  syntax_asdl::Token* left_token = nullptr;
  int right_id;
  cmd_parse::CommandParser* c_parser = nullptr;
  syntax_asdl::command_t* node = nullptr;
  syntax_asdl::Token* right_token = nullptr;
  List<BigStr*>* parts = nullptr;
  BigStr* code_str = nullptr;
  alloc::Arena* arena = nullptr;
  reader::FileLineReader* line_reader = nullptr;
  source::Reparsed* src = nullptr;
  StackRoot _root0(&left_token);
  StackRoot _root1(&c_parser);
  StackRoot _root2(&node);
  StackRoot _root3(&right_token);
  StackRoot _root4(&parts);
  StackRoot _root5(&code_str);
  StackRoot _root6(&arena);
  StackRoot _root7(&line_reader);
  StackRoot _root8(&src);

  left_token = this->cur_token;
  if ((left_id == Id::Left_DollarParen || left_id == Id::Left_AtParen || left_id == Id::Left_ProcSubIn || left_id == Id::Left_ProcSubOut)) {
    this->_SetNext(lex_mode_e::ShCommand);
    right_id = Id::Eof_RParen;
    this->lexer->PushHint(Id::Op_RParen, right_id);
    c_parser = this->parse_ctx->MakeParserForCommandSub(this->line_reader, this->lexer, right_id);
    node = c_parser->ParseCommandSub();
    right_token = c_parser->w_parser->cur_token;
  }
  else {
    if ((left_id == Id::Left_Backtick and this->parse_ctx->do_lossless)) {
      right_id = Id::Eof_Backtick;
      this->lexer->PushHint(Id::Left_Backtick, right_id);
      c_parser = this->parse_ctx->MakeParserForCommandSub(this->line_reader, this->lexer, right_id);
      node = c_parser->ParseCommandSub();
      right_token = c_parser->w_parser->cur_token;
    }
    else {
      if (left_id == Id::Left_Backtick) {
        if (!this->parse_opts->parse_backticks()) {
          p_die(str1875, left_token);
        }
        this->_SetNext(lex_mode_e::Backtick);
        parts = Alloc<List<BigStr*>>();
        while (true) {
          this->_GetToken();
          if (this->token_type == Id::Backtick_Quoted) {
            parts->append(lexer::TokenSliceLeft(this->cur_token, 1));
          }
          else {
            if (this->token_type == Id::Backtick_DoubleQuote) {
              if (d_quoted) {
                parts->append(lexer::TokenSliceLeft(this->cur_token, 1));
              }
              else {
                parts->append(lexer::TokenVal(this->cur_token));
              }
            }
            else {
              if (this->token_type == Id::Backtick_Other) {
                parts->append(lexer::TokenVal(this->cur_token));
              }
              else {
                if (this->token_type == Id::Backtick_Right) {
                  break;
                }
                else {
                  if (this->token_type == Id::Eof_Real) {
                    p_die(str1876, left_token);
                  }
                  else {
                    assert(0);  // AssertionError
                  }
                }
              }
            }
          }
          this->_SetNext(lex_mode_e::Backtick);
        }
        right_token = this->cur_token;
        code_str = str1877->join(parts);
        arena = this->parse_ctx->arena;
        line_reader = reader::StringLineReader(code_str, arena);
        c_parser = this->parse_ctx->MakeOshParser(line_reader);
        src = Alloc<source::Reparsed>(str1878, left_token, right_token);
        {  // with
          alloc::ctx_SourceCode ctx{arena, src};

          node = c_parser->ParseCommandSub();
        }
      }
      else {
        assert(0);  // AssertionError
      }
    }
  }
  return Alloc<CommandSub>(left_token, node, right_token);
}

word_part::ExprSub* WordParser::_ReadExprSub(types_asdl::lex_mode_t lex_mode) {
  syntax_asdl::Token* left_token = nullptr;
  syntax_asdl::expr_t* enode = nullptr;
  syntax_asdl::Token* right_token = nullptr;
  StackRoot _root0(&left_token);
  StackRoot _root1(&enode);
  StackRoot _root2(&right_token);

  left_token = this->cur_token;
  this->_SetNext(lex_mode_e::Expr);
  Tuple2<syntax_asdl::expr_t*, syntax_asdl::Token*> tup1 = this->parse_ctx->ParseYshExpr(this->lexer, grammar_nt::ysh_expr_sub);
  enode = tup1.at0();
  right_token = tup1.at1();
  this->_SetNext(lex_mode);
  return Alloc<word_part::ExprSub>(left_token, enode, right_token);
}

command::VarDecl* WordParser::ParseVarDecl(syntax_asdl::Token* kw_token) {
  command::VarDecl* enode = nullptr;
  syntax_asdl::Token* last_token = nullptr;
  StackRoot _root0(&kw_token);
  StackRoot _root1(&enode);
  StackRoot _root2(&last_token);

  this->_SetNext(lex_mode_e::Expr);
  Tuple2<command::VarDecl*, syntax_asdl::Token*> tup2 = this->parse_ctx->ParseVarDecl(kw_token, this->lexer);
  enode = tup2.at0();
  last_token = tup2.at1();
  if (last_token->id == Id::Op_RBrace) {
    last_token->id = Id::Lit_RBrace;
  }
  this->buffered_word = last_token;
  this->_SetNext(lex_mode_e::ShCommand);
  return enode;
}

command::Mutation* WordParser::ParseMutation(syntax_asdl::Token* kw_token, cmd_parse::VarChecker* var_checker) {
  command::Mutation* enode = nullptr;
  syntax_asdl::Token* last_token = nullptr;
  syntax_asdl::y_lhs_t* UP_lhs = nullptr;
  expr::Var* v = nullptr;
  StackRoot _root0(&kw_token);
  StackRoot _root1(&var_checker);
  StackRoot _root2(&enode);
  StackRoot _root3(&last_token);
  StackRoot _root4(&UP_lhs);
  StackRoot _root5(&v);

  this->_SetNext(lex_mode_e::Expr);
  Tuple2<command::Mutation*, syntax_asdl::Token*> tup3 = this->parse_ctx->ParseMutation(kw_token, this->lexer);
  enode = tup3.at0();
  last_token = tup3.at1();
  if (last_token->id == Id::Op_RBrace) {
    last_token->id = Id::Lit_RBrace;
  }
  for (ListIter<syntax_asdl::y_lhs_t*> it(enode->lhs); !it.Done(); it.Next()) {
    syntax_asdl::y_lhs_t* lhs = it.Value();
    StackRoot _for(&lhs  );
    UP_lhs = lhs;
    switch (lhs->tag()) {
      case y_lhs_e::Var: {
        Token* lhs = static_cast<Token*>(UP_lhs);
        var_checker->Check(kw_token->id, lexer::LazyStr(lhs), lhs);
      }
        break;
      case y_lhs_e::Subscript: {
        Subscript* lhs = static_cast<Subscript*>(UP_lhs);
        if (lhs->obj->tag() == expr_e::Var) {
          v = static_cast<expr::Var*>(lhs->obj);
          var_checker->Check(kw_token->id, v->name, v->left);
        }
      }
        break;
      case y_lhs_e::Attribute: {
        Attribute* lhs = static_cast<Attribute*>(UP_lhs);
        if (lhs->obj->tag() == expr_e::Var) {
          v = static_cast<expr::Var*>(lhs->obj);
          var_checker->Check(kw_token->id, v->name, v->left);
        }
      }
        break;
    }
  }
  this->buffered_word = last_token;
  this->_SetNext(lex_mode_e::ShCommand);
  return enode;
}

syntax_asdl::expr_t* WordParser::ParseBareDecl() {
  syntax_asdl::expr_t* enode = nullptr;
  syntax_asdl::Token* last_token = nullptr;
  StackRoot _root0(&enode);
  StackRoot _root1(&last_token);

  this->_SetNext(lex_mode_e::Expr);
  this->_GetToken();
  Tuple2<syntax_asdl::expr_t*, syntax_asdl::Token*> tup4 = this->parse_ctx->ParseYshExpr(this->lexer, grammar_nt::command_expr);
  enode = tup4.at0();
  last_token = tup4.at1();
  if (last_token->id == Id::Op_RBrace) {
    last_token->id = Id::Lit_RBrace;
  }
  this->buffered_word = last_token;
  this->_SetNext(lex_mode_e::ShCommand);
  return enode;
}

syntax_asdl::expr_t* WordParser::ParseYshExprForCommand() {
  syntax_asdl::expr_t* enode = nullptr;
  StackRoot _root0(&enode);

  if (this->token_type == Id::Op_LParen) {
    this->lexer->MaybeUnreadOne();
  }
  Tuple2<syntax_asdl::expr_t*, syntax_asdl::Token*> tup5 = this->parse_ctx->ParseYshExpr(this->lexer, grammar_nt::ysh_expr);
  enode = tup5.at0();
  this->_SetNext(lex_mode_e::ShCommand);
  return enode;
}

syntax_asdl::expr_t* WordParser::ParseCommandExpr() {
  syntax_asdl::expr_t* enode = nullptr;
  syntax_asdl::Token* last_token = nullptr;
  StackRoot _root0(&enode);
  StackRoot _root1(&last_token);

  Tuple2<syntax_asdl::expr_t*, syntax_asdl::Token*> tup6 = this->parse_ctx->ParseYshExpr(this->lexer, grammar_nt::command_expr);
  enode = tup6.at0();
  last_token = tup6.at1();
  if (last_token->id != Id::Eof_Real) {
    this->lexer->MaybeUnreadOne();
  }
  return enode;
}

void WordParser::ParseProc(syntax_asdl::Proc* node) {
  syntax_asdl::Token* last_token = nullptr;
  StackRoot _root0(&node);
  StackRoot _root1(&last_token);

  this->_SetNext(lex_mode_e::ShCommand);
  this->_GetToken();
  if (this->token_type != Id::Lit_Chars) {
    p_die(StrFormat("Invalid proc name %s", ui::PrettyToken(this->cur_token)), this->cur_token);
  }
  node->name = this->cur_token;
  last_token = this->parse_ctx->ParseProc(this->lexer, node);
  last_token->id = Id::Lit_LBrace;
  this->buffered_word = last_token;
  this->_SetNext(lex_mode_e::ShCommand);
}

void WordParser::ParseFunc(syntax_asdl::Func* node) {
  syntax_asdl::Token* last_token = nullptr;
  StackRoot _root0(&node);
  StackRoot _root1(&last_token);

  last_token = this->parse_ctx->ParseFunc(this->lexer, node);
  last_token->id = Id::Lit_LBrace;
  this->buffered_word = last_token;
  this->_SetNext(lex_mode_e::ShCommand);
}

Tuple2<syntax_asdl::pat_t*, syntax_asdl::Token*> WordParser::ParseYshCasePattern() {
  syntax_asdl::pat_t* pat = nullptr;
  syntax_asdl::Token* left_tok = nullptr;
  syntax_asdl::Token* last_token = nullptr;
  StackRoot _root0(&pat);
  StackRoot _root1(&left_tok);
  StackRoot _root2(&last_token);

  Tuple3<syntax_asdl::pat_t*, syntax_asdl::Token*, syntax_asdl::Token*> tup7 = this->parse_ctx->ParseYshCasePattern(this->lexer);
  pat = tup7.at0();
  left_tok = tup7.at1();
  last_token = tup7.at2();
  if (last_token->id == Id::Op_LBrace) {
    last_token->id = Id::Lit_LBrace;
  }
  this->buffered_word = last_token;
  return Tuple2<syntax_asdl::pat_t*, syntax_asdl::Token*>(pat, left_tok);
}

int WordParser::NewlineOkForYshCase() {
  int next_id;
  id_kind_asdl::Kind_t next_kind;
  while (true) {
    next_id = this->lexer->LookAheadOne(lex_mode_e::Expr);
    if (next_id == Id::Unknown_Tok) {
      this->lexer->MoveToNextLine();
      continue;
    }
    next_kind = consts::GetKind(next_id);
    if ((next_id != Id::Op_Newline and next_kind != Kind::Ignored)) {
      break;
    }
    this->lexer->Read(lex_mode_e::Expr);
  }
  if ((next_id == Id::Op_RBrace || next_id == Id::Op_LParen || next_id == Id::Arith_Slash)) {
    this->_SetNext(lex_mode_e::Expr);
  }
  else {
    this->_SetNext(lex_mode_e::ShCommand);
    this->_GetToken();
  }
  return next_id;
}

syntax_asdl::arith_expr_t* WordParser::_ReadArithExpr(int end_id) {
  syntax_asdl::arith_expr_t* anode = nullptr;
  int cur_id;
  StackRoot _root0(&anode);

  anode = this->a_parser->Parse();
  cur_id = this->a_parser->CurrentId();
  if ((end_id != Id::Undefined_Tok and cur_id != end_id)) {
    p_die(StrFormat("Unexpected token after arithmetic expression (%s != %s)", ui::PrettyId(cur_id), ui::PrettyId(end_id)), Alloc<loc::Word>(this->a_parser->cur_word));
  }
  return anode;
}

word_part::ArithSub* WordParser::_ReadArithSub() {
  syntax_asdl::Token* left_tok = nullptr;
  syntax_asdl::arith_expr_t* anode = nullptr;
  syntax_asdl::Token* right_tok = nullptr;
  StackRoot _root0(&left_tok);
  StackRoot _root1(&anode);
  StackRoot _root2(&right_tok);

  left_tok = this->cur_token;
  this->lexer->PushHint(Id::Op_RParen, Id::Right_DollarDParen);
  anode = arith_expr::EmptyZero;
  this->_NextNonSpace();
  if (this->token_type != Id::Arith_RParen) {
    anode = this->_ReadArithExpr(Id::Arith_RParen);
  }
  this->_SetNext(lex_mode_e::ShCommand);
  this->_GetToken();
  if (this->token_type != Id::Right_DollarDParen) {
    p_die(str1881, this->cur_token);
  }
  right_tok = this->cur_token;
  return Alloc<word_part::ArithSub>(left_tok, anode, right_tok);
}

Tuple2<syntax_asdl::arith_expr_t*, syntax_asdl::Token*> WordParser::ReadDParen() {
  syntax_asdl::arith_expr_t* anode = nullptr;
  syntax_asdl::Token* right = nullptr;
  StackRoot _root0(&anode);
  StackRoot _root1(&right);

  anode = arith_expr::EmptyZero;
  this->lexer->PushHint(Id::Op_RParen, Id::Op_DRightParen);
  this->_NextNonSpace();
  if (this->token_type != Id::Arith_RParen) {
    anode = this->_ReadArithExpr(Id::Arith_RParen);
  }
  this->_SetNext(lex_mode_e::ShCommand);
  this->_GetToken();
  right = this->cur_token;
  if (right->id != Id::Op_DRightParen) {
    p_die(str1882, right);
  }
  this->_SetNext(lex_mode_e::ShCommand);
  return Tuple2<syntax_asdl::arith_expr_t*, syntax_asdl::Token*>(anode, right);
}

void WordParser::_NextNonSpace() {
  while (true) {
    this->_SetNext(lex_mode_e::Arith);
    this->_GetToken();
    if ((this->token_kind != Kind::Ignored && this->token_kind != Kind::WS)) {
      break;
    }
  }
}

command::ForExpr* WordParser::ReadForExpression() {
  int cur_id;
  syntax_asdl::arith_expr_t* init_node = nullptr;
  syntax_asdl::arith_expr_t* cond_node = nullptr;
  syntax_asdl::arith_expr_t* update_node = nullptr;
  command::ForExpr* node = nullptr;
  StackRoot _root0(&init_node);
  StackRoot _root1(&cond_node);
  StackRoot _root2(&update_node);
  StackRoot _root3(&node);

  this->_NextNonSpace();
  cur_id = this->token_type;
  if (cur_id == Id::Arith_Semi) {
    init_node = arith_expr::EmptyZero;
  }
  else {
    init_node = this->a_parser->Parse();
    cur_id = this->a_parser->CurrentId();
  }
  this->_NextNonSpace();
  if (cur_id != Id::Arith_Semi) {
    p_die(str1883, Alloc<loc::Word>(this->a_parser->cur_word));
  }
  this->_GetToken();
  cur_id = this->token_type;
  if (cur_id == Id::Arith_Semi) {
    cond_node = arith_expr::EmptyOne;
  }
  else {
    cond_node = this->a_parser->Parse();
    cur_id = this->a_parser->CurrentId();
  }
  if (cur_id != Id::Arith_Semi) {
    p_die(str1884, Alloc<loc::Word>(this->a_parser->cur_word));
  }
  this->_NextNonSpace();
  if (this->token_type == Id::Arith_RParen) {
    update_node = arith_expr::EmptyZero;
  }
  else {
    update_node = this->_ReadArithExpr(Id::Arith_RParen);
  }
  this->_NextNonSpace();
  if (this->token_type != Id::Arith_RParen) {
    p_die(str1885, this->cur_token);
  }
  this->_SetNext(lex_mode_e::ShCommand);
  node = command::ForExpr::CreateNull();
  node->init = init_node;
  node->cond = cond_node;
  node->update = update_node;
  return node;
}

syntax_asdl::word_part_t* WordParser::_ReadArrayLiteral() {
  syntax_asdl::Token* left_token = nullptr;
  syntax_asdl::Token* right_token = nullptr;
  word_parse::WordParser* w_parser = nullptr;
  List<syntax_asdl::CompoundWord*>* words = nullptr;
  bool done;
  syntax_asdl::word_t* w = nullptr;
  Token* tok = nullptr;
  List<syntax_asdl::word_t*>* no_words = nullptr;
  syntax_asdl::ShArrayLiteral* node = nullptr;
  List<syntax_asdl::AssocPair*>* pairs = nullptr;
  syntax_asdl::AssocPair* pair = nullptr;
  int n;
  syntax_asdl::CompoundWord* w2 = nullptr;
  List<syntax_asdl::word_t*>* words2 = nullptr;
  List<syntax_asdl::word_t*>* words3 = nullptr;
  StackRoot _root0(&left_token);
  StackRoot _root1(&right_token);
  StackRoot _root2(&w_parser);
  StackRoot _root3(&words);
  StackRoot _root4(&w);
  StackRoot _root5(&tok);
  StackRoot _root6(&no_words);
  StackRoot _root7(&node);
  StackRoot _root8(&pairs);
  StackRoot _root9(&pair);
  StackRoot _root10(&w2);
  StackRoot _root11(&words2);
  StackRoot _root12(&words3);

  this->_SetNext(lex_mode_e::ShCommand);
  this->_GetToken();
  if (this->cur_token->id != Id::Op_LParen) {
    p_die(str1886, this->cur_token);
  }
  left_token = this->cur_token;
  right_token = nullptr;
  w_parser = this->parse_ctx->MakeWordParser(this->lexer, this->line_reader);
  words = Alloc<List<syntax_asdl::CompoundWord*>>();
  done = false;
  while (!done) {
    w = w_parser->ReadWord(lex_mode_e::ShCommand);
    switch (w->tag()) {
      case word_e::Operator: {
        tok = static_cast<Token*>(w);
        if (tok->id == Id::Right_ShArrayLiteral) {
          right_token = tok;
          done = true;
        }
        else {
          if (tok->id == Id::Op_Newline) {
            continue;
          }
          else {
            p_die(str1887, Alloc<loc::Word>(w));
          }
        }
      }
        break;
      case word_e::Compound: {
        words->append(static_cast<CompoundWord*>(w));
      }
        break;
      default: {
        assert(0);  // AssertionError
      }
    }
  }
  if (len(words) == 0) {
    no_words = Alloc<List<syntax_asdl::word_t*>>();
    node = Alloc<ShArrayLiteral>(left_token, no_words, right_token);
    return node;
  }
  pairs = Alloc<List<syntax_asdl::AssocPair*>>();
  pair = word_::DetectAssocPair(words->at(0));
  if (pair) {
    pairs->append(pair);
    n = len(words);
    for (int i = 1; i < n; ++i) {
      w2 = words->at(i);
      pair = word_::DetectAssocPair(w2);
      if (!pair) {
        p_die(str1888, Alloc<loc::Word>(w2));
      }
      pairs->append(pair);
    }
    return Alloc<word_part::BashAssocLiteral>(left_token, pairs, right_token);
  }
  words2 = braces::BraceDetectAll(words);
  words3 = word_::TildeDetectAll(words2);
  return Alloc<ShArrayLiteral>(left_token, words3, right_token);
}

syntax_asdl::ArgList* WordParser::ParseProcCallArgs(int start_symbol) {
  syntax_asdl::ArgList* arg_list = nullptr;
  StackRoot _root0(&arg_list);

  this->lexer->MaybeUnreadOne();
  arg_list = ArgList::CreateNull(true);
  arg_list->left = this->cur_token;
  this->parse_ctx->ParseProcCallArgs(this->lexer, arg_list, start_symbol);
  return arg_list;
}

bool WordParser::_MaybeReadWordPart(bool is_first, types_asdl::lex_mode_t lex_mode, List<syntax_asdl::word_part_t*>* parts) {
  bool done;
  syntax_asdl::Token* tok = nullptr;
  BigStr* ch = nullptr;
  syntax_asdl::word_part_t* part = nullptr;
  int next_id;
  syntax_asdl::word_part_t* part2 = nullptr;
  syntax_asdl::Token* splice_tok = nullptr;
  StackRoot _root0(&parts);
  StackRoot _root1(&tok);
  StackRoot _root2(&ch);
  StackRoot _root3(&part);
  StackRoot _root4(&part2);
  StackRoot _root5(&splice_tok);

  done = false;
  if (this->token_type == Id::Lit_EscapedChar) {
    tok = this->cur_token;
    ch = lexer::TokenSliceLeft(tok, 1);
    if (!this->parse_opts->parse_backslash()) {
      if (!pyutil::IsValidCharEscape(ch)) {
        p_die(str1889, this->cur_token);
      }
    }
    part = Alloc<word_part::EscapedLiteral>(this->cur_token, ch);
  }
  else {
    part = this->cur_token;
  }
  if ((is_first and this->token_type == Id::Lit_VarLike)) {
    parts->append(part);
    next_id = this->lexer->LookPastSpace(lex_mode);
    if (next_id == Id::Op_LParen) {
      this->lexer->PushHint(Id::Op_RParen, Id::Right_ShArrayLiteral);
      part2 = this->_ReadArrayLiteral();
      parts->append(part2);
      this->_SetNext(lex_mode);
      this->_GetToken();
      if (!list_contains(KINDS_THAT_END_WORDS, this->token_kind)) {
        p_die(str1890, this->cur_token);
      }
      done = true;
    }
  }
  else {
    if ((is_first and (this->parse_opts->parse_at() and this->token_type == Id::Lit_Splice))) {
      splice_tok = this->cur_token;
      part2 = Alloc<word_part::Splice>(splice_tok, lexer::TokenSliceLeft(splice_tok, 1));
      parts->append(part2);
      this->_SetNext(lex_mode);
      this->_GetToken();
      if (!list_contains(KINDS_THAT_END_WORDS, this->token_kind)) {
        p_die(str1891, this->cur_token);
      }
      done = true;
    }
    else {
      if ((is_first and (this->parse_opts->parse_at() and this->token_type == Id::Lit_AtLBracket))) {
        part2 = this->_ReadExprSub(lex_mode_e::DQ);
        parts->append(part2);
        this->_SetNext(lex_mode);
        this->_GetToken();
        if (!list_contains(KINDS_THAT_END_WORDS, this->token_kind)) {
          p_die(str1892, this->cur_token);
        }
        done = true;
      }
      else {
        if ((is_first and (this->parse_opts->parse_at() and this->token_type == Id::Lit_AtLBraceDot))) {
          p_die(str1893, this->cur_token);
        }
        else {
          if ((is_first and (this->parse_opts->parse_at_all() and this->token_type == Id::Lit_At))) {
            p_die(str1894, this->cur_token);
          }
          else {
            parts->append(part);
          }
        }
      }
    }
  }
  return done;
}

syntax_asdl::CompoundWord* WordParser::_ReadCompoundWord(types_asdl::lex_mode_t lex_mode) {
  return this->_ReadCompoundWord3(lex_mode, Id::Undefined_Tok, true);
}

syntax_asdl::CompoundWord* WordParser::_ReadCompoundWord3(types_asdl::lex_mode_t lex_mode, int eof_type, bool empty_ok) {
  syntax_asdl::CompoundWord* w = nullptr;
  int num_parts;
  int brace_count;
  bool done;
  syntax_asdl::BoolParamBox* is_triple_quoted = nullptr;
  bool allow_done;
  BigStr* next_byte = nullptr;
  syntax_asdl::Token* vsub_token = nullptr;
  syntax_asdl::word_part_t* part = nullptr;
  syntax_asdl::CommandSub* cs_part = nullptr;
  bool try_triple_quote;
  StackRoot _root0(&w);
  StackRoot _root1(&is_triple_quoted);
  StackRoot _root2(&next_byte);
  StackRoot _root3(&vsub_token);
  StackRoot _root4(&part);
  StackRoot _root5(&cs_part);

  w = Alloc<CompoundWord>(Alloc<List<syntax_asdl::word_part_t*>>());
  num_parts = 0;
  brace_count = 0;
  done = false;
  is_triple_quoted = nullptr;
  while (!done) {
    this->_GetToken();
    allow_done = (empty_ok or num_parts != 0);
    if ((allow_done and this->token_type == eof_type)) {
      done = true;
    }
    else {
      if ((this->token_kind == Kind::Lit || this->token_kind == Kind::History || this->token_kind == Kind::KW || this->token_kind == Kind::ControlFlow || this->token_kind == Kind::BoolUnary || this->token_kind == Kind::BoolBinary)) {
        if (this->token_type == Id::Lit_LBrace) {
          brace_count += 1;
        }
        else {
          if (this->token_type == Id::Lit_RBrace) {
            brace_count -= 1;
          }
          else {
            if (this->token_type == Id::Lit_Dollar) {
              if (!this->parse_opts->parse_dollar()) {
                if ((num_parts == 0 and lex_mode == lex_mode_e::ShCommand)) {
                  next_byte = this->lexer->ByteLookAhead();
                  if (str_equals(next_byte, str1895)) {
                    ;  // pass
                  }
                }
                p_die(str1896, this->cur_token);
              }
            }
          }
        }
        done = this->_MaybeReadWordPart(num_parts == 0, lex_mode, w->parts);
      }
      else {
        if (this->token_kind == Kind::VSub) {
          vsub_token = this->cur_token;
          part = Alloc<SimpleVarSub>(vsub_token);
          w->parts->append(part);
        }
        else {
          if (this->token_kind == Kind::ExtGlob) {
            if ((this->parse_opts->parse_at() and (this->token_type == Id::ExtGlob_At and num_parts == 0))) {
              cs_part = this->_ReadCommandSub(Id::Left_AtParen, false);
              cs_part->left_token->id = Id::Left_AtParen;
              part = cs_part;
              this->_GetToken();
              if (!list_contains(KINDS_THAT_END_WORDS, this->token_kind)) {
                p_die(str1897, this->cur_token);
              }
              done = true;
            }
            else {
              part = this->_ReadExtGlob();
            }
            w->parts->append(part);
          }
          else {
            if (this->token_kind == Kind::BashRegex) {
              if (this->token_type == Id::BashRegex_LParen) {
                part = this->_ReadBashRegexGroup();
                w->parts->append(part);
              }
              else {
                p_die(str1898, this->cur_token);
              }
            }
            else {
              if (this->token_kind == Kind::Left) {
                try_triple_quote = (this->parse_opts->parse_triple_quote() and (lex_mode == lex_mode_e::ShCommand and num_parts == 0));
                if (try_triple_quote) {
                  is_triple_quoted = Alloc<BoolParamBox>(false);
                }
                part = this->_ReadUnquotedLeftParts(is_triple_quoted);
                w->parts->append(part);
              }
              else {
                if (this->token_kind == Kind::Right) {
                  if (this->token_type == Id::Right_DoubleQuote) {
                    ;  // pass
                  }
                  else {
                    if (this->token_type == Id::Right_Subshell) {
                      if (this->lexer->MaybeUnreadOne()) {
                        this->lexer->PushHint(Id::Op_RParen, Id::Right_Subshell);
                        this->_SetNext(lex_mode);
                      }
                      done = true;
                    }
                    else {
                      done = true;
                    }
                  }
                }
                else {
                  if (this->token_kind == Kind::Ignored) {
                    done = true;
                  }
                  else {
                    if ((this->token_type == Id::Op_RParen || this->token_type == Id::Eof_RParen)) {
                      if (this->lexer->MaybeUnreadOne()) {
                        if (this->token_type == Id::Eof_RParen) {
                          this->lexer->PushHint(Id::Op_RParen, Id::Eof_RParen);
                        }
                        this->_SetNext(lex_mode);
                      }
                    }
                    done = true;
                  }
                }
              }
            }
          }
        }
      }
    }
    if (!done) {
      this->_SetNext(lex_mode);
      num_parts += 1;
    }
  }
  if ((this->parse_opts->parse_brace() and (num_parts > 1 and brace_count != 0))) {
    p_die(str1899, Alloc<loc::Word>(w));
  }
  if ((is_triple_quoted and (is_triple_quoted->b and num_parts > 1))) {
    p_die(str1900, Alloc<loc::WordPart>(w->parts->at(-1)));
  }
  return w;
}

syntax_asdl::word_t* WordParser::_ReadArithWord() {
  this->_GetToken();
  if (this->token_kind == Kind::Unknown) {
    p_die(StrFormat("Unexpected token while parsing arithmetic: %r", lexer::TokenVal(this->cur_token)), this->cur_token);
  }
  else {
    if (this->token_kind == Kind::Eof) {
      return this->cur_token;
    }
    else {
      if (this->token_kind == Kind::Ignored) {
        this->_SetNext(lex_mode_e::Arith);
        return nullptr;
      }
      else {
        if ((this->token_kind == Kind::Arith || this->token_kind == Kind::Right)) {
          this->_SetNext(lex_mode_e::Arith);
          return this->cur_token;
        }
        else {
          if ((this->token_kind == Kind::Lit || this->token_kind == Kind::Left || this->token_kind == Kind::VSub)) {
            return this->_ReadCompoundWord(lex_mode_e::Arith);
          }
          else {
            assert(0);  // AssertionError
          }
        }
      }
    }
  }
}

syntax_asdl::word_t* WordParser::_ReadWord(types_asdl::lex_mode_t word_mode) {
  types_asdl::lex_mode_t lex_mode;
  syntax_asdl::Token* bracket_word = nullptr;
  syntax_asdl::Token* tok = nullptr;
  int left_id;
  StackRoot _root0(&bracket_word);
  StackRoot _root1(&tok);

  if (word_mode == lex_mode_e::ShCommandFakeBrack) {
    lex_mode = lex_mode_e::ShCommand;
  }
  else {
    lex_mode = word_mode;
  }
  this->_GetToken();
  if (this->token_kind == Kind::Eof) {
    return this->cur_token;
  }
  else {
    if ((this->token_kind == Kind::Op || this->token_kind == Kind::Redir || this->token_kind == Kind::Arith)) {
      this->_SetNext(lex_mode);
      if (this->token_type == Id::Op_Newline) {
        if (this->multiline) {
          if (this->newline_state > 1) {
            p_die(str1902, this->cur_token);
          }
          return nullptr;
        }
        if (this->returned_newline) {
          return nullptr;
        }
      }
      return this->cur_token;
    }
    else {
      if (this->token_kind == Kind::Right) {
        if ((this->token_type != Id::Right_Subshell && this->token_type != Id::Right_ShFunction && this->token_type != Id::Right_CasePat && this->token_type != Id::Right_ShArrayLiteral)) {
          assert(0);  // AssertionError
        }
        this->_SetNext(lex_mode);
        return this->cur_token;
      }
      else {
        if ((this->token_kind == Kind::Ignored || this->token_kind == Kind::WS)) {
          this->_SetNext(lex_mode);
          return nullptr;
        }
        else {
          if ((word_mode == lex_mode_e::ShCommandFakeBrack and (this->parse_opts->parse_bracket() and this->token_type == Id::Lit_LBracket))) {
            bracket_word = this->cur_token;
            bracket_word->id = Id::Op_LBracket;
            this->_SetNext(lex_mode);
            return bracket_word;
          }
          if (this->token_type == Id::Lit_Pound) {
            this->_SetNext(lex_mode_e::Comment);
            this->_GetToken();
            return nullptr;
          }
          else {
            if (this->token_type == Id::Lit_TPound) {
              this->_SetNext(lex_mode_e::Comment);
              this->_GetToken();
              if ((this->token_type == Id::Ignored_Comment and this->emit_doc_token)) {
                return this->cur_token;
              }
              return nullptr;
            }
            else {
              if ((this->token_type == Id::Lit_Chars and this->lexer->LookAheadOne(lex_mode_e::ShCommand) == Id::Left_SingleQuote)) {
                tok = this->cur_token;
                if (this->parse_opts->parse_ysh_string()) {
                  if (lexer::TokenEquals(tok, str1903)) {
                    left_id = Id::Left_RSingleQuote;
                  }
                  else {
                    if (lexer::TokenEquals(tok, str1904)) {
                      left_id = Id::Left_USingleQuote;
                    }
                    else {
                      if (lexer::TokenEquals(tok, str1905)) {
                        left_id = Id::Left_BSingleQuote;
                      }
                      else {
                        left_id = Id::Undefined_Tok;
                      }
                    }
                  }
                  if (left_id != Id::Undefined_Tok) {
                    this->_SetNext(lex_mode_e::ShCommand);
                    this->_GetToken();
                    return this->_ReadYshSingleQuoted(left_id);
                  }
                }
              }
              return this->_ReadCompoundWord(lex_mode);
            }
          }
        }
      }
    }
  }
}

syntax_asdl::BracedVarSub* WordParser::ParseVarRef() {
  syntax_asdl::BracedVarSub* part = nullptr;
  StackRoot _root0(&part);

  this->_SetNext(lex_mode_e::VSub_1);
  this->_GetToken();
  if (this->token_kind != Kind::VSub) {
    p_die(str1906, this->cur_token);
  }
  part = this->_ParseVarOf();
  part->left = part->token;
  part->right = part->token;
  this->_GetToken();
  if (this->token_type != Id::Eof_Real) {
    p_die(str1907, this->cur_token);
  }
  return part;
}

int WordParser::LookPastSpace() {
  int id_;
  if (this->cur_token->id == Id::WS_Space) {
    id_ = this->lexer->LookPastSpace(lex_mode_e::ShCommand);
  }
  else {
    id_ = this->cur_token->id;
  }
  return id_;
}

bool WordParser::LookAheadFuncParens() {
  if (this->cur_token->id == Id::Op_LParen) {
    return this->lexer->LookAheadFuncParens(1);
  }
  else {
    if (this->cur_token->id == Id::WS_Space) {
      return this->lexer->LookAheadFuncParens(0);
    }
    else {
      return false;
    }
  }
}

syntax_asdl::word_t* WordParser::ReadWord(types_asdl::lex_mode_t word_mode) {
  syntax_asdl::word_t* w = nullptr;
  StackRoot _root0(&w);

  if (this->buffered_word) {
    w = this->buffered_word;
    this->buffered_word = nullptr;
  }
  else {
    while (true) {
      w = this->_ReadWord(word_mode);
      if (w != nullptr) {
        break;
      }
    }
  }
  this->returned_newline = word_::CommandId(w) == Id::Op_Newline;
  return w;
}

syntax_asdl::word_t* WordParser::ReadArithWord() {
  syntax_asdl::word_t* w = nullptr;
  StackRoot _root0(&w);

  while (true) {
    w = this->_ReadArithWord();
    if (w != nullptr) {
      break;
    }
  }
  return w;
}

void WordParser::ReadHereDocBody(List<syntax_asdl::word_part_t*>* parts) {
  StackRoot _root0(&parts);

  this->_ReadLikeDQ(nullptr, false, parts);
}

syntax_asdl::CompoundWord* WordParser::ReadForPlugin() {
  syntax_asdl::CompoundWord* w = nullptr;
  StackRoot _root0(&w);

  w = Alloc<CompoundWord>(Alloc<List<syntax_asdl::word_part_t*>>());
  this->_ReadLikeDQ(nullptr, false, w->parts);
  return w;
}

void WordParser::EmitDocToken(bool b) {
  this->emit_doc_token = b;
}

void WordParser::Multiline(bool b) {
  this->multiline = b;
}

}  // define namespace word_parse

namespace parse {  // define

using pnode::PNode;
using pnode::PNodeAllocator;
int NT_OFFSET = 256;

ParseError::ParseError(BigStr* msg, int type_, syntax_asdl::Token* tok) {
  this->msg = msg;
  this->type = type_;
  this->tok = tok;
}

_StackItem::_StackItem(Tuple2<List<List<Tuple2<int, int>*>*>*, Dict<int, int>*>* dfa, int state, pnode::PNode* node) {
  this->dfa = dfa;
  this->state = state;
  this->node = node;
}

Parser::Parser(grammar::Grammar* grammar) {
  this->grammar = grammar;
  this->rootnode = nullptr;
  this->stack = Alloc<List<parse::_StackItem*>>();
  this->pnode_alloc = nullptr;
}

void Parser::setup(int start, pnode::PNodeAllocator* pnode_alloc) {
  pnode::PNode* newnode = nullptr;
  StackRoot _root0(&pnode_alloc);
  StackRoot _root1(&newnode);

  this->pnode_alloc = pnode_alloc;
  newnode = this->pnode_alloc->NewPNode(start, nullptr);
  this->stack = NewList<parse::_StackItem*>(std::initializer_list<parse::_StackItem*>{Alloc<_StackItem>(this->grammar->dfas->at(start), 0, newnode)});
  this->rootnode = nullptr;
}

bool Parser::addtoken(int typ, syntax_asdl::Token* opaque, int ilabel) {
  parse::_StackItem* top = nullptr;
  List<List<Tuple2<int, int>*>*>* states = nullptr;
  int state;
  List<Tuple2<int, int>*>* arcs = nullptr;
  bool found;
  int ilab;
  int newstate;
  int t;
  int s0;
  int s1;
  Tuple2<List<List<Tuple2<int, int>*>*>*, Dict<int, int>*>* itsdfa = nullptr;
  Dict<int, int>* itsfirst = nullptr;
  bool found2;
  int left;
  int right;
  StackRoot _root0(&opaque);
  StackRoot _root1(&top);
  StackRoot _root2(&states);
  StackRoot _root3(&arcs);
  StackRoot _root4(&itsdfa);
  StackRoot _root5(&itsfirst);

  while (true) {
    top = this->stack->at(-1);
    Tuple2<List<List<Tuple2<int, int>*>*>*, Dict<int, int>*>* tup0 = top->dfa;
    states = tup0->at0();
    state = top->state;
    arcs = states->at(state);
    found = false;
    for (ListIter<Tuple2<int, int>*> it(arcs); !it.Done(); it.Next()) {
      Tuple2<int, int>* tup1 = it.Value();
      ilab = tup1->at0();
      newstate = tup1->at1();
      t = this->grammar->labels->at(ilab);
      if (ilabel == ilab) {
        this->shift(typ, opaque, newstate);
        state = newstate;
        while (true) {
          if (len(states->at(state)) != 1) {
            break;
          }
          Tuple2<int, int>* tup2 = states->at(state)->at(0);
          s0 = tup2->at0();
          s1 = tup2->at1();
          if ((s0 != 0 or s1 != state)) {
            break;
          }
          this->pop();
          if (len(this->stack) == 0) {
            return true;
          }
          top = this->stack->at(-1);
          Tuple2<List<List<Tuple2<int, int>*>*>*, Dict<int, int>*>* tup3 = top->dfa;
          states = tup3->at0();
          state = top->state;
        }
        return false;
      }
      else {
        if (t >= NT_OFFSET) {
          itsdfa = this->grammar->dfas->at(t);
          Tuple2<List<List<Tuple2<int, int>*>*>*, Dict<int, int>*>* tup4 = itsdfa;
          itsfirst = tup4->at1();
          if (dict_contains(itsfirst, ilabel)) {
            this->push(t, opaque, this->grammar->dfas->at(t), newstate);
            found = true;
            break;
          }
        }
      }
    }
    if (!found) {
      found2 = false;
      for (ListIter<Tuple2<int, int>*> it(arcs); !it.Done(); it.Next()) {
        Tuple2<int, int>* tup5 = it.Value();
        left = tup5->at0();
        right = tup5->at1();
        if ((left == 0 and right == state)) {
          this->pop();
          if (len(this->stack) == 0) {
            throw Alloc<ParseError>(str1909, typ, opaque);
          }
          found2 = true;
        }
      }
      if (!found2) {
        throw Alloc<ParseError>(str1910, typ, opaque);
      }
    }
  }
}

void Parser::shift(int typ, syntax_asdl::Token* opaque, int newstate) {
  parse::_StackItem* top = nullptr;
  pnode::PNode* newnode = nullptr;
  StackRoot _root0(&opaque);
  StackRoot _root1(&top);
  StackRoot _root2(&newnode);

  top = this->stack->at(-1);
  newnode = this->pnode_alloc->NewPNode(typ, opaque);
  top->node->AddChild(newnode);
  this->stack->at(-1)->state = newstate;
}

void Parser::push(int typ, syntax_asdl::Token* opaque, Tuple2<List<List<Tuple2<int, int>*>*>*, Dict<int, int>*>* newdfa, int newstate) {
  parse::_StackItem* top = nullptr;
  pnode::PNode* newnode = nullptr;
  StackRoot _root0(&opaque);
  StackRoot _root1(&newdfa);
  StackRoot _root2(&top);
  StackRoot _root3(&newnode);

  top = this->stack->at(-1);
  newnode = this->pnode_alloc->NewPNode(typ, opaque);
  this->stack->at(-1)->state = newstate;
  this->stack->append(Alloc<_StackItem>(newdfa, 0, newnode));
}

void Parser::pop() {
  parse::_StackItem* top = nullptr;
  pnode::PNode* newnode = nullptr;
  parse::_StackItem* top2 = nullptr;
  StackRoot _root0(&top);
  StackRoot _root1(&newnode);
  StackRoot _root2(&top2);

  top = this->stack->pop();
  newnode = top->node;
  if (len(this->stack)) {
    top2 = this->stack->at(-1);
    top2->node->AddChild(newnode);
  }
  else {
    this->rootnode = newnode;
  }
}

}  // define namespace parse

namespace cgi {  // define


BigStr* escape(BigStr* s) {
  StackRoot _root0(&s);

  s = s->replace(str1911, str1912);
  s = s->replace(str1913, str1914);
  s = s->replace(str1915, str1916);
  return s;
}

}  // define namespace cgi

namespace os_path {  // define

BigStr* extsep = str1917;
BigStr* sep = str1918;

BigStr* join(BigStr* s1, BigStr* s2) {
  StackRoot _root0(&s1);
  StackRoot _root1(&s2);

  if ((s2->startswith(str1919) or len(s1) == 0)) {
    return s2;
  }
  if (s1->endswith(str1920)) {
    return str_concat(s1, s2);
  }
  return StrFormat("%s/%s", s1, s2);
}

Tuple2<BigStr*, BigStr*> split(BigStr* p) {
  int i;
  BigStr* head = nullptr;
  BigStr* tail = nullptr;
  StackRoot _root0(&p);
  StackRoot _root1(&head);
  StackRoot _root2(&tail);

  i = (p->rfind(str1922) + 1);
  head = p->slice(0, i);
  tail = p->slice(i);
  head = rstrip_slashes(head);
  return Tuple2<BigStr*, BigStr*>(head, tail);
}

Tuple2<BigStr*, BigStr*> _splitext(BigStr* p, BigStr* sep, BigStr* extsep) {
  int sepIndex;
  int dotIndex;
  int filenameIndex;
  StackRoot _root0(&p);
  StackRoot _root1(&sep);
  StackRoot _root2(&extsep);

  sepIndex = p->rfind(sep);
  dotIndex = p->rfind(extsep);
  if (dotIndex > sepIndex) {
    filenameIndex = (sepIndex + 1);
    while (filenameIndex < dotIndex) {
      if (!(str_equals(p->at(filenameIndex), extsep))) {
        return Tuple2<BigStr*, BigStr*>(p->slice(0, dotIndex), p->slice(dotIndex));
      }
      filenameIndex += 1;
    }
  }
  return Tuple2<BigStr*, BigStr*>(p, str1923);
}

Tuple2<BigStr*, BigStr*> splitext(BigStr* p) {
  StackRoot _root0(&p);

  return _splitext(p, sep, extsep);
}

BigStr* basename(BigStr* p) {
  int i;
  StackRoot _root0(&p);

  i = (p->rfind(str1924) + 1);
  return p->slice(i);
}

BigStr* dirname(BigStr* p) {
  int i;
  BigStr* head = nullptr;
  StackRoot _root0(&p);
  StackRoot _root1(&head);

  i = (p->rfind(str1925) + 1);
  head = p->slice(0, i);
  head = rstrip_slashes(head);
  return head;
}

BigStr* normpath(BigStr* path) {
  BigStr* slash = nullptr;
  BigStr* dot = nullptr;
  int initial_slashes;
  List<BigStr*>* comps = nullptr;
  List<BigStr*>* new_comps = nullptr;
  StackRoot _root0(&path);
  StackRoot _root1(&slash);
  StackRoot _root2(&dot);
  StackRoot _root3(&comps);
  StackRoot _root4(&new_comps);

  slash = str1926;
  dot = str1927;
  if (str_equals(path, str1928)) {
    return dot;
  }
  initial_slashes = path->startswith(str1929);
  if ((initial_slashes and (path->startswith(str1930) and !path->startswith(str1931)))) {
    initial_slashes = 2;
  }
  comps = path->split(str1932);
  new_comps = Alloc<List<BigStr*>>();
  for (ListIter<BigStr*> it(comps); !it.Done(); it.Next()) {
    BigStr* comp = it.Value();
    StackRoot _for(&comp  );
    if ((len(comp) == 0 or str_equals(comp, str1933))) {
      continue;
    }
    if ((!(str_equals(comp, str1934)) or ((initial_slashes == 0 and len(new_comps) == 0) or (len(new_comps) and str_equals(new_comps->at(-1), str1935))))) {
      new_comps->append(comp);
    }
    else {
      if (len(new_comps)) {
        new_comps->pop();
      }
    }
  }
  comps = new_comps;
  path = slash->join(comps);
  if (initial_slashes) {
    path = str_concat(str_repeat(slash, initial_slashes), path);
  }
  return len(path) ? path : dot;
}

bool isabs(BigStr* s) {
  StackRoot _root0(&s);

  return s->startswith(str1936);
}

BigStr* abspath(BigStr* path) {
  BigStr* cwd = nullptr;
  StackRoot _root0(&path);
  StackRoot _root1(&cwd);

  if (!isabs(path)) {
    cwd = posix::getcwd();
    path = join(cwd, path);
  }
  return normpath(path);
}

}  // define namespace os_path

namespace fmt {  // define


void Format(alloc::Arena* arena, syntax_asdl::command_t* node) {
  ysh_ify::Cursor* cursor = nullptr;
  StackRoot _root0(&arena);
  StackRoot _root1(&node);
  StackRoot _root2(&cursor);

  cursor = Alloc<ysh_ify::Cursor>(arena, mylib::Stdout());
  cursor->PrintUntilEnd();
}

}  // define namespace fmt

namespace ysh_ify {  // define

using id_kind_asdl::Id;
using id_kind_asdl::Id_str;
using runtime_asdl::word_style_e;
using runtime_asdl::word_style_t;
using syntax_asdl::loc;
using syntax_asdl::CompoundWord;
using syntax_asdl::Token;
using syntax_asdl::SimpleVarSub;
using syntax_asdl::BracedVarSub;
using syntax_asdl::CommandSub;
using syntax_asdl::DoubleQuoted;
using syntax_asdl::SingleQuoted;
using syntax_asdl::word_e;
using syntax_asdl::word_t;
using syntax_asdl::word_part;
using syntax_asdl::word_part_e;
using syntax_asdl::word_part_t;
using syntax_asdl::rhs_word_e;
using syntax_asdl::rhs_word_t;
using syntax_asdl::sh_lhs;
using syntax_asdl::sh_lhs_e;
using syntax_asdl::command;
using syntax_asdl::command_e;
using syntax_asdl::BraceGroup;
using syntax_asdl::for_iter_e;
using syntax_asdl::case_arg_e;
using syntax_asdl::case_arg;
using syntax_asdl::condition;
using syntax_asdl::condition_e;
using syntax_asdl::redir_param;
using syntax_asdl::redir_param_e;
using syntax_asdl::Redir;
using error::p_die;
using mylib::print_stderr;

Cursor::Cursor(alloc::Arena* arena, mylib::Writer* f) {
  this->arena = arena;
  this->f = f;
  this->next_span_id = 0;
}

void Cursor::_PrintUntilSpid(int until_span_id) {
  syntax_asdl::Token* span = nullptr;
  int start_index;
  int end_index;
  BigStr* piece = nullptr;
  StackRoot _root0(&span);
  StackRoot _root1(&piece);

  if (until_span_id == runtime::NO_SPID) {
  }
  for (int span_id = this->next_span_id; span_id < until_span_id; ++span_id) {
    span = this->arena->GetToken(span_id);
    if (span->line == nullptr) {
      continue;
    }
    start_index = span->id == Id::Lit_CharsWithoutPrefix ? 0 : span->col;
    end_index = (span->col + span->length);
    piece = span->line->content->slice(start_index, end_index);
    this->f->write(piece);
  }
  this->next_span_id = until_span_id;
}

void Cursor::_SkipUntilSpid(int next_span_id) {
  if ((next_span_id == runtime::NO_SPID or next_span_id == (runtime::NO_SPID + 1))) {
  }
  this->next_span_id = next_span_id;
}

void Cursor::SkipUntil(syntax_asdl::Token* tok) {
  int span_id;
  StackRoot _root0(&tok);

  span_id = this->arena->GetSpanId(tok);
  this->_SkipUntilSpid(span_id);
}

void Cursor::SkipPast(syntax_asdl::Token* tok) {
  int span_id;
  StackRoot _root0(&tok);

  span_id = this->arena->GetSpanId(tok);
  this->_SkipUntilSpid((span_id + 1));
}

void Cursor::PrintUntil(syntax_asdl::Token* tok) {
  int span_id;
  StackRoot _root0(&tok);

  span_id = this->arena->GetSpanId(tok);
  this->_PrintUntilSpid(span_id);
}

void Cursor::PrintIncluding(syntax_asdl::Token* tok) {
  int span_id;
  StackRoot _root0(&tok);

  span_id = this->arena->GetSpanId(tok);
  this->_PrintUntilSpid((span_id + 1));
}

void Cursor::PrintUntilEnd() {
  this->_PrintUntilSpid(this->arena->LastSpanId());
}

void LosslessCat(alloc::Arena* arena) {
  ysh_ify::Cursor* cursor = nullptr;
  StackRoot _root0(&arena);
  StackRoot _root1(&cursor);

  cursor = Alloc<Cursor>(arena, mylib::Stdout());
  cursor->PrintUntilEnd();
}

void PrintTokens(alloc::Arena* arena) {
  int i;
  BigStr* piece = nullptr;
  StackRoot _root0(&arena);
  StackRoot _root1(&piece);

  if (len(arena->tokens) == 1) {
    print(str1937);
    print(StrFormat("%s", arena->tokens->at(0)));
    return ;
  }
  i = 0;
  for (ListIter<syntax_asdl::Token*> it(arena->tokens); !it.Done(); it.Next(), ++i) {
    syntax_asdl::Token* tok = it.Value();
    StackRoot _for(&tok  );
    piece = tok->line->content->slice(tok->col, (tok->col + tok->length));
    print(StrFormat("%5d %-20s %r", i, Id_str(tok->id), piece));
  }
  print_stderr(StrFormat("(%d tokens)", len(arena->tokens)));
}

void Ysh_ify(alloc::Arena* arena, syntax_asdl::command_t* node) {
  ysh_ify::Cursor* cursor = nullptr;
  ysh_ify::YshPrinter* fixer = nullptr;
  StackRoot _root0(&arena);
  StackRoot _root1(&node);
  StackRoot _root2(&cursor);
  StackRoot _root3(&fixer);

  cursor = Alloc<Cursor>(arena, mylib::Stdout());
  fixer = Alloc<YshPrinter>(cursor, arena, mylib::Stdout());
  fixer->DoCommand(node, nullptr, true);
  fixer->End();
}

runtime_asdl::word_style_t _GetRhsStyle(syntax_asdl::rhs_word_t* w) {
  syntax_asdl::rhs_word_t* UP_w = nullptr;
  syntax_asdl::word_part_t* part0 = nullptr;
  syntax_asdl::word_part_t* UP_part0 = nullptr;
  StackRoot _root0(&w);
  StackRoot _root1(&UP_w);
  StackRoot _root2(&part0);
  StackRoot _root3(&UP_part0);

  UP_w = w;
  switch (w->tag()) {
    case rhs_word_e::Empty: {
      return word_style_e::SQ;
    }
      break;
    case rhs_word_e::Compound: {
      CompoundWord* w = static_cast<CompoundWord*>(UP_w);
      if (len(w->parts) == 0) {
        assert(0);  // AssertionError
      }
      else {
        if (len(w->parts) == 1) {
          part0 = w->parts->at(0);
          UP_part0 = part0;
          switch (part0->tag()) {
            case word_part_e::TildeSub: {
              return word_style_e::Expr;
            }
              break;
            case word_part_e::Literal: {
              return word_style_e::SQ;
            }
              break;
            case word_part_e::SimpleVarSub: {
              return word_style_e::DQ;
            }
              break;
            case word_part_e::BracedVarSub: 
            case word_part_e::CommandSub: 
            case word_part_e::ArithSub: {
              return word_style_e::Unquoted;
            }
              break;
            case word_part_e::DoubleQuoted: {
              DoubleQuoted* part0 = static_cast<DoubleQuoted*>(UP_part0);
              return word_style_e::DQ;
            }
              break;
          }
        }
        else {
          return word_style_e::DQ;
        }
      }
    }
      break;
  }
  return word_style_e::SQ;
}

YshPrinter::YshPrinter(ysh_ify::Cursor* cursor, alloc::Arena* arena, mylib::Writer* f) {
  this->cursor = cursor;
  this->arena = arena;
  this->f = f;
}

void YshPrinter::_DebugSpid(int spid) {
  syntax_asdl::Token* span = nullptr;
  BigStr* s = nullptr;
  StackRoot _root0(&span);
  StackRoot _root1(&s);

  span = this->arena->GetToken(spid);
  s = span->line->content->slice(span->col, (span->col + span->length));
  print_stderr(StrFormat("SPID %d = %r", spid, s));
}

void YshPrinter::End() {
  this->cursor->PrintUntilEnd();
}

void YshPrinter::DoRedirect(syntax_asdl::Redir* node, Dict<BigStr*, bool>* local_symbols) {
  int op_id;
  redir_param::HereDoc* here_doc = nullptr;
  syntax_asdl::word_t* here_begin = nullptr;
  bool ok;
  BigStr* delimiter = nullptr;
  bool delim_quoted;
  syntax_asdl::Token* delim_end_tok = nullptr;
  StackRoot _root0(&node);
  StackRoot _root1(&local_symbols);
  StackRoot _root2(&here_doc);
  StackRoot _root3(&here_begin);
  StackRoot _root4(&delimiter);
  StackRoot _root5(&delim_end_tok);

  op_id = node->op->id;
  this->cursor->PrintUntil(node->op);
  if (node->arg->tag() == redir_param_e::HereDoc) {
    here_doc = static_cast<redir_param::HereDoc*>(node->arg);
    here_begin = here_doc->here_begin;
    Tuple3<bool, BigStr*, bool> tup0 = word_::StaticEval(here_begin);
    ok = tup0.at0();
    delimiter = tup0.at1();
    delim_quoted = tup0.at2();
    if (!ok) {
      p_die(str1942, Alloc<loc::Word>(here_begin));
    }
    this->f->write(str1943);
    if (delim_quoted) {
      this->f->write(str1944);
    }
    else {
      this->f->write(str1945);
    }
    delim_end_tok = location::RightTokenForWord(here_begin);
    this->cursor->SkipPast(delim_end_tok);
    for (ListIter<syntax_asdl::word_part_t*> it(here_doc->stdin_parts); !it.Done(); it.Next()) {
      syntax_asdl::word_part_t* part = it.Value();
      StackRoot _for(&part    );
      this->DoWordPart(part, local_symbols);
    }
    this->cursor->SkipPast(here_doc->here_end_tok);
    if (delim_quoted) {
      this->f->write(str1946);
    }
    else {
      this->f->write(str1947);
    }
  }
  else {
    ;  // pass
  }
}

void YshPrinter::DoShAssignment(command::ShAssignment* node, bool at_top_level, Dict<BigStr*, bool>* local_symbols) {
  bool has_rhs;
  bool defined_locally;
  syntax_asdl::sh_lhs_t* lhs0 = nullptr;
  List<bool>* has_array_index = nullptr;
  int n;
  int i;
  syntax_asdl::sh_lhs_t* lhs = nullptr;
  syntax_asdl::sh_lhs_t* UP_lhs = nullptr;
  StackRoot _root0(&node);
  StackRoot _root1(&local_symbols);
  StackRoot _root2(&lhs0);
  StackRoot _root3(&has_array_index);
  StackRoot _root4(&lhs);
  StackRoot _root5(&UP_lhs);

  has_rhs = false;
  defined_locally = false;
  if (true) {
    this->cursor->PrintUntil(node->pairs->at(0)->left);
    if (local_symbols != nullptr) {
      lhs0 = node->pairs->at(0)->lhs;
    }
    has_array_index = Alloc<List<bool>>();
    for (ListIter<syntax_asdl::AssignPair*> it(node->pairs); !it.Done(); it.Next()) {
      syntax_asdl::AssignPair* pair = it.Value();
      has_array_index->append(pair->lhs->tag() == sh_lhs_e::UnparsedIndex);
    }
    if (at_top_level) {
      this->f->write(str1948);
    }
    else {
      if (defined_locally) {
        this->f->write(str1949);
      }
      else {
        this->f->write(str1950);
      }
    }
  }
  n = len(node->pairs);
  i = 0;
  for (ListIter<syntax_asdl::AssignPair*> it(node->pairs); !it.Done(); it.Next(), ++i) {
    syntax_asdl::AssignPair* pair = it.Value();
    StackRoot _for(&pair  );
    lhs = pair->lhs;
    UP_lhs = lhs;
    switch (lhs->tag()) {
      case sh_lhs_e::Name: {
        sh_lhs::Name* lhs = static_cast<sh_lhs::Name*>(UP_lhs);
        this->cursor->PrintUntil(pair->left);
        this->cursor->SkipPast(pair->left);
        this->f->write(lhs->name);
        this->f->write(str1951);
        if (pair->rhs->tag() == rhs_word_e::Empty) {
          this->f->write(str1952);
        }
        else {
          this->DoRhsWord(pair->rhs, local_symbols);
        }
      }
        break;
      case sh_lhs_e::UnparsedIndex: {
        ;  // pass
      }
        break;
      default: {
        assert(0);  // AssertionError
      }
    }
    if (i != (n - 1)) {
      this->f->write(str1953);
    }
  }
}

void YshPrinter::_DoSimple(command::Simple* node, Dict<BigStr*, bool>* local_symbols) {
  syntax_asdl::word_t* first_word = nullptr;
  bool ok;
  BigStr* val = nullptr;
  bool quoted;
  syntax_asdl::Token* word0_tok = nullptr;
  syntax_asdl::word_t* word2 = nullptr;
  syntax_asdl::word_t* last_word = nullptr;
  syntax_asdl::Token* tok2 = nullptr;
  syntax_asdl::Token* rbrack_tok = nullptr;
  StackRoot _root0(&node);
  StackRoot _root1(&local_symbols);
  StackRoot _root2(&first_word);
  StackRoot _root3(&val);
  StackRoot _root4(&word0_tok);
  StackRoot _root5(&word2);
  StackRoot _root6(&last_word);
  StackRoot _root7(&tok2);
  StackRoot _root8(&rbrack_tok);

  if (len(node->more_env)) {
    for (ListIter<syntax_asdl::EnvPair*> it(node->more_env); !it.Done(); it.Next()) {
      syntax_asdl::EnvPair* pair = it.Value();
      StackRoot _for(&pair    );
      this->DoRhsWord(pair->val, local_symbols);
    }
  }
  if (len(node->words)) {
    first_word = node->words->at(0);
    Tuple3<bool, BigStr*, bool> tup1 = word_::StaticEval(first_word);
    ok = tup1.at0();
    val = tup1.at1();
    quoted = tup1.at2();
    word0_tok = location::LeftTokenForWord(first_word);
    if ((ok and !quoted)) {
      if ((str_equals(val, str1954) and len(node->words) >= 3)) {
        word2 = node->words->at(-2);
        last_word = node->words->at(-1);
        Tuple3<bool, BigStr*, bool> tup2 = word_::StaticEval(last_word);
        ok = tup2.at0();
        val = tup2.at1();
        quoted = tup2.at2();
        if ((ok and (!quoted and str_equals(val, str1955)))) {
          this->cursor->PrintUntil(word0_tok);
          this->cursor->SkipPast(word0_tok);
          this->f->write(str1956);
          for (ListIter<syntax_asdl::word_t*> it(node->words->slice(1, -1)); !it.Done(); it.Next()) {
            syntax_asdl::word_t* w = it.Value();
            StackRoot _for(&w          );
            this->DoWordInCommand(w, local_symbols);
          }
          tok2 = location::RightTokenForWord(word2);
          rbrack_tok = location::LeftTokenForWord(last_word);
          this->cursor->PrintIncluding(tok2);
          this->cursor->SkipPast(rbrack_tok);
          return ;
        }
        else {
          throw Alloc<RuntimeError>(str1957);
        }
      }
      else {
        if (str_equals(val, str1958)) {
          this->cursor->PrintUntil(word0_tok);
          this->cursor->SkipPast(word0_tok);
          this->f->write(str1959);
          return ;
        }
      }
    }
  }
  for (ListIter<syntax_asdl::word_t*> it(node->words); !it.Done(); it.Next()) {
    syntax_asdl::word_t* w = it.Value();
    StackRoot _for(&w  );
    this->DoWordInCommand(w, local_symbols);
  }
}

void YshPrinter::DoCommand(syntax_asdl::command_t* node, Dict<BigStr*, bool>* local_symbols, bool at_top_level) {
  syntax_asdl::command_t* UP_node = nullptr;
  Dict<BigStr*, bool>* new_local_symbols = nullptr;
  syntax_asdl::command_t* UP_body = nullptr;
  syntax_asdl::for_iter_t* UP_iterable = nullptr;
  syntax_asdl::Token* body_tok = nullptr;
  List<syntax_asdl::command_t*>* commands = nullptr;
  command::Sentence* sentence = nullptr;
  int i;
  syntax_asdl::Token* elif_tok = nullptr;
  syntax_asdl::Token* then_tok = nullptr;
  syntax_asdl::condition_t* cond = nullptr;
  syntax_asdl::word_t* to_match = nullptr;
  syntax_asdl::SimpleVarSub* var_part = nullptr;
  CompoundWord* w = nullptr;
  syntax_asdl::word_part_t* part0 = nullptr;
  DoubleQuoted* dq_part = nullptr;
  syntax_asdl::word_part_t* dq_part0 = nullptr;
  bool missing_last_dsemi;
  StackRoot _root0(&node);
  StackRoot _root1(&local_symbols);
  StackRoot _root2(&UP_node);
  StackRoot _root3(&new_local_symbols);
  StackRoot _root4(&UP_body);
  StackRoot _root5(&UP_iterable);
  StackRoot _root6(&body_tok);
  StackRoot _root7(&commands);
  StackRoot _root8(&sentence);
  StackRoot _root9(&elif_tok);
  StackRoot _root10(&then_tok);
  StackRoot _root11(&cond);
  StackRoot _root12(&to_match);
  StackRoot _root13(&var_part);
  StackRoot _root14(&w);
  StackRoot _root15(&part0);
  StackRoot _root16(&dq_part);
  StackRoot _root17(&dq_part0);

  UP_node = node;
  switch (node->tag()) {
    case command_e::CommandList: {
      command::CommandList* node = static_cast<command::CommandList*>(UP_node);
      for (ListIter<syntax_asdl::command_t*> it(node->children); !it.Done(); it.Next()) {
        syntax_asdl::command_t* child = it.Value();
        StackRoot _for(&child      );
        this->DoCommand(child, local_symbols, at_top_level);
      }
    }
      break;
    case command_e::Redirect: {
      command::Redirect* node = static_cast<command::Redirect*>(UP_node);
      this->DoCommand(node->child, local_symbols, at_top_level);
      for (ListIter<syntax_asdl::Redir*> it(node->redirects); !it.Done(); it.Next()) {
        syntax_asdl::Redir* r = it.Value();
        StackRoot _for(&r      );
        this->DoRedirect(r, local_symbols);
      }
    }
      break;
    case command_e::Simple: {
      command::Simple* node = static_cast<command::Simple*>(UP_node);
      this->_DoSimple(node, local_symbols);
    }
      break;
    case command_e::ShAssignment: {
      command::ShAssignment* node = static_cast<command::ShAssignment*>(UP_node);
      this->DoShAssignment(node, at_top_level, local_symbols);
    }
      break;
    case command_e::Pipeline: {
      command::Pipeline* node = static_cast<command::Pipeline*>(UP_node);
      for (ListIter<syntax_asdl::command_t*> it(node->children); !it.Done(); it.Next()) {
        syntax_asdl::command_t* child = it.Value();
        StackRoot _for(&child      );
        this->DoCommand(child, local_symbols);
      }
    }
      break;
    case command_e::AndOr: {
      command::AndOr* node = static_cast<command::AndOr*>(UP_node);
      for (ListIter<syntax_asdl::command_t*> it(node->children); !it.Done(); it.Next()) {
        syntax_asdl::command_t* child = it.Value();
        StackRoot _for(&child      );
        this->DoCommand(child, local_symbols);
      }
    }
      break;
    case command_e::Sentence: {
      command::Sentence* node = static_cast<command::Sentence*>(UP_node);
      this->DoCommand(node->child, local_symbols);
    }
      break;
    case command_e::BraceGroup: {
      BraceGroup* node = static_cast<BraceGroup*>(UP_node);
      this->cursor->PrintUntil(node->left);
      this->cursor->SkipPast(node->left);
      this->f->write(str1960);
      for (ListIter<syntax_asdl::command_t*> it(node->children); !it.Done(); it.Next()) {
        syntax_asdl::command_t* child = it.Value();
        StackRoot _for(&child      );
        this->DoCommand(child, local_symbols);
      }
    }
      break;
    case command_e::Subshell: {
      command::Subshell* node = static_cast<command::Subshell*>(UP_node);
      this->cursor->PrintUntil(node->left);
      this->cursor->SkipPast(node->left);
      this->f->write(str1961);
      this->DoCommand(node->child, local_symbols);
      this->cursor->PrintUntil(node->right);
      this->cursor->SkipPast(node->right);
      this->f->write(str1962);
    }
      break;
    case command_e::ShFunction: {
      command::ShFunction* node = static_cast<command::ShFunction*>(UP_node);
      new_local_symbols = Alloc<Dict<BigStr*, bool>>();
      if (node->keyword) {
        this->cursor->PrintUntil(node->keyword);
      }
      else {
        this->cursor->PrintUntil(node->name_tok);
      }
      this->f->write(StrFormat("proc %s ", node->name));
      UP_body = node->body;
      switch (UP_body->tag()) {
        case command_e::BraceGroup: {
          BraceGroup* body = static_cast<BraceGroup*>(UP_body);
          this->cursor->SkipUntil(body->left);
          for (ListIter<syntax_asdl::command_t*> it(body->children); !it.Done(); it.Next()) {
            syntax_asdl::command_t* child = it.Value();
            StackRoot _for(&child          );
            this->DoCommand(child, new_local_symbols);
          }
        }
          break;
        default: {
          ;  // pass
        }
      }
    }
      break;
    case command_e::DoGroup: {
      command::DoGroup* node = static_cast<command::DoGroup*>(UP_node);
      this->cursor->PrintUntil(node->left);
      this->cursor->SkipPast(node->left);
      this->f->write(str1964);
      for (ListIter<syntax_asdl::command_t*> it(node->children); !it.Done(); it.Next()) {
        syntax_asdl::command_t* child = it.Value();
        StackRoot _for(&child      );
        this->DoCommand(child, local_symbols);
      }
      this->cursor->PrintUntil(node->right);
      this->cursor->SkipPast(node->right);
      this->f->write(str1965);
    }
      break;
    case command_e::ForEach: {
      command::ForEach* node = static_cast<command::ForEach*>(UP_node);
      UP_iterable = node->iterable;
      switch (node->iterable->tag()) {
        case for_iter_e::Args: {
          this->f->write(StrFormat("for %s in @ARGV ", node->iter_names->at(0)));
          body_tok = location::TokenForCommand(node->body);
          this->cursor->SkipUntil(body_tok);
        }
          break;
        case for_iter_e::Words: {
          ;  // pass
        }
          break;
        case for_iter_e::YshExpr: {
          ;  // pass
        }
          break;
      }
      if (node->semi_tok != nullptr) {
        this->cursor->PrintUntil(node->semi_tok);
        this->cursor->SkipPast(node->semi_tok);
      }
      this->DoCommand(node->body, local_symbols);
    }
      break;
    case command_e::WhileUntil: {
      command::WhileUntil* node = static_cast<command::WhileUntil*>(UP_node);
      if (node->keyword->id == Id::KW_Until) {
        this->cursor->PrintUntil(node->keyword);
        this->cursor->SkipPast(node->keyword);
        this->f->write(str1967);
      }
      if (node->cond->tag() == condition_e::Shell) {
        commands = static_cast<condition::Shell*>(node->cond)->commands;
        if ((len(commands) == 1 and commands->at(0)->tag() == command_e::Sentence)) {
          sentence = static_cast<command::Sentence*>(commands->at(0));
          this->DoCommand(sentence->child, local_symbols);
          this->cursor->SkipPast(sentence->terminator);
        }
      }
      this->DoCommand(node->body, local_symbols);
    }
      break;
    case command_e::If: {
      command::If* node = static_cast<command::If*>(UP_node);
      i = 0;
      for (ListIter<syntax_asdl::IfArm*> it(node->arms); !it.Done(); it.Next(), ++i) {
        syntax_asdl::IfArm* arm = it.Value();
        StackRoot _for(&arm      );
        elif_tok = arm->keyword;
        then_tok = arm->then_tok;
        if (i != 0) {
          this->cursor->PrintUntil(elif_tok);
          this->f->write(str1968);
        }
        cond = arm->cond;
        if (cond->tag() == condition_e::Shell) {
          commands = static_cast<condition::Shell*>(cond)->commands;
          if ((len(commands) == 1 and commands->at(0)->tag() == command_e::Sentence)) {
            sentence = static_cast<command::Sentence*>(commands->at(0));
            this->DoCommand(sentence, local_symbols);
            this->cursor->PrintUntil(sentence->terminator);
            this->cursor->SkipPast(sentence->terminator);
          }
          else {
            for (ListIter<syntax_asdl::command_t*> it(commands); !it.Done(); it.Next()) {
              syntax_asdl::command_t* child = it.Value();
              StackRoot _for(&child            );
              this->DoCommand(child, local_symbols);
            }
          }
        }
        this->cursor->PrintUntil(then_tok);
        this->cursor->SkipPast(then_tok);
        this->f->write(str1969);
        for (ListIter<syntax_asdl::command_t*> it(arm->action); !it.Done(); it.Next()) {
          syntax_asdl::command_t* child = it.Value();
          StackRoot _for(&child        );
          this->DoCommand(child, local_symbols);
        }
      }
      if (len(node->else_action)) {
        this->cursor->PrintUntil(node->else_kw);
        this->f->write(str1970);
        this->cursor->PrintIncluding(node->else_kw);
        this->f->write(str1971);
        for (ListIter<syntax_asdl::command_t*> it(node->else_action); !it.Done(); it.Next()) {
          syntax_asdl::command_t* child = it.Value();
          StackRoot _for(&child        );
          this->DoCommand(child, local_symbols);
        }
      }
      this->cursor->PrintUntil(node->fi_kw);
      this->cursor->SkipPast(node->fi_kw);
      this->f->write(str1972);
    }
      break;
    case command_e::Case: {
      command::Case* node = static_cast<command::Case*>(UP_node);
      to_match = nullptr;
      switch (node->to_match->tag()) {
        case case_arg_e::YshExpr: {
          return ;
        }
          break;
        case case_arg_e::Word: {
          to_match = static_cast<case_arg::Word*>(node->to_match)->w;
        }
          break;
        default: {
          assert(0);  // AssertionError
        }
      }
      this->cursor->PrintIncluding(node->case_kw);
      var_part = nullptr;
      switch (to_match->tag()) {
        case word_e::Compound: {
          w = static_cast<CompoundWord*>(to_match);
          part0 = w->parts->at(0);
          switch (part0->tag()) {
            case word_part_e::SimpleVarSub: {
              var_part = static_cast<SimpleVarSub*>(part0);
            }
              break;
            case word_part_e::DoubleQuoted: {
              dq_part = static_cast<DoubleQuoted*>(part0);
              if (len(dq_part->parts) == 1) {
                dq_part0 = dq_part->parts->at(0);
                switch (dq_part0->tag()) {
                  case word_part_e::SimpleVarSub: {
                    var_part = static_cast<SimpleVarSub*>(dq_part0);
                  }
                    break;
                }
              }
            }
              break;
          }
        }
          break;
      }
      if (var_part) {
        this->f->write(str1973);
        this->f->write(lexer::LazyStr(var_part->tok));
        this->f->write(str1974);
      }
      this->cursor->SkipPast(node->arms_start);
      this->f->write(str1975);
      missing_last_dsemi = false;
      for (ListIter<syntax_asdl::CaseArm*> it(node->arms); !it.Done(); it.Next()) {
        syntax_asdl::CaseArm* case_arm = it.Value();
        StackRoot _for(&case_arm      );
        this->cursor->PrintUntil(case_arm->middle);
        this->f->write(str1976);
        this->cursor->SkipPast(case_arm->middle);
        for (ListIter<syntax_asdl::command_t*> it(case_arm->action); !it.Done(); it.Next()) {
          syntax_asdl::command_t* child = it.Value();
          StackRoot _for(&child        );
          this->DoCommand(child, local_symbols);
        }
        if (case_arm->right) {
          this->cursor->PrintUntil(case_arm->right);
          this->f->write(str1977);
          this->cursor->SkipPast(case_arm->right);
        }
        else {
          missing_last_dsemi = true;
        }
      }
      this->cursor->PrintUntil(node->arms_end);
      if (missing_last_dsemi) {
        this->f->write(str1978);
      }
      this->cursor->SkipPast(node->arms_end);
      this->f->write(str1979);
    }
      break;
    case command_e::TimeBlock: {
      command::TimeBlock* node = static_cast<command::TimeBlock*>(UP_node);
      this->DoCommand(node->pipeline, local_symbols);
    }
      break;
    case command_e::DParen: {
      command::DParen* node = static_cast<command::DParen*>(UP_node);
      ;  // pass
    }
      break;
    case command_e::DBracket: {
      command::DBracket* node = static_cast<command::DBracket*>(UP_node);
      ;  // pass
    }
      break;
    default: {
      ;  // pass
    }
  }
}

void YshPrinter::DoRhsWord(syntax_asdl::rhs_word_t* node, Dict<BigStr*, bool>* local_symbols) {
  syntax_asdl::rhs_word_t* UP_node = nullptr;
  runtime_asdl::word_style_t style;
  StackRoot _root0(&node);
  StackRoot _root1(&local_symbols);
  StackRoot _root2(&UP_node);

  UP_node = node;
  switch (node->tag()) {
    case rhs_word_e::Empty: {
      this->f->write(str1980);
    }
      break;
    case rhs_word_e::Compound: {
      CompoundWord* node = static_cast<CompoundWord*>(UP_node);
      style = _GetRhsStyle(node);
      if (style == word_style_e::SQ) {
        this->f->write(str1981);
        this->DoWordInCommand(node, local_symbols);
        this->f->write(str1982);
      }
      else {
        if (style == word_style_e::DQ) {
          this->f->write(str1983);
          this->DoWordInCommand(node, local_symbols);
          this->f->write(str1984);
        }
        else {
          if (word_::IsVarSub(node)) {
            ;  // pass
          }
          this->DoWordInCommand(node, local_symbols);
        }
      }
    }
      break;
  }
}

void YshPrinter::DoWordInCommand(syntax_asdl::word_t* node, Dict<BigStr*, bool>* local_symbols) {
  syntax_asdl::word_t* UP_node = nullptr;
  DoubleQuoted* dq_part = nullptr;
  syntax_asdl::word_part_t* part0 = nullptr;
  SimpleVarSub* vsub_part = nullptr;
  StackRoot _root0(&node);
  StackRoot _root1(&local_symbols);
  StackRoot _root2(&UP_node);
  StackRoot _root3(&dq_part);
  StackRoot _root4(&part0);
  StackRoot _root5(&vsub_part);

  UP_node = node;
  switch (node->tag()) {
    case word_e::Compound: {
      CompoundWord* node = static_cast<CompoundWord*>(UP_node);
      if ((len(node->parts) == 1 and node->parts->at(0)->tag() == word_part_e::DoubleQuoted)) {
        dq_part = static_cast<DoubleQuoted*>(node->parts->at(0));
        if (len(dq_part->parts) == 1) {
          part0 = dq_part->parts->at(0);
          if (part0->tag() == word_part_e::SimpleVarSub) {
            vsub_part = static_cast<SimpleVarSub*>(dq_part->parts->at(0));
            if (vsub_part->tok->id == Id::VSub_At) {
              this->cursor->PrintUntil(dq_part->left);
              this->cursor->SkipPast(dq_part->right);
              this->f->write(str1985);
              return ;
            }
            if ((vsub_part->tok->id == Id::VSub_Number || vsub_part->tok->id == Id::VSub_DollarName)) {
              this->cursor->PrintUntil(dq_part->left);
              this->cursor->SkipPast(dq_part->right);
              this->f->write(lexer::TokenVal(vsub_part->tok));
              return ;
            }
          }
          else {
            if (part0->tag() == word_part_e::BracedVarSub) {
              this->cursor->PrintUntil(dq_part->left);
              this->cursor->SkipPast(dq_part->left);
              this->DoWordPart(part0, local_symbols);
              this->cursor->SkipPast(dq_part->right);
              return ;
            }
            else {
              if (part0->tag() == word_part_e::CommandSub) {
                this->cursor->PrintUntil(dq_part->left);
                this->cursor->SkipPast(dq_part->left);
                this->DoWordPart(part0, local_symbols);
                this->cursor->SkipPast(dq_part->right);
                return ;
              }
            }
          }
        }
      }
      for (ListIter<syntax_asdl::word_part_t*> it(node->parts); !it.Done(); it.Next()) {
        syntax_asdl::word_part_t* part = it.Value();
        StackRoot _for(&part      );
        this->DoWordPart(part, local_symbols);
      }
    }
      break;
    case word_e::BracedTree: {
      ;  // pass
    }
      break;
    default: {
      assert(0);  // AssertionError
    }
  }
}

void YshPrinter::DoWordPart(syntax_asdl::word_part_t* node, Dict<BigStr*, bool>* local_symbols, bool quoted) {
  syntax_asdl::Token* left_tok = nullptr;
  syntax_asdl::word_part_t* UP_node = nullptr;
  syntax_asdl::Token* t = nullptr;
  BigStr* val = nullptr;
  int op_id;
  StackRoot _root0(&node);
  StackRoot _root1(&local_symbols);
  StackRoot _root2(&left_tok);
  StackRoot _root3(&UP_node);
  StackRoot _root4(&t);
  StackRoot _root5(&val);

  left_tok = location::LeftTokenForWordPart(node);
  if (left_tok) {
    this->cursor->PrintUntil(left_tok);
  }
  UP_node = node;
  switch (node->tag()) {
    case word_part_e::ShArrayLiteral: 
    case word_part_e::BashAssocLiteral: 
    case word_part_e::TildeSub: 
    case word_part_e::ExtGlob: {
      ;  // pass
    }
      break;
    case word_part_e::EscapedLiteral: {
      word_part::EscapedLiteral* node = static_cast<word_part::EscapedLiteral*>(UP_node);
      if (quoted) {
        ;  // pass
      }
      else {
        t = node->token;
        val = lexer::TokenSliceLeft(t, 1);
        if (!(str_equals(val, str1986))) {
          this->cursor->PrintUntil(t);
          this->cursor->SkipPast(t);
          this->f->write(StrFormat("'%s'", val));
        }
      }
    }
      break;
    case word_part_e::Literal: {
      Token* node = static_cast<Token*>(UP_node);
      this->cursor->PrintIncluding(node);
    }
      break;
    case word_part_e::SingleQuoted: {
      SingleQuoted* node = static_cast<SingleQuoted*>(UP_node);
      this->cursor->PrintUntil(node->right);
    }
      break;
    case word_part_e::DoubleQuoted: {
      DoubleQuoted* node = static_cast<DoubleQuoted*>(UP_node);
      for (ListIter<syntax_asdl::word_part_t*> it(node->parts); !it.Done(); it.Next()) {
        syntax_asdl::word_part_t* part = it.Value();
        StackRoot _for(&part      );
        this->DoWordPart(part, local_symbols, true);
      }
    }
      break;
    case word_part_e::SimpleVarSub: {
      SimpleVarSub* node = static_cast<SimpleVarSub*>(UP_node);
      op_id = node->tok->id;
      if (op_id == Id::VSub_DollarName) {
        this->cursor->PrintIncluding(node->tok);
      }
      else {
        if (op_id == Id::VSub_Number) {
          this->cursor->PrintIncluding(node->tok);
        }
        else {
          if (op_id == Id::VSub_At) {
            this->f->write(str1988);
            this->cursor->SkipPast(node->tok);
          }
          else {
            if (op_id == Id::VSub_Star) {
              this->f->write(str1989);
              this->cursor->SkipPast(node->tok);
            }
            else {
              if (op_id == Id::VSub_Pound) {
                this->f->write(str1990);
                this->cursor->SkipPast(node->tok);
              }
              else {
                ;  // pass
              }
            }
          }
        }
      }
    }
      break;
    case word_part_e::BracedVarSub: {
      BracedVarSub* node = static_cast<BracedVarSub*>(UP_node);
      this->cursor->PrintUntil(node->left);
      if (node->bracket_op) {
        ;  // pass
      }
      if (node->prefix_op) {
        ;  // pass
      }
      if (node->suffix_op) {
        ;  // pass
      }
      op_id = node->token->id;
      if (op_id == Id::VSub_QMark) {
        this->cursor->PrintIncluding(node->token);
      }
      this->cursor->PrintIncluding(node->right);
    }
      break;
    case word_part_e::CommandSub: {
      CommandSub* node = static_cast<CommandSub*>(UP_node);
      if (node->left_token->id == Id::Left_Backtick) {
        this->cursor->PrintUntil(node->left_token);
        this->f->write(str1991);
        this->cursor->SkipPast(node->left_token);
        this->DoCommand(node->child, local_symbols);
        this->cursor->SkipPast(node->right);
        this->f->write(str1992);
      }
      else {
        this->cursor->PrintIncluding(node->right);
      }
    }
      break;
    default: {
      ;  // pass
    }
  }
}

}  // define namespace ysh_ify

namespace expr_eval {  // define

using id_kind_asdl::Id;
using syntax_asdl::loc;
using syntax_asdl::loc_t;
using syntax_asdl::re;
using syntax_asdl::re_e;
using syntax_asdl::re_t;
using syntax_asdl::Token;
using syntax_asdl::SimpleVarSub;
using syntax_asdl::word_part;
using syntax_asdl::SingleQuoted;
using syntax_asdl::DoubleQuoted;
using syntax_asdl::BracedVarSub;
using syntax_asdl::ShArrayLiteral;
using syntax_asdl::CommandSub;
using syntax_asdl::expr;
using syntax_asdl::expr_e;
using syntax_asdl::expr_t;
using syntax_asdl::y_lhs_e;
using syntax_asdl::y_lhs_t;
using syntax_asdl::Attribute;
using syntax_asdl::Subscript;
using syntax_asdl::class_literal_term;
using syntax_asdl::class_literal_term_e;
using syntax_asdl::class_literal_term_t;
using syntax_asdl::char_class_term_t;
using syntax_asdl::PosixClass;
using syntax_asdl::PerlClass;
using syntax_asdl::CharCode;
using syntax_asdl::CharRange;
using syntax_asdl::ArgList;
using syntax_asdl::Eggex;
using runtime_asdl::coerced_e;
using runtime_asdl::coerced_t;
using runtime_asdl::scope_e;
using runtime_asdl::scope_t;
using runtime_asdl::part_value;
using runtime_asdl::part_value_t;
using runtime_asdl::Piece;
using value_asdl::value;
using value_asdl::value_e;
using value_asdl::value_t;
using value_asdl::y_lvalue;
using value_asdl::y_lvalue_e;
using value_asdl::y_lvalue_t;
using value_asdl::IntBox;
using value_asdl::LeftName;
using error::e_die;
using error::e_die_status;
using mylib::print_stderr;

value_asdl::value_t* LookupVar(state::Mem* mem, BigStr* var_name, runtime_asdl::scope_t which_scopes, syntax_asdl::loc_t* var_loc) {
  value_asdl::value_t* val = nullptr;
  StackRoot _root0(&mem);
  StackRoot _root1(&var_name);
  StackRoot _root2(&var_loc);
  StackRoot _root3(&val);

  val = mem->GetValue(var_name, which_scopes);
  if (val->tag() == value_e::Undef) {
    e_die(StrFormat("Undefined variable %r", var_name), var_loc);
  }
  return val;
}

mops::BigInt _ConvertToInt(value_asdl::value_t* val, BigStr* msg, syntax_asdl::loc_t* blame_loc) {
  value_asdl::value_t* UP_val = nullptr;
  StackRoot _root0(&val);
  StackRoot _root1(&msg);
  StackRoot _root2(&blame_loc);
  StackRoot _root3(&UP_val);

  UP_val = val;
  switch (val->tag()) {
    case value_e::Int: {
      value::Int* val = static_cast<value::Int*>(UP_val);
      return val->i;
    }
      break;
    case value_e::Str: {
      value::Str* val = static_cast<value::Str*>(UP_val);
      if (match::LooksLikeInteger(val->s)) {
        return mops::FromStr(val->s);
      }
    }
      break;
  }
  throw Alloc<error::TypeErr>(val, msg, blame_loc);
}

Tuple3<runtime_asdl::coerced_t, mops::BigInt, double> _ConvertToNumber(value_asdl::value_t* val) {
  value_asdl::value_t* UP_val = nullptr;
  StackRoot _root0(&val);
  StackRoot _root1(&UP_val);

  UP_val = val;
  switch (val->tag()) {
    case value_e::Int: {
      value::Int* val = static_cast<value::Int*>(UP_val);
      return Tuple3<runtime_asdl::coerced_t, mops::BigInt, double>(coerced_e::Int, val->i, -1.0);
    }
      break;
    case value_e::Float: {
      value::Float* val = static_cast<value::Float*>(UP_val);
      return Tuple3<runtime_asdl::coerced_t, mops::BigInt, double>(coerced_e::Float, mops::MINUS_ONE, val->f);
    }
      break;
    case value_e::Str: {
      value::Str* val = static_cast<value::Str*>(UP_val);
      if (match::LooksLikeInteger(val->s)) {
        return Tuple3<runtime_asdl::coerced_t, mops::BigInt, double>(coerced_e::Int, mops::FromStr(val->s), -1.0);
      }
      if (match::LooksLikeFloat(val->s)) {
        return Tuple3<runtime_asdl::coerced_t, mops::BigInt, double>(coerced_e::Float, mops::MINUS_ONE, to_float(val->s));
      }
    }
      break;
  }
  return Tuple3<runtime_asdl::coerced_t, mops::BigInt, double>(coerced_e::Neither, mops::MINUS_ONE, -1.0);
}

Tuple5<runtime_asdl::coerced_t, mops::BigInt, mops::BigInt, double, double> _ConvertForBinaryOp(value_asdl::value_t* left, value_asdl::value_t* right) {
  runtime_asdl::coerced_t c1;
  mops::BigInt i1;
  double f1;
  runtime_asdl::coerced_t c2;
  mops::BigInt i2;
  double f2;
  mops::BigInt nope;
  StackRoot _root0(&left);
  StackRoot _root1(&right);

  Tuple3<runtime_asdl::coerced_t, mops::BigInt, double> tup0 = _ConvertToNumber(left);
  c1 = tup0.at0();
  i1 = tup0.at1();
  f1 = tup0.at2();
  Tuple3<runtime_asdl::coerced_t, mops::BigInt, double> tup1 = _ConvertToNumber(right);
  c2 = tup1.at0();
  i2 = tup1.at1();
  f2 = tup1.at2();
  nope = mops::MINUS_ONE;
  if ((c1 == coerced_e::Int and c2 == coerced_e::Int)) {
    return Tuple5<runtime_asdl::coerced_t, mops::BigInt, mops::BigInt, double, double>(coerced_e::Int, i1, i2, -1.0, -1.0);
  }
  else {
    if ((c1 == coerced_e::Int and c2 == coerced_e::Float)) {
      return Tuple5<runtime_asdl::coerced_t, mops::BigInt, mops::BigInt, double, double>(coerced_e::Float, nope, nope, mops::ToFloat(i1), f2);
    }
    else {
      if ((c1 == coerced_e::Float and c2 == coerced_e::Int)) {
        return Tuple5<runtime_asdl::coerced_t, mops::BigInt, mops::BigInt, double, double>(coerced_e::Float, nope, nope, f1, mops::ToFloat(i2));
      }
      else {
        if ((c1 == coerced_e::Float and c2 == coerced_e::Float)) {
          return Tuple5<runtime_asdl::coerced_t, mops::BigInt, mops::BigInt, double, double>(coerced_e::Float, nope, nope, f1, f2);
        }
        else {
          return Tuple5<runtime_asdl::coerced_t, mops::BigInt, mops::BigInt, double, double>(coerced_e::Neither, nope, nope, -1.0, -1.0);
        }
      }
    }
  }
}

ExprEvaluator::ExprEvaluator(state::Mem* mem, state::MutableOpts* mutable_opts, Dict<int, Dict<BigStr*, vm::_Callable*>*>* methods, split::SplitContext* splitter, ui::ErrorFormatter* errfmt) {
  this->shell_ex = nullptr;
  this->cmd_ev = nullptr;
  this->word_ev = nullptr;
  this->mem = mem;
  this->mutable_opts = mutable_opts;
  this->methods = methods;
  this->splitter = splitter;
  this->errfmt = errfmt;
}

void ExprEvaluator::CheckCircularDeps() {
}

value_asdl::value_t* ExprEvaluator::_LookupVar(BigStr* name, syntax_asdl::loc_t* var_loc) {
  StackRoot _root0(&name);
  StackRoot _root1(&var_loc);

  return LookupVar(this->mem, name, scope_e::LocalOrGlobal, var_loc);
}

void ExprEvaluator::EvalAugmented(value_asdl::y_lvalue_t* lval, value_asdl::value_t* rhs_val, syntax_asdl::Token* op, runtime_asdl::scope_t which_scopes) {
  value_asdl::y_lvalue_t* UP_lval = nullptr;
  value_asdl::value_t* lhs_val = nullptr;
  value_asdl::value_t* new_val = nullptr;
  value_asdl::value_t* obj = nullptr;
  value_asdl::value_t* UP_obj = nullptr;
  value_asdl::value_t* lhs_val_ = nullptr;
  int index;
  BigStr* key = nullptr;
  value_asdl::value_t* new_val_ = nullptr;
  StackRoot _root0(&lval);
  StackRoot _root1(&rhs_val);
  StackRoot _root2(&op);
  StackRoot _root3(&UP_lval);
  StackRoot _root4(&lhs_val);
  StackRoot _root5(&new_val);
  StackRoot _root6(&obj);
  StackRoot _root7(&UP_obj);
  StackRoot _root8(&lhs_val_);
  StackRoot _root9(&key);
  StackRoot _root10(&new_val_);

  UP_lval = lval;
  switch (lval->tag()) {
    case y_lvalue_e::Local: {
      LeftName* lval = static_cast<LeftName*>(UP_lval);
      lhs_val = this->_LookupVar(lval->name, lval->blame_loc);
      if ((op->id == Id::Arith_PlusEqual || op->id == Id::Arith_MinusEqual || op->id == Id::Arith_StarEqual || op->id == Id::Arith_SlashEqual)) {
        new_val = this->_ArithIntFloat(lhs_val, rhs_val, op);
      }
      else {
        new_val = this->_ArithIntOnly(lhs_val, rhs_val, op);
      }
      this->mem->SetNamed(lval, new_val, which_scopes);
    }
      break;
    case y_lvalue_e::Container: {
      y_lvalue::Container* lval = static_cast<y_lvalue::Container*>(UP_lval);
      obj = lval->obj;
      UP_obj = obj;
      lhs_val_ = nullptr;
      switch (obj->tag()) {
        case value_e::List: {
          value::List* obj = static_cast<value::List*>(UP_obj);
          index = val_ops::ToInt(lval->index, str1994, loc::Missing);
          try {
            lhs_val_ = obj->items->at(index);
          }
          catch (IndexError*) {
            throw Alloc<error::Expr>(StrFormat("List index out of range: %d", index), loc::Missing);
          }
        }
          break;
        case value_e::Dict: {
          value::Dict* obj = static_cast<value::Dict*>(UP_obj);
          index = -1;
          key = val_ops::ToStr(lval->index, str1996, loc::Missing);
          try {
            lhs_val_ = obj->d->at(key);
          }
          catch (KeyError*) {
            throw Alloc<error::Expr>(StrFormat("Dict entry not found: %r", key), loc::Missing);
          }
        }
          break;
        default: {
          throw Alloc<error::TypeErr>(obj, str1998, loc::Missing);
        }
      }
      if ((op->id == Id::Arith_PlusEqual || op->id == Id::Arith_MinusEqual || op->id == Id::Arith_StarEqual || op->id == Id::Arith_SlashEqual)) {
        new_val_ = this->_ArithIntFloat(lhs_val_, rhs_val, op);
      }
      else {
        new_val_ = this->_ArithIntOnly(lhs_val_, rhs_val, op);
      }
      switch (obj->tag()) {
        case value_e::List: {
          value::List* obj = static_cast<value::List*>(UP_obj);
          obj->items->set(index, new_val_);
        }
          break;
        case value_e::Dict: {
          value::Dict* obj = static_cast<value::Dict*>(UP_obj);
          obj->d->set(key, new_val_);
        }
          break;
      }
    }
      break;
    default: {
      assert(0);  // AssertionError
    }
  }
}

value_asdl::value_t* ExprEvaluator::_EvalLeftLocalOrGlobal(syntax_asdl::expr_t* lhs, runtime_asdl::scope_t which_scopes) {
  syntax_asdl::expr_t* UP_lhs = nullptr;
  value_asdl::value_t* obj = nullptr;
  value_asdl::value_t* index = nullptr;
  StackRoot _root0(&lhs);
  StackRoot _root1(&UP_lhs);
  StackRoot _root2(&obj);
  StackRoot _root3(&index);

  UP_lhs = lhs;
  switch (lhs->tag()) {
    case expr_e::Var: {
      expr::Var* lhs = static_cast<expr::Var*>(UP_lhs);
      return LookupVar(this->mem, lhs->name, which_scopes, lhs->left);
    }
      break;
    case expr_e::Subscript: {
      Subscript* lhs = static_cast<Subscript*>(UP_lhs);
      obj = this->_EvalLeftLocalOrGlobal(lhs->obj, which_scopes);
      index = this->_EvalExpr(lhs->index);
      return this->_EvalSubscript(obj, index);
    }
      break;
    case expr_e::Attribute: {
      Attribute* lhs = static_cast<Attribute*>(UP_lhs);
      obj = this->_EvalLeftLocalOrGlobal(lhs->obj, which_scopes);
      return this->_EvalDot(lhs, obj);
    }
      break;
    default: {
      assert(0);  // AssertionError
    }
  }
}

value_asdl::y_lvalue_t* ExprEvaluator::_EvalLhsExpr(syntax_asdl::y_lhs_t* lhs, runtime_asdl::scope_t which_scopes) {
  syntax_asdl::y_lhs_t* UP_lhs = nullptr;
  value_asdl::value_t* lval = nullptr;
  value_asdl::value_t* index = nullptr;
  value::Str* attr = nullptr;
  StackRoot _root0(&lhs);
  StackRoot _root1(&UP_lhs);
  StackRoot _root2(&lval);
  StackRoot _root3(&index);
  StackRoot _root4(&attr);

  UP_lhs = lhs;
  switch (lhs->tag()) {
    case y_lhs_e::Var: {
      Token* lhs = static_cast<Token*>(UP_lhs);
      return Alloc<LeftName>(lexer::LazyStr(lhs), lhs);
    }
      break;
    case y_lhs_e::Subscript: {
      Subscript* lhs = static_cast<Subscript*>(UP_lhs);
      lval = this->_EvalLeftLocalOrGlobal(lhs->obj, which_scopes);
      index = this->_EvalExpr(lhs->index);
      return Alloc<y_lvalue::Container>(lval, index);
    }
      break;
    case y_lhs_e::Attribute: {
      Attribute* lhs = static_cast<Attribute*>(UP_lhs);
      lval = this->_EvalLeftLocalOrGlobal(lhs->obj, which_scopes);
      attr = Alloc<value::Str>(lhs->attr_name);
      return Alloc<y_lvalue::Container>(lval, attr);
    }
      break;
    default: {
      assert(0);  // AssertionError
    }
  }
}

value_asdl::value_t* ExprEvaluator::EvalExpr(syntax_asdl::expr_t* node, syntax_asdl::loc_t* blame_loc) {
  value_asdl::value_t* val = nullptr;
  StackRoot _root0(&node);
  StackRoot _root1(&blame_loc);
  StackRoot _root2(&val);

  this->mem->SetLocationForExpr(blame_loc);
  {  // with
    state::ctx_YshExpr ctx{this->mutable_opts};

    val = this->_EvalExpr(node);
  }
  return val;
}

value_asdl::y_lvalue_t* ExprEvaluator::EvalLhsExpr(syntax_asdl::y_lhs_t* lhs, runtime_asdl::scope_t which_scopes) {
  value_asdl::y_lvalue_t* lval = nullptr;
  StackRoot _root0(&lhs);
  StackRoot _root1(&lval);

  {  // with
    state::ctx_YshExpr ctx{this->mutable_opts};

    lval = this->_EvalLhsExpr(lhs, which_scopes);
  }
  return lval;
}

runtime_asdl::part_value_t* ExprEvaluator::EvalExprSub(word_part::ExprSub* part) {
  value_asdl::value_t* val = nullptr;
  BigStr* s = nullptr;
  List<BigStr*>* strs = nullptr;
  StackRoot _root0(&part);
  StackRoot _root1(&val);
  StackRoot _root2(&s);
  StackRoot _root3(&strs);

  val = this->EvalExpr(part->child, part->left);
  switch (part->left->id) {
    case Id::Left_DollarBracket: {
      s = val_ops::Stringify(val, Alloc<loc::WordPart>(part));
      return Alloc<Piece>(s, false, false);
    }
      break;
    case Id::Lit_AtLBracket: {
      strs = val_ops::ToShellArray(val, Alloc<loc::WordPart>(part), str1999);
      return Alloc<part_value::Array>(strs);
    }
      break;
    default: {
      assert(0);  // AssertionError
    }
  }
}

value_asdl::value_t* ExprEvaluator::PluginCall(value::Func* func_val, List<value_asdl::value_t*>* pos_args) {
  Dict<BigStr*, value_asdl::value_t*>* named_args = nullptr;
  syntax_asdl::ArgList* arg_list = nullptr;
  typed_args::Reader* rd = nullptr;
  value_asdl::value_t* val = nullptr;
  StackRoot _root0(&func_val);
  StackRoot _root1(&pos_args);
  StackRoot _root2(&named_args);
  StackRoot _root3(&arg_list);
  StackRoot _root4(&rd);
  StackRoot _root5(&val);

  {  // with
    state::ctx_YshExpr ctx{this->mutable_opts};

    {  // with
      state::ctx_Registers ctx{this->mem};

      named_args = Alloc<Dict<BigStr*, value_asdl::value_t*>>();
      arg_list = ArgList::CreateNull();
      rd = Alloc<typed_args::Reader>(pos_args, named_args, nullptr, arg_list);
      try {
        val = func_proc::CallUserFunc(func_val, rd, this->mem, this->cmd_ev);
      }
      catch (error::FatalRuntime* e) {
        val = Alloc<value::Str>(StrFormat("<Runtime error: %s>", e->UserErrorString()));
      }
      catch (IOError_OSError* e) {
        val = Alloc<value::Str>(StrFormat("<I/O error: %s>", pyutil::strerror(e)));
      }
      catch (KeyboardInterrupt*) {
        val = Alloc<value::Str>(str2002);
      }
    }
  }
  return val;
}

value_asdl::value_t* ExprEvaluator::CallConvertFunc(value_asdl::value_t* func_val, value_asdl::value_t* arg, syntax_asdl::Token* convert_tok, syntax_asdl::loc_t* call_loc) {
  List<value_asdl::value_t*>* pos_args = nullptr;
  Dict<BigStr*, value_asdl::value_t*>* named_args = nullptr;
  syntax_asdl::ArgList* arg_list = nullptr;
  typed_args::Reader* rd = nullptr;
  value_asdl::value_t* val = nullptr;
  BigStr* func_name = nullptr;
  StackRoot _root0(&func_val);
  StackRoot _root1(&arg);
  StackRoot _root2(&convert_tok);
  StackRoot _root3(&call_loc);
  StackRoot _root4(&pos_args);
  StackRoot _root5(&named_args);
  StackRoot _root6(&arg_list);
  StackRoot _root7(&rd);
  StackRoot _root8(&val);
  StackRoot _root9(&func_name);

  {  // with
    state::ctx_YshExpr ctx{this->mutable_opts};

    pos_args = NewList<value_asdl::value_t*>(std::initializer_list<value_asdl::value_t*>{arg});
    named_args = Alloc<Dict<BigStr*, value_asdl::value_t*>>();
    arg_list = ArgList::CreateNull();
    rd = Alloc<typed_args::Reader>(pos_args, named_args, nullptr, arg_list);
    rd->SetFallbackLocation(convert_tok);
    try {
      val = this->_CallFunc(func_val, rd);
    }
    catch (error::FatalRuntime* e) {
      func_name = lexer::TokenVal(convert_tok);
      this->errfmt->Print_(StrFormat("Fatal error calling Eggex conversion func %r from this Match accessor", func_name), call_loc);
      print_stderr(str2004);
      throw ;
    }
  }
  return val;
}

List<BigStr*>* ExprEvaluator::SpliceValue(value_asdl::value_t* val, word_part::Splice* part) {
  StackRoot _root0(&val);
  StackRoot _root1(&part);

  return val_ops::ToShellArray(val, Alloc<loc::WordPart>(part), str2005);
}

value_asdl::value_t* ExprEvaluator::_EvalConst(expr::Const* node) {
  StackRoot _root0(&node);

  return node->val;
}

value_asdl::value_t* ExprEvaluator::_EvalUnary(expr::Unary* node) {
  value_asdl::value_t* val = nullptr;
  runtime_asdl::coerced_t c1;
  mops::BigInt i1;
  double f1;
  mops::BigInt i;
  bool b;
  StackRoot _root0(&node);
  StackRoot _root1(&val);

  val = this->_EvalExpr(node->child);
  switch (node->op->id) {
    case Id::Arith_Minus: {
      Tuple3<runtime_asdl::coerced_t, mops::BigInt, double> tup2 = _ConvertToNumber(val);
      c1 = tup2.at0();
      i1 = tup2.at1();
      f1 = tup2.at2();
      if (c1 == coerced_e::Int) {
        return Alloc<value::Int>(mops::Negate(i1));
      }
      if (c1 == coerced_e::Float) {
        return Alloc<value::Float>(-f1);
      }
      throw Alloc<error::TypeErr>(val, str2006, node->op);
    }
      break;
    case Id::Arith_Tilde: {
      i = _ConvertToInt(val, str2007, node->op);
      return Alloc<value::Int>(mops::BitNot(i));
    }
      break;
    case Id::Expr_Not: {
      b = val_ops::ToBool(val);
      return Alloc<value::Bool>(b ? false : true);
    }
      break;
    case Id::Arith_Amp: {
      FAIL(kNotImplemented);  // Python NotImplementedError
    }
      break;
    default: {
      assert(0);  // AssertionError
    }
  }
  assert(0);  // AssertionError
}

value_asdl::value_t* ExprEvaluator::_ArithIntFloat(value_asdl::value_t* left, value_asdl::value_t* right, syntax_asdl::Token* op) {
  runtime_asdl::coerced_t c;
  mops::BigInt i1;
  mops::BigInt i2;
  double f1;
  double f2;
  int op_id;
  StackRoot _root0(&left);
  StackRoot _root1(&right);
  StackRoot _root2(&op);

  Tuple5<runtime_asdl::coerced_t, mops::BigInt, mops::BigInt, double, double> tup3 = _ConvertForBinaryOp(left, right);
  c = tup3.at0();
  i1 = tup3.at1();
  i2 = tup3.at2();
  f1 = tup3.at3();
  f2 = tup3.at4();
  op_id = op->id;
  if (c == coerced_e::Int) {
    switch (op_id) {
      case Id::Arith_Plus: 
      case Id::Arith_PlusEqual: {
        return Alloc<value::Int>(mops::Add(i1, i2));
      }
        break;
      case Id::Arith_Minus: 
      case Id::Arith_MinusEqual: {
        return Alloc<value::Int>(mops::Sub(i1, i2));
      }
        break;
      case Id::Arith_Star: 
      case Id::Arith_StarEqual: {
        return Alloc<value::Int>(mops::Mul(i1, i2));
      }
        break;
      case Id::Arith_Slash: 
      case Id::Arith_SlashEqual: {
        if (mops::Equal(i2, mops::ZERO)) {
          throw Alloc<error::Expr>(str2009, op);
        }
        return Alloc<value::Float>((mops::ToFloat(i1) / mops::ToFloat(i2)));
      }
        break;
      default: {
        assert(0);  // AssertionError
      }
    }
  }
  else {
    if (c == coerced_e::Float) {
      switch (op_id) {
        case Id::Arith_Plus: 
        case Id::Arith_PlusEqual: {
          return Alloc<value::Float>((f1 + f2));
        }
          break;
        case Id::Arith_Minus: 
        case Id::Arith_MinusEqual: {
          return Alloc<value::Float>((f1 - f2));
        }
          break;
        case Id::Arith_Star: 
        case Id::Arith_StarEqual: {
          return Alloc<value::Float>((f1 * f2));
        }
          break;
        case Id::Arith_Slash: 
        case Id::Arith_SlashEqual: {
          if (f2 == 0.0) {
            throw Alloc<error::Expr>(str2010, op);
          }
          return Alloc<value::Float>((f1 / f2));
        }
          break;
        default: {
          assert(0);  // AssertionError
        }
      }
    }
    else {
      throw Alloc<error::TypeErrVerbose>(StrFormat("Binary operator expected numbers, got %s and %s (OILS-ERR-201)", ui::ValType(left), ui::ValType(right)), op);
    }
  }
}

value_asdl::value_t* ExprEvaluator::_ArithIntOnly(value_asdl::value_t* left, value_asdl::value_t* right, syntax_asdl::Token* op) {
  mops::BigInt i1;
  mops::BigInt i2;
  StackRoot _root0(&left);
  StackRoot _root1(&right);
  StackRoot _root2(&op);

  i1 = _ConvertToInt(left, str2012, op);
  i2 = _ConvertToInt(right, str2013, op);
  switch (op->id) {
    case Id::Arith_Percent: 
    case Id::Arith_PercentEqual: {
      if (mops::Equal(i2, mops::ZERO)) {
        throw Alloc<error::Expr>(str2014, op);
      }
      if (mops::Greater(mops::ZERO, i2)) {
        throw Alloc<error::Expr>(str2015, op);
      }
      return Alloc<value::Int>(num::IntRemainder(i1, i2));
    }
      break;
    case Id::Expr_DSlash: 
    case Id::Expr_DSlashEqual: {
      if (mops::Equal(i2, mops::ZERO)) {
        throw Alloc<error::Expr>(str2016, op);
      }
      return Alloc<value::Int>(num::IntDivide(i1, i2));
    }
      break;
    case Id::Arith_DStar: 
    case Id::Expr_DStarEqual: {
      if (mops::Greater(mops::ZERO, i2)) {
        throw Alloc<error::Expr>(str2017, op);
      }
      return Alloc<value::Int>(num::Exponent(i1, i2));
    }
      break;
    case Id::Arith_Amp: 
    case Id::Arith_AmpEqual: {
      return Alloc<value::Int>(mops::BitAnd(i1, i2));
    }
      break;
    case Id::Arith_Pipe: 
    case Id::Arith_PipeEqual: {
      return Alloc<value::Int>(mops::BitOr(i1, i2));
    }
      break;
    case Id::Arith_Caret: 
    case Id::Arith_CaretEqual: {
      return Alloc<value::Int>(mops::BitXor(i1, i2));
    }
      break;
    case Id::Arith_DGreat: 
    case Id::Arith_DGreatEqual: {
      return Alloc<value::Int>(mops::RShift(i1, i2));
    }
      break;
    case Id::Arith_DLess: 
    case Id::Arith_DLessEqual: {
      return Alloc<value::Int>(mops::LShift(i1, i2));
    }
      break;
    default: {
      assert(0);  // AssertionError
    }
  }
}

value_asdl::value_t* ExprEvaluator::_Concat(value_asdl::value_t* left, value_asdl::value_t* right, syntax_asdl::Token* op) {
  value_asdl::value_t* UP_left = nullptr;
  value_asdl::value_t* UP_right = nullptr;
  List<value_asdl::value_t*>* c = nullptr;
  StackRoot _root0(&left);
  StackRoot _root1(&right);
  StackRoot _root2(&op);
  StackRoot _root3(&UP_left);
  StackRoot _root4(&UP_right);
  StackRoot _root5(&c);

  UP_left = left;
  UP_right = right;
  if ((left->tag() == value_e::Str and right->tag() == value_e::Str)) {
    value::Str* left = static_cast<value::Str*>(UP_left);
    value::Str* right = static_cast<value::Str*>(UP_right);
    return Alloc<value::Str>(str_concat(left->s, right->s));
  }
  else {
    if ((left->tag() == value_e::List and right->tag() == value_e::List)) {
      value::List* left = static_cast<value::List*>(UP_left);
      value::List* right = static_cast<value::List*>(UP_right);
      c = list(left->items);
      c->extend(right->items);
      return Alloc<value::List>(c);
    }
    else {
      throw Alloc<error::TypeErrVerbose>(StrFormat("Expected Str ++ Str or List ++ List, got %s ++ %s", ui::ValType(left), ui::ValType(right)), op);
    }
  }
}

value_asdl::value_t* ExprEvaluator::_EvalBinary(expr::Binary* node) {
  value_asdl::value_t* left = nullptr;
  value_asdl::value_t* right = nullptr;
  StackRoot _root0(&node);
  StackRoot _root1(&left);
  StackRoot _root2(&right);

  left = this->_EvalExpr(node->left);
  switch (node->op->id) {
    case Id::Expr_And: {
      if (val_ops::ToBool(left)) {
        return this->_EvalExpr(node->right);
      }
      else {
        return left;
      }
    }
      break;
    case Id::Expr_Or: {
      if (val_ops::ToBool(left)) {
        return left;
      }
      else {
        return this->_EvalExpr(node->right);
      }
    }
      break;
  }
  right = this->_EvalExpr(node->right);
  switch (node->op->id) {
    case Id::Arith_DPlus: {
      return this->_Concat(left, right, node->op);
    }
      break;
    case Id::Arith_Plus: 
    case Id::Arith_Minus: 
    case Id::Arith_Star: 
    case Id::Arith_Slash: {
      return this->_ArithIntFloat(left, right, node->op);
    }
      break;
    default: {
      return this->_ArithIntOnly(left, right, node->op);
    }
  }
}

bool ExprEvaluator::_CompareNumeric(value_asdl::value_t* left, value_asdl::value_t* right, syntax_asdl::Token* op) {
  runtime_asdl::coerced_t c;
  mops::BigInt i1;
  mops::BigInt i2;
  double f1;
  double f2;
  StackRoot _root0(&left);
  StackRoot _root1(&right);
  StackRoot _root2(&op);

  Tuple5<runtime_asdl::coerced_t, mops::BigInt, mops::BigInt, double, double> tup4 = _ConvertForBinaryOp(left, right);
  c = tup4.at0();
  i1 = tup4.at1();
  i2 = tup4.at2();
  f1 = tup4.at3();
  f2 = tup4.at4();
  if (c == coerced_e::Int) {
    switch (op->id) {
      case Id::Arith_Less: {
        return mops::Greater(i2, i1);
      }
        break;
      case Id::Arith_Great: {
        return mops::Greater(i1, i2);
      }
        break;
      case Id::Arith_LessEqual: {
        return (mops::Greater(i2, i1) or mops::Equal(i1, i2));
      }
        break;
      case Id::Arith_GreatEqual: {
        return (mops::Greater(i1, i2) or mops::Equal(i1, i2));
      }
        break;
      default: {
        assert(0);  // AssertionError
      }
    }
  }
  else {
    if (c == coerced_e::Float) {
      switch (op->id) {
        case Id::Arith_Less: {
          return f1 < f2;
        }
          break;
        case Id::Arith_Great: {
          return f1 > f2;
        }
          break;
        case Id::Arith_LessEqual: {
          return f1 <= f2;
        }
          break;
        case Id::Arith_GreatEqual: {
          return f1 >= f2;
        }
          break;
        default: {
          assert(0);  // AssertionError
        }
      }
    }
    else {
      throw Alloc<error::TypeErrVerbose>(StrFormat("Comparison operator expected numbers, got %s and %s", ui::ValType(left), ui::ValType(right)), op);
    }
  }
}

value_asdl::value_t* ExprEvaluator::_EvalCompare(expr::Compare* node) {
  value_asdl::value_t* left = nullptr;
  bool result;
  int i;
  syntax_asdl::expr_t* right_expr = nullptr;
  value_asdl::value_t* right = nullptr;
  value_asdl::value_t* UP_left = nullptr;
  value_asdl::value_t* UP_right = nullptr;
  BigStr* left2 = nullptr;
  bool lb;
  bool eq;
  StackRoot _root0(&node);
  StackRoot _root1(&left);
  StackRoot _root2(&right_expr);
  StackRoot _root3(&right);
  StackRoot _root4(&UP_left);
  StackRoot _root5(&UP_right);
  StackRoot _root6(&left2);

  left = this->_EvalExpr(node->left);
  result = true;
  i = 0;
  for (ListIter<syntax_asdl::Token*> it(node->ops); !it.Done(); it.Next(), ++i) {
    syntax_asdl::Token* op = it.Value();
    StackRoot _for(&op  );
    right_expr = node->comparators->at(i);
    right = this->_EvalExpr(right_expr);
    if ((op->id == Id::Arith_Less || op->id == Id::Arith_Great || op->id == Id::Arith_LessEqual || op->id == Id::Arith_GreatEqual)) {
      result = this->_CompareNumeric(left, right, op);
    }
    else {
      if (op->id == Id::Expr_TEqual) {
        if (left->tag() != right->tag()) {
          result = false;
        }
        else {
          result = val_ops::ExactlyEqual(left, right, op);
        }
      }
      else {
        if (op->id == Id::Expr_NotDEqual) {
          if (left->tag() != right->tag()) {
            result = true;
          }
          else {
            result = !val_ops::ExactlyEqual(left, right, op);
          }
        }
        else {
          if (op->id == Id::Expr_In) {
            result = val_ops::Contains(left, right);
          }
          else {
            if (op->id == Id::Node_NotIn) {
              result = !val_ops::Contains(left, right);
            }
            else {
              if (op->id == Id::Expr_Is) {
                if (left->tag() != right->tag()) {
                  throw Alloc<error::TypeErrVerbose>(str2020, op);
                }
                result = left == right;
              }
              else {
                if (op->id == Id::Node_IsNot) {
                  if (left->tag() != right->tag()) {
                    throw Alloc<error::TypeErrVerbose>(str2021, op);
                  }
                  result = left != right;
                }
                else {
                  if (op->id == Id::Expr_DTilde) {
                    if (left->tag() != value_e::Str) {
                      throw Alloc<error::TypeErrVerbose>(str2022, op);
                    }
                    if (right->tag() != value_e::Str) {
                      throw Alloc<error::TypeErrVerbose>(str2023, op);
                    }
                    UP_left = left;
                    UP_right = right;
                    value::Str* left = static_cast<value::Str*>(UP_left);
                    value::Str* right = static_cast<value::Str*>(UP_right);
                    return Alloc<value::Bool>(libc::fnmatch(right->s, left->s));
                  }
                  else {
                    if (op->id == Id::Expr_NotDTilde) {
                      if (left->tag() != value_e::Str) {
                        throw Alloc<error::TypeErrVerbose>(str2024, op);
                      }
                      if (right->tag() != value_e::Str) {
                        throw Alloc<error::TypeErrVerbose>(str2025, op);
                      }
                      UP_left = left;
                      UP_right = right;
                      value::Str* left = static_cast<value::Str*>(UP_left);
                      value::Str* right = static_cast<value::Str*>(UP_right);
                      return Alloc<value::Bool>(!libc::fnmatch(right->s, left->s));
                    }
                    else {
                      if (op->id == Id::Expr_TildeDEqual) {
                        UP_left = left;
                        if (left->tag() != value_e::Str) {
                          e_die(str2026, op);
                        }
                        value::Str* left = static_cast<value::Str*>(UP_left);
                        left2 = left->s->strip();
                        UP_right = right;
                        switch (right->tag()) {
                          case value_e::Str: {
                            value::Str* right = static_cast<value::Str*>(UP_right);
                            return Alloc<value::Bool>(str_equals(left2, right->s));
                          }
                            break;
                          case value_e::Bool: {
                            value::Bool* right = static_cast<value::Bool*>(UP_right);
                            left2 = left2->lower();
                            lb = false;
                            if (str_equals(left2, str2027)) {
                              lb = true;
                            }
                            else {
                              if (str_equals(left2, str2028)) {
                                lb = false;
                              }
                              else {
                                return Alloc<value::Bool>(false);
                              }
                            }
                            return Alloc<value::Bool>(lb == right->b);
                          }
                            break;
                          case value_e::Int: {
                            value::Int* right = static_cast<value::Int*>(UP_right);
                            if (!left2->isdigit()) {
                              return Alloc<value::Bool>(false);
                            }
                            eq = mops::Equal(mops::FromStr(left2), right->i);
                            return Alloc<value::Bool>(eq);
                          }
                            break;
                        }
                        e_die(str2029, op);
                      }
                      else {
                        try {
                          if (op->id == Id::Arith_Tilde) {
                            result = val_ops::MatchRegex(left, right, this->mem);
                          }
                          else {
                            if (op->id == Id::Expr_NotTilde) {
                              result = !val_ops::MatchRegex(left, right, nullptr);
                            }
                            else {
                              assert(0);  // AssertionError
                            }
                          }
                        }
                        catch (ValueError* e) {
                          e_die_status(2, e->message, op);
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
    if (!result) {
      return Alloc<value::Bool>(result);
    }
    left = right;
  }
  return Alloc<value::Bool>(result);
}

value_asdl::value_t* ExprEvaluator::_CallFunc(value_asdl::value_t* to_call, typed_args::Reader* rd) {
  value_asdl::value_t* UP_to_call = nullptr;
  vm::_Callable* f = nullptr;
  StackRoot _root0(&to_call);
  StackRoot _root1(&rd);
  StackRoot _root2(&UP_to_call);
  StackRoot _root3(&f);

  UP_to_call = to_call;
  switch (to_call->tag()) {
    case value_e::Func: {
      value::Func* to_call = static_cast<value::Func*>(UP_to_call);
      return func_proc::CallUserFunc(to_call, rd, this->mem, this->cmd_ev);
    }
      break;
    case value_e::BuiltinFunc: {
      value::BuiltinFunc* to_call = static_cast<value::BuiltinFunc*>(UP_to_call);
      f = static_cast<vm::_Callable*>(to_call->callable);
      return f->Call(rd);
    }
      break;
    default: {
      assert(0);  // AssertionError
    }
  }
}

value_asdl::value_t* ExprEvaluator::_EvalFuncCall(expr::FuncCall* node) {
  value_asdl::value_t* func = nullptr;
  value_asdl::value_t* UP_func = nullptr;
  value_asdl::value_t* to_call = nullptr;
  List<value_asdl::value_t*>* pos_args = nullptr;
  Dict<BigStr*, value_asdl::value_t*>* named_args = nullptr;
  typed_args::Reader* rd = nullptr;
  StackRoot _root0(&node);
  StackRoot _root1(&func);
  StackRoot _root2(&UP_func);
  StackRoot _root3(&to_call);
  StackRoot _root4(&pos_args);
  StackRoot _root5(&named_args);
  StackRoot _root6(&rd);

  func = this->_EvalExpr(node->func);
  UP_func = func;
  switch (func->tag()) {
    case value_e::Func: 
    case value_e::BuiltinFunc: {
      to_call = func;
      Tuple2<List<value_asdl::value_t*>*, Dict<BigStr*, value_asdl::value_t*>*> tup5 = func_proc::_EvalArgList(this, node->args);
      pos_args = tup5.at0();
      named_args = tup5.at1();
      rd = Alloc<typed_args::Reader>(pos_args, named_args, nullptr, node->args);
    }
      break;
    case value_e::BoundFunc: {
      value::BoundFunc* func = static_cast<value::BoundFunc*>(UP_func);
      to_call = func->func;
      Tuple2<List<value_asdl::value_t*>*, Dict<BigStr*, value_asdl::value_t*>*> tup6 = func_proc::_EvalArgList(this, node->args, func->me);
      pos_args = tup6.at0();
      named_args = tup6.at1();
      rd = Alloc<typed_args::Reader>(pos_args, named_args, nullptr, node->args, true);
    }
      break;
    default: {
      throw Alloc<error::TypeErr>(func, str2031, node->args->left);
    }
  }
  return this->_CallFunc(to_call, rd);
}

value_asdl::value_t* ExprEvaluator::_EvalSubscript(value_asdl::value_t* obj, value_asdl::value_t* index) {
  value_asdl::value_t* UP_obj = nullptr;
  value_asdl::value_t* UP_index = nullptr;
  int lower;
  int upper;
  int i;
  StackRoot _root0(&obj);
  StackRoot _root1(&index);
  StackRoot _root2(&UP_obj);
  StackRoot _root3(&UP_index);

  UP_obj = obj;
  UP_index = index;
  switch (obj->tag()) {
    case value_e::Str: {
      value::Str* obj = static_cast<value::Str*>(UP_obj);
      switch (index->tag()) {
        case value_e::Slice: {
          value::Slice* index = static_cast<value::Slice*>(UP_index);
          lower = index->lower ? index->lower->i : 0;
          upper = index->upper ? index->upper->i : len(obj->s);
          return Alloc<value::Str>(obj->s->slice(lower, upper));
        }
          break;
        case value_e::Int: {
          value::Int* index = static_cast<value::Int*>(UP_index);
          i = mops::BigTruncate(index->i);
          try {
            return Alloc<value::Str>(obj->s->at(i));
          }
          catch (IndexError*) {
            throw Alloc<error::Expr>(str2032, loc::Missing);
          }
        }
          break;
        default: {
          throw Alloc<error::TypeErr>(index, str2033, loc::Missing);
        }
      }
    }
      break;
    case value_e::List: {
      value::List* obj = static_cast<value::List*>(UP_obj);
      switch (index->tag()) {
        case value_e::Slice: {
          value::Slice* index = static_cast<value::Slice*>(UP_index);
          lower = index->lower ? index->lower->i : 0;
          upper = index->upper ? index->upper->i : len(obj->items);
          return Alloc<value::List>(obj->items->slice(lower, upper));
        }
          break;
        case value_e::Int: {
          value::Int* index = static_cast<value::Int*>(UP_index);
          i = mops::BigTruncate(index->i);
          try {
            return obj->items->at(i);
          }
          catch (IndexError*) {
            throw Alloc<error::Expr>(StrFormat("List index out of range: %d", i), loc::Missing);
          }
        }
          break;
        default: {
          throw Alloc<error::TypeErr>(index, str2035, loc::Missing);
        }
      }
    }
      break;
    case value_e::Dict: {
      value::Dict* obj = static_cast<value::Dict*>(UP_obj);
      if (index->tag() != value_e::Str) {
        throw Alloc<error::TypeErr>(index, str2036, loc::Missing);
      }
      value::Str* index = static_cast<value::Str*>(UP_index);
      try {
        return obj->d->at(index->s);
      }
      catch (KeyError*) {
        throw Alloc<error::Expr>(StrFormat("Dict entry not found: %r", index->s), loc::Missing);
      }
    }
      break;
  }
  throw Alloc<error::TypeErr>(obj, str2038, loc::Missing);
}

value_asdl::value_t* ExprEvaluator::_EvalDot(syntax_asdl::Attribute* node, value_asdl::value_t* obj) {
  value_asdl::value_t* UP_obj = nullptr;
  BigStr* attr_name = nullptr;
  value_asdl::value_t* result = nullptr;
  StackRoot _root0(&node);
  StackRoot _root1(&obj);
  StackRoot _root2(&UP_obj);
  StackRoot _root3(&attr_name);
  StackRoot _root4(&result);

  UP_obj = obj;
  switch (obj->tag()) {
    case value_e::Dict: {
      value::Dict* obj = static_cast<value::Dict*>(UP_obj);
      attr_name = node->attr_name;
      try {
        result = obj->d->at(attr_name);
      }
      catch (KeyError*) {
        throw Alloc<error::Expr>(StrFormat("Dict entry %r not found", attr_name), node->op);
      }
    }
      break;
    default: {
      throw Alloc<error::TypeErr>(obj, str2040, node->op);
    }
  }
  return result;
}

value_asdl::value_t* ExprEvaluator::_EvalAttribute(syntax_asdl::Attribute* node) {
  value_asdl::value_t* o = nullptr;
  value_asdl::value_t* UP_o = nullptr;
  BigStr* name = nullptr;
  Dict<BigStr*, vm::_Callable*>* type_methods = nullptr;
  vm::_Callable* vm_callable = nullptr;
  value::BuiltinFunc* func_val = nullptr;
  value_asdl::value_t* val = nullptr;
  StackRoot _root0(&node);
  StackRoot _root1(&o);
  StackRoot _root2(&UP_o);
  StackRoot _root3(&name);
  StackRoot _root4(&type_methods);
  StackRoot _root5(&vm_callable);
  StackRoot _root6(&func_val);
  StackRoot _root7(&val);

  o = this->_EvalExpr(node->obj);
  UP_o = o;
  switch (node->op->id) {
    case Id::Expr_RArrow: 
    case Id::Expr_RDArrow: {
      name = node->attr_name;
      type_methods = this->methods->get(o->tag());
      vm_callable = type_methods != nullptr ? type_methods->get(name) : nullptr;
      if (vm_callable) {
        func_val = Alloc<value::BuiltinFunc>(vm_callable);
        return Alloc<value::BoundFunc>(o, func_val);
      }
      if (node->op->id == Id::Expr_RArrow) {
        throw Alloc<error::TypeErrVerbose>(StrFormat("Method %r does not exist on type %s", name, ui::ValType(o)), node->attr);
      }
      val = this->_LookupVar(name, node->attr);
      switch (val->tag()) {
        case value_e::Func: 
        case value_e::BuiltinFunc: {
          return Alloc<value::BoundFunc>(o, val);
        }
          break;
        default: {
          throw Alloc<error::TypeErr>(val, str2042, node->attr);
        }
      }
    }
      break;
    case Id::Expr_Dot: {
      return this->_EvalDot(node, o);
    }
      break;
    default: {
      assert(0);  // AssertionError
    }
  }
}

value_asdl::value_t* ExprEvaluator::_EvalExpr(syntax_asdl::expr_t* node) {
  syntax_asdl::expr_t* UP_node = nullptr;
  Dict<BigStr*, runtime_asdl::Cell*>* frame = nullptr;
  int id_;
  BigStr* stdout_str = nullptr;
  List<BigStr*>* strs = nullptr;
  List<value_asdl::value_t*>* items = nullptr;
  List<syntax_asdl::CompoundWord*>* words = nullptr;
  value_asdl::IntBox* lower = nullptr;
  value_asdl::IntBox* upper = nullptr;
  BigStr* msg = nullptr;
  int i;
  int j;
  bool b;
  List<value_asdl::value_t*>* kvals = nullptr;
  List<value_asdl::value_t*>* values = nullptr;
  value::Str* key = nullptr;
  value_asdl::value_t* v = nullptr;
  Dict<BigStr*, value_asdl::value_t*>* d = nullptr;
  BigStr* k = nullptr;
  value_asdl::value_t* obj = nullptr;
  value_asdl::value_t* index = nullptr;
  StackRoot _root0(&node);
  StackRoot _root1(&UP_node);
  StackRoot _root2(&frame);
  StackRoot _root3(&stdout_str);
  StackRoot _root4(&strs);
  StackRoot _root5(&items);
  StackRoot _root6(&words);
  StackRoot _root7(&lower);
  StackRoot _root8(&upper);
  StackRoot _root9(&msg);
  StackRoot _root10(&kvals);
  StackRoot _root11(&values);
  StackRoot _root12(&key);
  StackRoot _root13(&v);
  StackRoot _root14(&d);
  StackRoot _root15(&k);
  StackRoot _root16(&obj);
  StackRoot _root17(&index);

  UP_node = node;
  switch (node->tag()) {
    case expr_e::Const: {
      expr::Const* node = static_cast<expr::Const*>(UP_node);
      return this->_EvalConst(node);
    }
      break;
    case expr_e::Var: {
      expr::Var* node = static_cast<expr::Var*>(UP_node);
      return this->_LookupVar(node->name, node->left);
    }
      break;
    case expr_e::Place: {
      expr::Place* node = static_cast<expr::Place*>(UP_node);
      frame = this->mem->TopNamespace();
      return Alloc<value::Place>(Alloc<LeftName>(node->var_name, node->blame_tok), frame);
    }
      break;
    case expr_e::CommandSub: {
      CommandSub* node = static_cast<CommandSub*>(UP_node);
      id_ = node->left_token->id;
      if (id_ == Id::Left_CaretParen) {
        return Alloc<value::Command>(node->child);
      }
      else {
        stdout_str = this->shell_ex->RunCommandSub(node);
        if (id_ == Id::Left_AtParen) {
          try {
            strs = j8::SplitJ8Lines(stdout_str);
          }
          catch (error::Decode* e) {
            throw Alloc<error::Structured>(4, e->Message(), node->left_token);
          }
          items = Alloc<List<value_asdl::value_t*>>();
          for (ListIter<BigStr*> it(strs); !it.Done(); it.Next()) {
            BigStr* s = it.Value();
            items->append(Alloc<value::Str>(s));
          }
          return Alloc<value::List>(items);
        }
        else {
          return Alloc<value::Str>(stdout_str);
        }
      }
    }
      break;
    case expr_e::ShArrayLiteral: {
      ShArrayLiteral* node = static_cast<ShArrayLiteral*>(UP_node);
      words = braces::BraceExpandWords(node->words);
      strs = this->word_ev->EvalWordSequence(words);
      items = Alloc<List<value_asdl::value_t*>>();
      for (ListIter<BigStr*> it(strs); !it.Done(); it.Next()) {
        BigStr* s = it.Value();
        items->append(Alloc<value::Str>(s));
      }
      return Alloc<value::List>(items);
    }
      break;
    case expr_e::DoubleQuoted: {
      DoubleQuoted* node = static_cast<DoubleQuoted*>(UP_node);
      return Alloc<value::Str>(this->word_ev->EvalDoubleQuotedToString(node));
    }
      break;
    case expr_e::SingleQuoted: {
      SingleQuoted* node = static_cast<SingleQuoted*>(UP_node);
      return Alloc<value::Str>(node->sval);
    }
      break;
    case expr_e::BracedVarSub: {
      BracedVarSub* node = static_cast<BracedVarSub*>(UP_node);
      return Alloc<value::Str>(this->word_ev->EvalBracedVarSubToString(node));
    }
      break;
    case expr_e::SimpleVarSub: {
      SimpleVarSub* node = static_cast<SimpleVarSub*>(UP_node);
      return Alloc<value::Str>(this->word_ev->EvalSimpleVarSubToString(node));
    }
      break;
    case expr_e::Unary: {
      expr::Unary* node = static_cast<expr::Unary*>(UP_node);
      return this->_EvalUnary(node);
    }
      break;
    case expr_e::Binary: {
      expr::Binary* node = static_cast<expr::Binary*>(UP_node);
      return this->_EvalBinary(node);
    }
      break;
    case expr_e::Slice: {
      expr::Slice* node = static_cast<expr::Slice*>(UP_node);
      lower = nullptr;
      upper = nullptr;
      if (node->lower) {
        msg = str2045;
        i = val_ops::ToInt(this->_EvalExpr(node->lower), msg, loc::Missing);
        lower = Alloc<IntBox>(i);
      }
      if (node->upper) {
        msg = str2046;
        i = val_ops::ToInt(this->_EvalExpr(node->upper), msg, loc::Missing);
        upper = Alloc<IntBox>(i);
      }
      return Alloc<value::Slice>(lower, upper);
    }
      break;
    case expr_e::Range: {
      expr::Range* node = static_cast<expr::Range*>(UP_node);
      msg = str2047;
      i = val_ops::ToInt(this->_EvalExpr(node->lower), msg, loc::Missing);
      msg = str2048;
      j = val_ops::ToInt(this->_EvalExpr(node->upper), msg, loc::Missing);
      return Alloc<value::Range>(i, j);
    }
      break;
    case expr_e::Compare: {
      expr::Compare* node = static_cast<expr::Compare*>(UP_node);
      return this->_EvalCompare(node);
    }
      break;
    case expr_e::IfExp: {
      expr::IfExp* node = static_cast<expr::IfExp*>(UP_node);
      b = val_ops::ToBool(this->_EvalExpr(node->test));
      if (b) {
        return this->_EvalExpr(node->body);
      }
      else {
        return this->_EvalExpr(node->orelse);
      }
    }
      break;
    case expr_e::List: {
      expr::List* node = static_cast<expr::List*>(UP_node);
      items = Alloc<List<value_asdl::value_t*>>();
      for (ListIter<syntax_asdl::expr_t*> it(node->elts); !it.Done(); it.Next()) {
        syntax_asdl::expr_t* e = it.Value();
        items->append(this->_EvalExpr(e));
      }
      return Alloc<value::List>(items);
    }
      break;
    case expr_e::Tuple: {
      expr::Tuple* node = static_cast<expr::Tuple*>(UP_node);
      items = Alloc<List<value_asdl::value_t*>>();
      for (ListIter<syntax_asdl::expr_t*> it(node->elts); !it.Done(); it.Next()) {
        syntax_asdl::expr_t* e = it.Value();
        items->append(this->_EvalExpr(e));
      }
      return Alloc<value::List>(items);
    }
      break;
    case expr_e::Dict: {
      expr::Dict* node = static_cast<expr::Dict*>(UP_node);
      kvals = Alloc<List<value_asdl::value_t*>>();
      for (ListIter<syntax_asdl::expr_t*> it(node->keys); !it.Done(); it.Next()) {
        syntax_asdl::expr_t* e = it.Value();
        kvals->append(this->_EvalExpr(e));
      }
      values = Alloc<List<value_asdl::value_t*>>();
      i = 0;
      for (ListIter<syntax_asdl::expr_t*> it(node->values); !it.Done(); it.Next(), ++i) {
        syntax_asdl::expr_t* value_expr = it.Value();
        StackRoot _for(&value_expr      );
        if (value_expr->tag() == expr_e::Implicit) {
          key = static_cast<value::Str*>(kvals->at(i));
          v = this->_LookupVar(key->s, loc::Missing);
        }
        else {
          v = this->_EvalExpr(value_expr);
        }
        values->append(v);
      }
      d = Alloc<Dict<BigStr*, value_asdl::value_t*>>();
      i = 0;
      for (ListIter<value_asdl::value_t*> it(kvals); !it.Done(); it.Next(), ++i) {
        value_asdl::value_t* kval = it.Value();
        StackRoot _for(&kval      );
        k = val_ops::ToStr(kval, str2049, loc::Missing);
        d->set(k, values->at(i));
      }
      return Alloc<value::Dict>(d);
    }
      break;
    case expr_e::ListComp: {
      e_die_status(2, str2050);
    }
      break;
    case expr_e::GeneratorExp: {
      e_die_status(2, str2051);
    }
      break;
    case expr_e::Literal: {
      expr::Literal* node = static_cast<expr::Literal*>(UP_node);
      return Alloc<value::Expr>(node->inner);
    }
      break;
    case expr_e::Lambda: {
      e_die_status(2, str2052);
    }
      break;
    case expr_e::FuncCall: {
      expr::FuncCall* node = static_cast<expr::FuncCall*>(UP_node);
      return this->_EvalFuncCall(node);
    }
      break;
    case expr_e::Subscript: {
      Subscript* node = static_cast<Subscript*>(UP_node);
      obj = this->_EvalExpr(node->obj);
      index = this->_EvalExpr(node->index);
      return this->_EvalSubscript(obj, index);
    }
      break;
    case expr_e::Attribute: {
      Attribute* node = static_cast<Attribute*>(UP_node);
      return this->_EvalAttribute(node);
    }
      break;
    case expr_e::Eggex: {
      Eggex* node = static_cast<Eggex*>(UP_node);
      return this->EvalEggex(node);
    }
      break;
    default: {
      FAIL(kNotImplemented);  // Python NotImplementedError
    }
  }
}

value::Eggex* ExprEvaluator::EvalEggex(syntax_asdl::Eggex* node) {
  expr_eval::EggexEvaluator* ev = nullptr;
  syntax_asdl::re_t* spliced = nullptr;
  StackRoot _root0(&node);
  StackRoot _root1(&ev);
  StackRoot _root2(&spliced);

  ev = Alloc<EggexEvaluator>(this->mem, node->canonical_flags);
  spliced = ev->EvalE(node->regex);
  return Alloc<value::Eggex>(spliced, node->canonical_flags, ev->convert_funcs, ev->convert_toks, nullptr, Alloc<List<BigStr*>>());
}

EggexEvaluator::EggexEvaluator(state::Mem* mem, BigStr* canonical_flags) {
  this->mem = mem;
  this->canonical_flags = canonical_flags;
  this->convert_funcs = Alloc<List<value_asdl::value_t*>>();
  this->convert_toks = Alloc<List<syntax_asdl::Token*>>();
}

value_asdl::value_t* EggexEvaluator::_LookupVar(BigStr* name, syntax_asdl::loc_t* var_loc) {
  StackRoot _root0(&name);
  StackRoot _root1(&var_loc);

  return LookupVar(this->mem, name, scope_e::LocalOrGlobal, var_loc);
}

void EggexEvaluator::_EvalClassLiteralTerm(syntax_asdl::class_literal_term_t* term, List<syntax_asdl::char_class_term_t*>* out) {
  syntax_asdl::class_literal_term_t* UP_term = nullptr;
  BigStr* s = nullptr;
  syntax_asdl::Token* char_code_tok = nullptr;
  value_asdl::value_t* val = nullptr;
  int char_int;
  StackRoot _root0(&term);
  StackRoot _root1(&out);
  StackRoot _root2(&UP_term);
  StackRoot _root3(&s);
  StackRoot _root4(&char_code_tok);
  StackRoot _root5(&val);

  UP_term = term;
  s = nullptr;
  char_code_tok = nullptr;
  switch (term->tag()) {
    case class_literal_term_e::CharCode: {
      CharCode* term = static_cast<CharCode*>(UP_term);
      out->append(term);
      return ;
    }
      break;
    case class_literal_term_e::CharRange: {
      CharRange* term = static_cast<CharRange*>(UP_term);
      out->append(term);
      return ;
    }
      break;
    case class_literal_term_e::PosixClass: {
      PosixClass* term = static_cast<PosixClass*>(UP_term);
      out->append(term);
      return ;
    }
      break;
    case class_literal_term_e::PerlClass: {
      PerlClass* term = static_cast<PerlClass*>(UP_term);
      out->append(term);
      return ;
    }
      break;
    case class_literal_term_e::SingleQuoted: {
      SingleQuoted* term = static_cast<SingleQuoted*>(UP_term);
      s = term->sval;
      char_code_tok = term->left;
    }
      break;
    case class_literal_term_e::Splice: {
      class_literal_term::Splice* term = static_cast<class_literal_term::Splice*>(UP_term);
      val = this->_LookupVar(term->var_name, term->name);
      s = val_ops::ToStr(val, str2053, term->name);
      char_code_tok = term->name;
    }
      break;
  }
  for (StrIter it(s); !it.Done(); it.Next()) {
    BigStr* ch = it.Value();
    StackRoot _for(&ch  );
    char_int = ord(ch);
    if (char_int >= 128) {
      e_die(StrFormat("Use unquoted char literal for byte %d, which is >= 128 (avoid confusing a set of bytes with a sequence)", char_int), char_code_tok);
    }
    out->append(Alloc<CharCode>(char_code_tok, char_int, false));
  }
}

syntax_asdl::re_t* EggexEvaluator::EvalE(syntax_asdl::re_t* node) {
  syntax_asdl::re_t* UP_node = nullptr;
  List<syntax_asdl::re_t*>* new_children = nullptr;
  value_asdl::value_t* convert_func = nullptr;
  syntax_asdl::Token* convert_tok = nullptr;
  BigStr* func_name = nullptr;
  value_asdl::value_t* func_val = nullptr;
  List<syntax_asdl::char_class_term_t*>* new_terms = nullptr;
  BigStr* s = nullptr;
  value_asdl::value_t* val = nullptr;
  value_asdl::value_t* UP_val = nullptr;
  syntax_asdl::re_t* to_splice = nullptr;
  StackRoot _root0(&node);
  StackRoot _root1(&UP_node);
  StackRoot _root2(&new_children);
  StackRoot _root3(&convert_func);
  StackRoot _root4(&convert_tok);
  StackRoot _root5(&func_name);
  StackRoot _root6(&func_val);
  StackRoot _root7(&new_terms);
  StackRoot _root8(&s);
  StackRoot _root9(&val);
  StackRoot _root10(&UP_val);
  StackRoot _root11(&to_splice);

  UP_node = node;
  switch (node->tag()) {
    case re_e::Seq: {
      re::Seq* node = static_cast<re::Seq*>(UP_node);
      new_children = Alloc<List<syntax_asdl::re_t*>>();
      for (ListIter<syntax_asdl::re_t*> it(node->children); !it.Done(); it.Next()) {
        syntax_asdl::re_t* child = it.Value();
        new_children->append(this->EvalE(child));
      }
      return Alloc<re::Seq>(new_children);
    }
      break;
    case re_e::Alt: {
      re::Alt* node = static_cast<re::Alt*>(UP_node);
      new_children = Alloc<List<syntax_asdl::re_t*>>();
      for (ListIter<syntax_asdl::re_t*> it(node->children); !it.Done(); it.Next()) {
        syntax_asdl::re_t* child = it.Value();
        new_children->append(this->EvalE(child));
      }
      return Alloc<re::Alt>(new_children);
    }
      break;
    case re_e::Repeat: {
      re::Repeat* node = static_cast<re::Repeat*>(UP_node);
      return Alloc<re::Repeat>(this->EvalE(node->child), node->op);
    }
      break;
    case re_e::Group: {
      re::Group* node = static_cast<re::Group*>(UP_node);
      this->convert_funcs->append(nullptr);
      this->convert_toks->append(nullptr);
      return Alloc<re::Group>(this->EvalE(node->child));
    }
      break;
    case re_e::Capture: {
      re::Capture* node = static_cast<re::Capture*>(UP_node);
      convert_func = nullptr;
      convert_tok = nullptr;
      if (node->func_name) {
        func_name = lexer::LazyStr(node->func_name);
        func_val = this->mem->GetValue(func_name);
        switch (func_val->tag()) {
          case value_e::Func: 
          case value_e::BuiltinFunc: {
            convert_func = func_val;
            convert_tok = node->func_name;
          }
            break;
          default: {
            throw Alloc<error::TypeErr>(func_val, StrFormat("Expected %r to be a func", func_name), node->func_name);
          }
        }
      }
      this->convert_funcs->append(convert_func);
      this->convert_toks->append(convert_tok);
      return Alloc<re::Capture>(this->EvalE(node->child), node->name, node->func_name);
    }
      break;
    case re_e::CharClassLiteral: {
      re::CharClassLiteral* node = static_cast<re::CharClassLiteral*>(UP_node);
      new_terms = Alloc<List<syntax_asdl::char_class_term_t*>>();
      for (ListIter<syntax_asdl::class_literal_term_t*> it(node->terms); !it.Done(); it.Next()) {
        syntax_asdl::class_literal_term_t* t = it.Value();
        StackRoot _for(&t      );
        this->_EvalClassLiteralTerm(t, new_terms);
      }
      return Alloc<re::CharClass>(node->negated, new_terms);
    }
      break;
    case re_e::SingleQuoted: {
      SingleQuoted* node = static_cast<SingleQuoted*>(UP_node);
      s = node->sval;
      return Alloc<re::LiteralChars>(node->left, s);
    }
      break;
    case re_e::Splice: {
      re::Splice* node = static_cast<re::Splice*>(UP_node);
      val = this->_LookupVar(node->var_name, node->name);
      UP_val = val;
      switch (val->tag()) {
        case value_e::Str: {
          value::Str* val = static_cast<value::Str*>(UP_val);
          to_splice = Alloc<re::LiteralChars>(node->name, val->s);
        }
          break;
        case value_e::Eggex: {
          value::Eggex* val = static_cast<value::Eggex*>(UP_val);
          this->convert_funcs->extend(val->convert_funcs);
          this->convert_toks->extend(val->convert_toks);
          to_splice = val->spliced;
          if (!(str_equals(val->canonical_flags, this->canonical_flags))) {
            e_die(StrFormat("Expected eggex flags %r, but got %r", this->canonical_flags, val->canonical_flags), node->name);
          }
        }
          break;
        default: {
          throw Alloc<error::TypeErr>(val, str2057, node->name);
        }
      }
      return to_splice;
    }
      break;
    default: {
      return node;
    }
  }
}

}  // define namespace expr_eval

namespace expr_parse {  // define

using syntax_asdl::loc;
using syntax_asdl::Token;
using syntax_asdl::DoubleQuoted;
using syntax_asdl::SingleQuoted;
using syntax_asdl::CommandSub;
using syntax_asdl::ShArrayLiteral;
using syntax_asdl::CompoundWord;
using syntax_asdl::word_part_t;
using syntax_asdl::word_e;
using id_kind_asdl::Id;
using id_kind_asdl::Kind;
using id_kind_asdl::Id_str;
using types_asdl::lex_mode_e;
using error::p_die;
using pnode::PNodeAllocator;

int _Classify(grammar::Grammar* gr, syntax_asdl::Token* tok) {
  int id_;
  BigStr* type_str = nullptr;
  StackRoot _root0(&gr);
  StackRoot _root1(&tok);
  StackRoot _root2(&type_str);

  id_ = tok->id;
  if (dict_contains(gr->tokens, id_)) {
    return gr->tokens->at(id_);
  }
  if (id_ == Id::Unknown_DEqual) {
    p_die(str2058, tok);
  }
  if (id_ == Id::Unknown_Tok) {
    type_str = str2059;
  }
  else {
    type_str = StrFormat(" (%s)", ui::PrettyId(tok->id));
  }
  p_die(StrFormat("Unexpected token in expression mode%s", type_str), tok);
}
GLOBAL_DICT(_OTHER_BALANCE, int, int, 4, {Id::Op_LParen COMMA Id::Op_RParen COMMA Id::Op_LBracket COMMA Id::Op_RBracket}, {1 COMMA -1 COMMA 1 COMMA -1});

syntax_asdl::Token* _PushYshTokens(parse_lib::ParseContext* parse_ctx, grammar::Grammar* gr, parse::Parser* p, lexer::Lexer* lex) {
  syntax_asdl::Token* last_token = nullptr;
  bool prev_was_newline;
  int balance;
  syntax_asdl::Token* tok = nullptr;
  int ilabel;
  syntax_asdl::Token* left_tok = nullptr;
  reader::DisallowedLineReader* line_reader = nullptr;
  word_parse::WordParser* w_parser = nullptr;
  List<syntax_asdl::CompoundWord*>* words = nullptr;
  syntax_asdl::Token* close_tok = nullptr;
  bool done;
  syntax_asdl::word_t* w = nullptr;
  List<syntax_asdl::word_t*>* words2 = nullptr;
  List<syntax_asdl::word_t*>* words3 = nullptr;
  int typ;
  syntax_asdl::ShArrayLiteral* lit_part = nullptr;
  Token* opaque = nullptr;
  syntax_asdl::Token* left_token = nullptr;
  cmd_parse::CommandParser* c_parser = nullptr;
  syntax_asdl::command_t* node = nullptr;
  syntax_asdl::Token* right_token = nullptr;
  syntax_asdl::CommandSub* cs_part = nullptr;
  List<syntax_asdl::word_part_t*>* parts = nullptr;
  syntax_asdl::DoubleQuoted* expr_dq_part = nullptr;
  syntax_asdl::BracedVarSub* part = nullptr;
  types_asdl::lex_mode_t sq_mode;
  List<syntax_asdl::Token*>* tokens = nullptr;
  BigStr* sval = nullptr;
  syntax_asdl::SingleQuoted* sq_part = nullptr;
  StackRoot _root0(&parse_ctx);
  StackRoot _root1(&gr);
  StackRoot _root2(&p);
  StackRoot _root3(&lex);
  StackRoot _root4(&last_token);
  StackRoot _root5(&tok);
  StackRoot _root6(&left_tok);
  StackRoot _root7(&line_reader);
  StackRoot _root8(&w_parser);
  StackRoot _root9(&words);
  StackRoot _root10(&close_tok);
  StackRoot _root11(&w);
  StackRoot _root12(&words2);
  StackRoot _root13(&words3);
  StackRoot _root14(&lit_part);
  StackRoot _root15(&opaque);
  StackRoot _root16(&left_token);
  StackRoot _root17(&c_parser);
  StackRoot _root18(&node);
  StackRoot _root19(&right_token);
  StackRoot _root20(&cs_part);
  StackRoot _root21(&parts);
  StackRoot _root22(&expr_dq_part);
  StackRoot _root23(&part);
  StackRoot _root24(&tokens);
  StackRoot _root25(&sval);
  StackRoot _root26(&sq_part);

  last_token = nullptr;
  prev_was_newline = false;
  balance = 0;
  while (true) {
    if (last_token) {
      tok = last_token;
      last_token = nullptr;
    }
    else {
      tok = lex->Read(lex_mode_e::Expr);
    }
    if (consts::GetKind(tok->id) == Kind::Ignored) {
      continue;
    }
    if (tok->id == Id::Op_Newline) {
      if (balance > 0) {
        continue;
      }
      if (prev_was_newline) {
        continue;
      }
      prev_was_newline = true;
    }
    else {
      prev_was_newline = false;
    }
    balance += _OTHER_BALANCE->get(tok->id, 0);
    if (tok->id == Id::Op_LParen) {
      lex->PushHint(Id::Op_RParen, Id::Op_RParen);
    }
    ilabel = _Classify(gr, tok);
    if (p->addtoken(tok->id, tok, ilabel)) {
      return tok;
    }
    if ((tok->id == Id::Left_ColonPipe || tok->id == Id::Left_PercentParen)) {
      left_tok = tok;
      if (tok->id == Id::Left_PercentParen) {
        lex->PushHint(Id::Op_RParen, Id::Right_ShArrayLiteral);
      }
      line_reader = Alloc<reader::DisallowedLineReader>(parse_ctx->arena, tok);
      w_parser = parse_ctx->MakeWordParser(lex, line_reader);
      words = Alloc<List<syntax_asdl::CompoundWord*>>();
      close_tok = nullptr;
      done = false;
      while (!done) {
        w = w_parser->ReadWord(lex_mode_e::ShCommand);
        switch (w->tag()) {
          case word_e::Operator: {
            tok = reinterpret_cast<Token*>(w);
            if (tok->id == Id::Right_ShArrayLiteral) {
              if (left_tok->id != Id::Left_PercentParen) {
                p_die(str2062, left_tok);
              }
              close_tok = tok;
              done = true;
            }
            else {
              if (tok->id == Id::Op_Pipe) {
                if (left_tok->id != Id::Left_ColonPipe) {
                  p_die(str2063, left_tok);
                }
                close_tok = tok;
                done = true;
              }
              else {
                if (tok->id == Id::Op_Newline) {
                  continue;
                }
                else {
                  p_die(str2064, Alloc<loc::Word>(w));
                }
              }
            }
          }
            break;
          case word_e::Compound: {
            words->append(static_cast<CompoundWord*>(w));
          }
            break;
          default: {
            assert(0);  // AssertionError
          }
        }
      }
      words2 = braces::BraceDetectAll(words);
      words3 = word_::TildeDetectAll(words2);
      typ = Id::Expr_CastedDummy;
      lit_part = Alloc<ShArrayLiteral>(left_tok, words3, close_tok);
      opaque = reinterpret_cast<Token*>(lit_part);
      done = p->addtoken(typ, opaque, gr->tokens->at(typ));
      ilabel = _Classify(gr, close_tok);
      done = p->addtoken(tok->id, close_tok, ilabel);
      continue;
    }
    if ((tok->id == Id::Left_DollarParen || tok->id == Id::Left_AtParen || tok->id == Id::Left_CaretParen)) {
      left_token = tok;
      lex->PushHint(Id::Op_RParen, Id::Eof_RParen);
      line_reader = Alloc<reader::DisallowedLineReader>(parse_ctx->arena, tok);
      c_parser = parse_ctx->MakeParserForCommandSub(line_reader, lex, Id::Eof_RParen);
      node = c_parser->ParseCommandSub();
      right_token = c_parser->w_parser->cur_token;
      cs_part = Alloc<CommandSub>(left_token, node, right_token);
      typ = Id::Expr_CastedDummy;
      opaque = reinterpret_cast<Token*>(cs_part);
      done = p->addtoken(typ, opaque, gr->tokens->at(typ));
      ilabel = _Classify(gr, right_token);
      done = p->addtoken(right_token->id, right_token, ilabel);
      continue;
    }
    if ((tok->id == Id::Left_DoubleQuote || tok->id == Id::Left_DollarDoubleQuote || tok->id == Id::Left_TDoubleQuote || tok->id == Id::Left_DollarTDoubleQuote || tok->id == Id::Left_CaretDoubleQuote)) {
      left_token = tok;
      line_reader = Alloc<reader::DisallowedLineReader>(parse_ctx->arena, tok);
      w_parser = parse_ctx->MakeWordParser(lex, line_reader);
      parts = Alloc<List<syntax_asdl::word_part_t*>>();
      last_token = w_parser->ReadDoubleQuoted(left_token, parts);
      expr_dq_part = Alloc<DoubleQuoted>(left_token, parts, last_token);
      typ = Id::Expr_CastedDummy;
      opaque = reinterpret_cast<Token*>(expr_dq_part);
      done = p->addtoken(typ, opaque, gr->tokens->at(typ));
      continue;
    }
    if (tok->id == Id::Left_DollarBrace) {
      left_token = tok;
      line_reader = Alloc<reader::DisallowedLineReader>(parse_ctx->arena, tok);
      w_parser = parse_ctx->MakeWordParser(lex, line_reader);
      Tuple2<syntax_asdl::BracedVarSub*, syntax_asdl::Token*> tup0 = w_parser->ReadBracedVarSub(left_token);
      part = tup0.at0();
      last_token = tup0.at1();
      typ = Id::Expr_CastedDummy;
      opaque = reinterpret_cast<Token*>(part);
      done = p->addtoken(typ, opaque, gr->tokens->at(typ));
      continue;
    }
    if ((tok->id == Id::Left_SingleQuote || tok->id == Id::Left_TSingleQuote || tok->id == Id::Left_RSingleQuote || tok->id == Id::Left_RTSingleQuote || tok->id == Id::Left_USingleQuote || tok->id == Id::Left_UTSingleQuote || tok->id == Id::Left_BSingleQuote || tok->id == Id::Left_BTSingleQuote || tok->id == Id::Left_DollarSingleQuote)) {
      if (tok->id == Id::Left_DollarSingleQuote) {
        sq_mode = lex_mode_e::SQ_C;
      }
      else {
        if ((tok->id == Id::Left_USingleQuote || tok->id == Id::Left_UTSingleQuote || tok->id == Id::Left_BSingleQuote || tok->id == Id::Left_BTSingleQuote)) {
          sq_mode = lex_mode_e::J8_Str;
        }
        else {
          sq_mode = lex_mode_e::SQ_Raw;
        }
      }
      left_token = tok;
      line_reader = Alloc<reader::DisallowedLineReader>(parse_ctx->arena, tok);
      w_parser = parse_ctx->MakeWordParser(lex, line_reader);
      tokens = Alloc<List<syntax_asdl::Token*>>();
      last_token = w_parser->ReadSingleQuoted(sq_mode, left_token, tokens, true);
      sval = word_compile::EvalSingleQuoted(left_token->id, tokens);
      sq_part = Alloc<SingleQuoted>(left_token, sval, last_token);
      typ = Id::Expr_CastedDummy;
      opaque = reinterpret_cast<Token*>(sq_part);
      done = p->addtoken(typ, opaque, gr->tokens->at(typ));
      continue;
    }
  }
}

ExprParser::ExprParser(parse_lib::ParseContext* parse_ctx, grammar::Grammar* gr) {
  this->parse_ctx = parse_ctx;
  this->gr = gr;
  this->push_parser = Alloc<parse::Parser>(gr);
  this->pnode_alloc = nullptr;
}

Tuple2<pnode::PNode*, syntax_asdl::Token*> ExprParser::Parse(lexer::Lexer* lexer, int start_symbol) {
  syntax_asdl::Token* last_token = nullptr;
  StackRoot _root0(&lexer);
  StackRoot _root1(&last_token);

  this->push_parser->setup(start_symbol, this->pnode_alloc);
  try {
    last_token = _PushYshTokens(this->parse_ctx, this->gr, this->push_parser, lexer);
  }
  catch (parse::ParseError* e) {
    p_die(StrFormat("Syntax error in expression (near %s)", ui::PrettyId(e->tok->id)), e->tok);
  }
  return Tuple2<pnode::PNode*, syntax_asdl::Token*>(this->push_parser->rootnode, last_token);
}

ctx_PNodeAllocator::ctx_PNodeAllocator(expr_parse::ExprParser* ep) {
  gHeap.PushRoot(reinterpret_cast<RawObject**>(&(this->expr_parser)));
  this->expr_parser = ep;
  this->expr_parser->pnode_alloc = Alloc<PNodeAllocator>();
}

ctx_PNodeAllocator::~ctx_PNodeAllocator() {
  this->expr_parser->pnode_alloc->Clear();
  this->expr_parser->pnode_alloc = nullptr;
  gHeap.PopRoot();
}

}  // define namespace expr_parse

namespace expr_to_ast {  // define

using id_kind_asdl::Id;
using id_kind_asdl::Id_t;
using id_kind_asdl::Id_str;
using id_kind_asdl::Kind;
using syntax_asdl::Token;
using syntax_asdl::SimpleVarSub;
using syntax_asdl::loc;
using syntax_asdl::loc_t;
using syntax_asdl::DoubleQuoted;
using syntax_asdl::SingleQuoted;
using syntax_asdl::BracedVarSub;
using syntax_asdl::CommandSub;
using syntax_asdl::ShArrayLiteral;
using syntax_asdl::command;
using syntax_asdl::expr;
using syntax_asdl::expr_e;
using syntax_asdl::expr_t;
using syntax_asdl::expr_context_e;
using syntax_asdl::re;
using syntax_asdl::re_t;
using syntax_asdl::re_repeat;
using syntax_asdl::re_repeat_t;
using syntax_asdl::class_literal_term;
using syntax_asdl::class_literal_term_t;
using syntax_asdl::PosixClass;
using syntax_asdl::PerlClass;
using syntax_asdl::NameType;
using syntax_asdl::y_lhs_t;
using syntax_asdl::Comprehension;
using syntax_asdl::Subscript;
using syntax_asdl::Attribute;
using syntax_asdl::proc_sig;
using syntax_asdl::proc_sig_t;
using syntax_asdl::Param;
using syntax_asdl::RestParam;
using syntax_asdl::ParamGroup;
using syntax_asdl::NamedArg;
using syntax_asdl::ArgList;
using syntax_asdl::pat;
using syntax_asdl::pat_t;
using syntax_asdl::TypeExpr;
using syntax_asdl::Func;
using syntax_asdl::Eggex;
using syntax_asdl::EggexFlag;
using syntax_asdl::CharCode;
using syntax_asdl::CharRange;
using value_asdl::value;
using value_asdl::value_t;
using error::p_die;
GLOBAL_DICT(PERL_CLASSES, BigStr*, BigStr*, 4, {str2066 COMMA str2068 COMMA str2070 COMMA str2072}, {str2067 COMMA str2069 COMMA str2071 COMMA str2073});
GLOBAL_LIST(POSIX_CLASSES, BigStr*, 12, {str2074 COMMA str2075 COMMA str2076 COMMA str2077 COMMA str2078 COMMA str2079 COMMA str2080 COMMA str2081 COMMA str2082 COMMA str2083 COMMA str2084 COMMA str2085});
BigStr* RANGE_POINT_TOO_LONG = str2086;
BigStr* POS_ARG_MISPLACED = str2087;
int NT_OFFSET = 256;

Transformer::Transformer(grammar::Grammar* gr) {
  this->number2symbol = gr->number2symbol;
}

syntax_asdl::expr_t* Transformer::_LeftAssoc(pnode::PNode* p_node) {
  int i;
  int n;
  syntax_asdl::expr_t* left = nullptr;
  pnode::PNode* op = nullptr;
  syntax_asdl::expr_t* right = nullptr;
  StackRoot _root0(&p_node);
  StackRoot _root1(&left);
  StackRoot _root2(&op);
  StackRoot _root3(&right);

  i = 1;
  n = p_node->NumChildren();
  left = this->Expr(p_node->GetChild(0));
  while (i < n) {
    op = p_node->GetChild(i);
    right = this->Expr(p_node->GetChild((i + 1)));
    left = Alloc<expr::Binary>(op->tok, left, right);
    i += 2;
  }
  return left;
}

syntax_asdl::expr_t* Transformer::_Trailer(syntax_asdl::expr_t* base, pnode::PNode* p_trailer) {
  syntax_asdl::Token* tok0 = nullptr;
  int typ0;
  syntax_asdl::Token* lparen = nullptr;
  syntax_asdl::Token* rparen = nullptr;
  syntax_asdl::ArgList* arglist = nullptr;
  pnode::PNode* p = nullptr;
  pnode::PNode* p_args = nullptr;
  int n;
  pnode::PNode* a = nullptr;
  syntax_asdl::Token* attr = nullptr;
  StackRoot _root0(&base);
  StackRoot _root1(&p_trailer);
  StackRoot _root2(&tok0);
  StackRoot _root3(&lparen);
  StackRoot _root4(&rparen);
  StackRoot _root5(&arglist);
  StackRoot _root6(&p);
  StackRoot _root7(&p_args);
  StackRoot _root8(&a);
  StackRoot _root9(&attr);

  tok0 = p_trailer->GetChild(0)->tok;
  typ0 = p_trailer->GetChild(0)->typ;
  if (typ0 == Id::Op_LParen) {
    lparen = tok0;
    rparen = p_trailer->GetChild(-1)->tok;
    arglist = Alloc<ArgList>(lparen, Alloc<List<syntax_asdl::expr_t*>>(), nullptr, Alloc<List<syntax_asdl::NamedArg*>>(), nullptr, nullptr, rparen);
    if (p_trailer->NumChildren() == 2) {
      return Alloc<expr::FuncCall>(base, arglist);
    }
    p = p_trailer->GetChild(1);
    this->_ArgList(p, arglist);
    return Alloc<expr::FuncCall>(base, arglist);
  }
  if (typ0 == Id::Op_LBracket) {
    p_args = p_trailer->GetChild(1);
    n = p_args->NumChildren();
    if (n > 1) {
      p_die(str2088, p_args->GetChild(1)->tok);
    }
    a = p_args->GetChild(0);
    return Alloc<Subscript>(tok0, base, this->_Subscript(a));
  }
  if ((typ0 == Id::Expr_Dot || typ0 == Id::Expr_RArrow || typ0 == Id::Expr_RDArrow)) {
    attr = p_trailer->GetChild(1)->tok;
    return Alloc<Attribute>(base, tok0, attr, lexer::TokenVal(attr), expr_context_e::Store);
  }
  assert(0);  // AssertionError
}

Tuple2<syntax_asdl::expr_t*, syntax_asdl::expr_t*> Transformer::_DictPair(pnode::PNode* p_node) {
  int typ;
  syntax_asdl::expr_t* key = nullptr;
  syntax_asdl::expr_t* val = nullptr;
  syntax_asdl::Token* tok0 = nullptr;
  int id_;
  value::Str* key_str = nullptr;
  StackRoot _root0(&p_node);
  StackRoot _root1(&key);
  StackRoot _root2(&val);
  StackRoot _root3(&tok0);
  StackRoot _root4(&key_str);

  typ = p_node->GetChild(0)->typ;
  if ((typ == grammar_nt::sq_string || typ == grammar_nt::dq_string)) {
    key = this->Expr(p_node->GetChild(0));
    val = this->Expr(p_node->GetChild(2));
    return Tuple2<syntax_asdl::expr_t*, syntax_asdl::expr_t*>(key, val);
  }
  tok0 = p_node->GetChild(0)->tok;
  id_ = tok0->id;
  if (id_ == Id::Expr_Name) {
    key_str = Alloc<value::Str>(lexer::TokenVal(tok0));
    key = Alloc<expr::Const>(tok0, key_str);
    if (p_node->NumChildren() >= 3) {
      val = this->Expr(p_node->GetChild(2));
    }
    else {
      val = expr::Implicit;
    }
  }
  if (id_ == Id::Op_LBracket) {
    key = this->Expr(p_node->GetChild(1));
    val = this->Expr(p_node->GetChild(4));
    return Tuple2<syntax_asdl::expr_t*, syntax_asdl::expr_t*>(key, val);
  }
  return Tuple2<syntax_asdl::expr_t*, syntax_asdl::expr_t*>(key, val);
}

expr::Dict* Transformer::_Dict(pnode::PNode* parent, pnode::PNode* p_node) {
  List<syntax_asdl::expr_t*>* keys = nullptr;
  List<syntax_asdl::expr_t*>* values = nullptr;
  int n;
  syntax_asdl::expr_t* key = nullptr;
  syntax_asdl::expr_t* val = nullptr;
  StackRoot _root0(&parent);
  StackRoot _root1(&p_node);
  StackRoot _root2(&keys);
  StackRoot _root3(&values);
  StackRoot _root4(&key);
  StackRoot _root5(&val);

  if (p_node->typ == Id::Op_RBrace) {
    return Alloc<expr::Dict>(parent->tok, Alloc<List<syntax_asdl::expr_t*>>(), Alloc<List<syntax_asdl::expr_t*>>());
  }
  keys = Alloc<List<syntax_asdl::expr_t*>>();
  values = Alloc<List<syntax_asdl::expr_t*>>();
  n = p_node->NumChildren();
  for (int i = 0; i < n; i += 2) {
    Tuple2<syntax_asdl::expr_t*, syntax_asdl::expr_t*> tup0 = this->_DictPair(p_node->GetChild(i));
    key = tup0.at0();
    val = tup0.at1();
    keys->append(key);
    values->append(val);
  }
  return Alloc<expr::Dict>(parent->tok, keys, values);
}

syntax_asdl::expr_t* Transformer::_Tuple(pnode::PNode* parent) {
  int n;
  List<syntax_asdl::expr_t*>* elts = nullptr;
  pnode::PNode* p_node = nullptr;
  StackRoot _root0(&parent);
  StackRoot _root1(&elts);
  StackRoot _root2(&p_node);

  n = parent->NumChildren();
  if (n == 1) {
    return this->Expr(parent->GetChild(0));
  }
  if (n == 2) {
    p_die(str2089, parent->GetChild(1)->tok);
  }
  elts = Alloc<List<syntax_asdl::expr_t*>>();
  for (int i = 0; i < n; i += 2) {
    p_node = parent->GetChild(i);
    elts->append(this->Expr(p_node));
  }
  return Alloc<expr::Tuple>(parent->tok, elts, expr_context_e::Store);
}

syntax_asdl::expr_t* Transformer::_TestlistComp(pnode::PNode* parent, pnode::PNode* p_node, int id0) {
  int n;
  syntax_asdl::expr_t* elt = nullptr;
  syntax_asdl::Comprehension* comp = nullptr;
  List<syntax_asdl::expr_t*>* elts = nullptr;
  StackRoot _root0(&parent);
  StackRoot _root1(&p_node);
  StackRoot _root2(&elt);
  StackRoot _root3(&comp);
  StackRoot _root4(&elts);

  n = p_node->NumChildren();
  if ((n > 1 and p_node->GetChild(1)->typ == grammar_nt::comp_for)) {
    elt = this->Expr(p_node->GetChild(0));
    comp = this->_CompFor(p_node->GetChild(1));
    if (id0 == Id::Op_LParen) {
      return Alloc<expr::GeneratorExp>(elt, NewList<syntax_asdl::Comprehension*>(std::initializer_list<syntax_asdl::Comprehension*>{comp}));
    }
    if (id0 == Id::Op_LBracket) {
      return Alloc<expr::ListComp>(parent->tok, elt, NewList<syntax_asdl::Comprehension*>(std::initializer_list<syntax_asdl::Comprehension*>{comp}));
    }
    assert(0);  // AssertionError
  }
  if (id0 == Id::Op_LParen) {
    if (n == 1) {
      return this->Expr(p_node->GetChild(0));
    }
    if (p_node->GetChild(1)->typ == Id::Arith_Comma) {
      return this->_Tuple(p_node);
    }
    assert(0);  // AssertionError
  }
  if (id0 == Id::Op_LBracket) {
    elts = Alloc<List<syntax_asdl::expr_t*>>();
    for (int i = 0; i < n; i += 2) {
      elts->append(this->Expr(p_node->GetChild(i)));
    }
    return Alloc<expr::List>(parent->tok, elts, expr_context_e::Store);
  }
  assert(0);  // AssertionError
}

syntax_asdl::expr_t* Transformer::_Atom(pnode::PNode* parent) {
  syntax_asdl::Token* tok = nullptr;
  int id_;
  int n;
  syntax_asdl::expr_t* child = nullptr;
  int i;
  syntax_asdl::Token* name_tok = nullptr;
  StackRoot _root0(&parent);
  StackRoot _root1(&tok);
  StackRoot _root2(&child);
  StackRoot _root3(&name_tok);

  tok = parent->GetChild(0)->tok;
  id_ = tok->id;
  n = parent->NumChildren();
  if (id_ == Id::Op_LParen) {
    if (n == 2) {
      return Alloc<expr::Tuple>(tok, Alloc<List<syntax_asdl::expr_t*>>(), expr_context_e::Store);
    }
    return this->_TestlistComp(parent, parent->GetChild(1), id_);
  }
  if (id_ == Id::Op_LBracket) {
    if (n == 2) {
      return Alloc<expr::List>(tok, Alloc<List<syntax_asdl::expr_t*>>(), expr_context_e::Store);
    }
    return this->_TestlistComp(parent, parent->GetChild(1), id_);
  }
  if (id_ == Id::Left_CaretBracket) {
    child = this->Expr(parent->GetChild(1));
    return Alloc<expr::Literal>(child);
  }
  if (id_ == Id::Op_LBrace) {
    i = 1;
    if (parent->GetChild(i)->typ == Id::Op_Newline) {
      i += 1;
    }
    return this->_Dict(parent, parent->GetChild(i));
  }
  if (id_ == Id::Arith_Amp) {
    n = parent->NumChildren();
    if (n >= 3) {
      p_die(str2090, parent->GetChild(2)->tok);
    }
    name_tok = parent->GetChild(1)->tok;
    return Alloc<expr::Place>(name_tok, lexer::TokenVal(name_tok), Alloc<List<syntax_asdl::place_op_t*>>());
  }
  if (id_ == Id::Expr_Func) {
    return Alloc<expr::Lambda>(Alloc<List<syntax_asdl::NameType*>>(), expr::Implicit);
  }
  if (id_ == Id::Expr_DecInt) {
    p_die(str2091, parent->GetChild(1)->tok);
  }
  if (id_ == Id::Expr_Float) {
    p_die(str2092, parent->GetChild(1)->tok);
  }
  assert(0);  // AssertionError
}

syntax_asdl::NameType* Transformer::_NameType(pnode::PNode* p_node) {
  syntax_asdl::Token* name_tok = nullptr;
  syntax_asdl::TypeExpr* typ = nullptr;
  int n;
  StackRoot _root0(&p_node);
  StackRoot _root1(&name_tok);
  StackRoot _root2(&typ);

  name_tok = p_node->GetChild(0)->tok;
  typ = nullptr;
  n = p_node->NumChildren();
  if (n == 2) {
    typ = this->_TypeExpr(p_node->GetChild(1));
  }
  if (n == 3) {
    typ = this->_TypeExpr(p_node->GetChild(2));
  }
  return Alloc<NameType>(name_tok, lexer::TokenVal(name_tok), typ);
}

List<syntax_asdl::NameType*>* Transformer::_NameTypeList(pnode::PNode* p_node) {
  List<syntax_asdl::NameType*>* results = nullptr;
  int n;
  StackRoot _root0(&p_node);
  StackRoot _root1(&results);

  results = Alloc<List<syntax_asdl::NameType*>>();
  n = p_node->NumChildren();
  for (int i = 0; i < n; i += 2) {
    results->append(this->_NameType(p_node->GetChild(i)));
  }
  return results;
}

syntax_asdl::Comprehension* Transformer::_CompFor(pnode::PNode* p_node) {
  List<syntax_asdl::NameType*>* lhs = nullptr;
  syntax_asdl::expr_t* iterable = nullptr;
  syntax_asdl::expr_t* cond = nullptr;
  StackRoot _root0(&p_node);
  StackRoot _root1(&lhs);
  StackRoot _root2(&iterable);
  StackRoot _root3(&cond);

  lhs = this->_NameTypeList(p_node->GetChild(1));
  iterable = this->Expr(p_node->GetChild(3));
  if (p_node->NumChildren() >= 6) {
    cond = this->Expr(p_node->GetChild(5));
  }
  else {
    cond = nullptr;
  }
  return Alloc<Comprehension>(lhs, iterable, cond);
}

syntax_asdl::expr_t* Transformer::_CompareChain(pnode::PNode* parent) {
  List<syntax_asdl::Token*>* cmp_ops = nullptr;
  List<syntax_asdl::expr_t*>* comparators = nullptr;
  syntax_asdl::expr_t* left = nullptr;
  int i;
  int n;
  pnode::PNode* p = nullptr;
  syntax_asdl::Token* op = nullptr;
  StackRoot _root0(&parent);
  StackRoot _root1(&cmp_ops);
  StackRoot _root2(&comparators);
  StackRoot _root3(&left);
  StackRoot _root4(&p);
  StackRoot _root5(&op);

  cmp_ops = Alloc<List<syntax_asdl::Token*>>();
  comparators = Alloc<List<syntax_asdl::expr_t*>>();
  left = this->Expr(parent->GetChild(0));
  i = 1;
  n = parent->NumChildren();
  while (i < n) {
    p = parent->GetChild(i);
    op = p->GetChild(0)->tok;
    if (p->NumChildren() == 2) {
      if (op->id == Id::Expr_Not) {
        op->id = Id::Node_NotIn;
      }
      else {
        if (op->id == Id::Expr_Is) {
          op->id = Id::Node_IsNot;
        }
        else {
          assert(0);  // AssertionError
        }
      }
    }
    else {
      ;  // pass
    }
    cmp_ops->append(op);
    i += 1;
    comparators->append(this->Expr(parent->GetChild(i)));
    i += 1;
  }
  return Alloc<expr::Compare>(left, cmp_ops, comparators);
}

syntax_asdl::expr_t* Transformer::_Subscript(pnode::PNode* parent) {
  int typ0;
  int n;
  syntax_asdl::expr_t* lower = nullptr;
  syntax_asdl::expr_t* upper = nullptr;
  StackRoot _root0(&parent);
  StackRoot _root1(&lower);
  StackRoot _root2(&upper);

  typ0 = parent->GetChild(0)->typ;
  n = parent->NumChildren();
  if (typ0 == grammar_nt::expr) {
    if (n == 3) {
      lower = this->Expr(parent->GetChild(0));
      upper = this->Expr(parent->GetChild(2));
    }
    else {
      if (n == 2) {
        lower = this->Expr(parent->GetChild(0));
        upper = nullptr;
      }
      else {
        return this->Expr(parent->GetChild(0));
      }
    }
  }
  else {
    lower = nullptr;
    if (n == 1) {
      upper = nullptr;
    }
    else {
      upper = this->Expr(parent->GetChild(1));
    }
  }
  return Alloc<expr::Slice>(lower, parent->GetChild(0)->tok, upper);
}

syntax_asdl::expr_t* Transformer::Expr(pnode::PNode* pnode) {
  int typ;
  syntax_asdl::expr_t* test = nullptr;
  syntax_asdl::expr_t* body = nullptr;
  syntax_asdl::expr_t* orelse = nullptr;
  int n;
  List<syntax_asdl::NameType*>* params = nullptr;
  syntax_asdl::Token* op_tok = nullptr;
  pnode::PNode* op = nullptr;
  pnode::PNode* e = nullptr;
  syntax_asdl::expr_t* node = nullptr;
  int i;
  syntax_asdl::expr_t* factor = nullptr;
  DoubleQuoted* s = nullptr;
  syntax_asdl::Token* tok = nullptr;
  BigStr* bare = nullptr;
  BigStr* tok_str = nullptr;
  BigStr* c_under = nullptr;
  value_asdl::value_t* cval = nullptr;
  BigStr* hex_str = nullptr;
  BigStr* byte = nullptr;
  StackRoot _root0(&pnode);
  StackRoot _root1(&test);
  StackRoot _root2(&body);
  StackRoot _root3(&orelse);
  StackRoot _root4(&params);
  StackRoot _root5(&op_tok);
  StackRoot _root6(&op);
  StackRoot _root7(&e);
  StackRoot _root8(&node);
  StackRoot _root9(&factor);
  StackRoot _root10(&s);
  StackRoot _root11(&tok);
  StackRoot _root12(&bare);
  StackRoot _root13(&tok_str);
  StackRoot _root14(&c_under);
  StackRoot _root15(&cval);
  StackRoot _root16(&hex_str);
  StackRoot _root17(&byte);

  typ = pnode->typ;
  if (typ == grammar_nt::ysh_expr) {
    return this->Expr(pnode->GetChild(1));
  }
  if (typ == grammar_nt::command_expr) {
    return this->Expr(pnode->GetChild(0));
  }
  if (typ == grammar_nt::atom) {
    if (pnode->NumChildren() == 1) {
      return this->Expr(pnode->GetChild(0));
    }
    return this->_Atom(pnode);
  }
  if (typ == grammar_nt::testlist) {
    return this->_Tuple(pnode);
  }
  if (typ == grammar_nt::test) {
    if (pnode->NumChildren() == 1) {
      return this->Expr(pnode->GetChild(0));
    }
    test = this->Expr(pnode->GetChild(2));
    body = this->Expr(pnode->GetChild(0));
    orelse = this->Expr(pnode->GetChild(4));
    return Alloc<expr::IfExp>(test, body, orelse);
  }
  if (typ == grammar_nt::lambdef) {
    n = pnode->NumChildren();
    if (n == 4) {
      params = this->_NameTypeList(pnode->GetChild(1));
    }
    else {
      params = Alloc<List<syntax_asdl::NameType*>>();
    }
    body = this->Expr(pnode->GetChild((n - 1)));
    return Alloc<expr::Lambda>(params, body);
  }
  if (typ == grammar_nt::or_test) {
    return this->_LeftAssoc(pnode);
  }
  if (typ == grammar_nt::and_test) {
    return this->_LeftAssoc(pnode);
  }
  if (typ == grammar_nt::not_test) {
    if (pnode->NumChildren() == 1) {
      return this->Expr(pnode->GetChild(0));
    }
    op_tok = pnode->GetChild(0)->tok;
    return Alloc<expr::Unary>(op_tok, this->Expr(pnode->GetChild(1)));
  }
  else {
    if (typ == grammar_nt::comparison) {
      if (pnode->NumChildren() == 1) {
        return this->Expr(pnode->GetChild(0));
      }
      return this->_CompareChain(pnode);
    }
    else {
      if (typ == grammar_nt::range_expr) {
        n = pnode->NumChildren();
        if (n == 1) {
          return this->Expr(pnode->GetChild(0));
        }
        if (n == 3) {
          return Alloc<expr::Range>(this->Expr(pnode->GetChild(0)), pnode->GetChild(1)->tok, this->Expr(pnode->GetChild(2)));
        }
        assert(0);  // AssertionError
      }
      else {
        if (typ == grammar_nt::expr) {
          return this->_LeftAssoc(pnode);
        }
      }
    }
  }
  if (typ == grammar_nt::xor_expr) {
    return this->_LeftAssoc(pnode);
  }
  if (typ == grammar_nt::and_expr) {
    return this->_LeftAssoc(pnode);
  }
  else {
    if (typ == grammar_nt::shift_expr) {
      return this->_LeftAssoc(pnode);
    }
    else {
      if (typ == grammar_nt::arith_expr) {
        return this->_LeftAssoc(pnode);
      }
      else {
        if (typ == grammar_nt::term) {
          return this->_LeftAssoc(pnode);
        }
        else {
          if (typ == grammar_nt::factor) {
            if (pnode->NumChildren() == 1) {
              return this->Expr(pnode->GetChild(0));
            }
            op = pnode->GetChild(0);
            e = pnode->GetChild(1);
            return Alloc<expr::Unary>(op->tok, this->Expr(e));
          }
          else {
            if (typ == grammar_nt::power) {
              node = this->Expr(pnode->GetChild(0));
              if (pnode->NumChildren() == 1) {
                return node;
              }
              n = pnode->NumChildren();
              i = 1;
              while ((i < n and pnode->GetChild(i)->typ == grammar_nt::trailer)) {
                node = this->_Trailer(node, pnode->GetChild(i));
                i += 1;
              }
              if (i != n) {
                op_tok = pnode->GetChild(i)->tok;
                factor = this->Expr(pnode->GetChild((i + 1)));
                node = Alloc<expr::Binary>(op_tok, node, factor);
              }
              return node;
            }
            else {
              if (typ == grammar_nt::eggex) {
                return this->_Eggex(pnode);
              }
              else {
                if (typ == grammar_nt::ysh_expr_sub) {
                  return this->Expr(pnode->GetChild(0));
                }
                else {
                  if (typ == grammar_nt::sh_array_literal) {
                    return reinterpret_cast<ShArrayLiteral*>(pnode->GetChild(1)->tok);
                  }
                  else {
                    if (typ == grammar_nt::old_sh_array_literal) {
                      return reinterpret_cast<ShArrayLiteral*>(pnode->GetChild(1)->tok);
                    }
                    else {
                      if (typ == grammar_nt::sh_command_sub) {
                        return reinterpret_cast<CommandSub*>(pnode->GetChild(1)->tok);
                      }
                      else {
                        if (typ == grammar_nt::braced_var_sub) {
                          return reinterpret_cast<BracedVarSub*>(pnode->GetChild(1)->tok);
                        }
                        else {
                          if (typ == grammar_nt::dq_string) {
                            s = reinterpret_cast<DoubleQuoted*>(pnode->GetChild(1)->tok);
                            if (pnode->GetChild(0)->typ == Id::Left_CaretDoubleQuote) {
                              return Alloc<expr::Literal>(s);
                            }
                            return s;
                          }
                          else {
                            if (typ == grammar_nt::sq_string) {
                              return reinterpret_cast<SingleQuoted*>(pnode->GetChild(1)->tok);
                            }
                            else {
                              if (typ == grammar_nt::simple_var_sub) {
                                tok = pnode->GetChild(0)->tok;
                                if (tok->id == Id::VSub_DollarName) {
                                  bare = lexer::TokenSliceLeft(tok, 1);
                                  p_die(StrFormat("In expressions, remove $ and use `%s`, or sometimes \"$%s\"", bare, bare), tok);
                                }
                                return Alloc<SimpleVarSub>(tok);
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  }
  tok = pnode->tok;
  if (typ == Id::Expr_Name) {
    return Alloc<expr::Var>(tok, lexer::TokenVal(tok));
  }
  tok_str = lexer::TokenVal(tok);
  c_under = tok_str->replace(str2094, str2095);
  if (typ == Id::Expr_DecInt) {
    try {
      cval = Alloc<value::Int>(mops::FromStr(c_under));
    }
    catch (ValueError*) {
      p_die(str2096, tok);
    }
  }
  else {
    if (typ == Id::Expr_BinInt) {
      try {
        cval = Alloc<value::Int>(mops::FromStr(c_under->slice(2), 2));
      }
      catch (ValueError*) {
        p_die(str2097, tok);
      }
    }
    else {
      if (typ == Id::Expr_OctInt) {
        try {
          cval = Alloc<value::Int>(mops::FromStr(c_under->slice(2), 8));
        }
        catch (ValueError*) {
          p_die(str2098, tok);
        }
      }
      else {
        if (typ == Id::Expr_HexInt) {
          try {
            cval = Alloc<value::Int>(mops::FromStr(c_under->slice(2), 16));
          }
          catch (ValueError*) {
            p_die(str2099, tok);
          }
        }
        else {
          if (typ == Id::Expr_Float) {
            cval = Alloc<value::Float>(to_float(c_under));
          }
          else {
            if (typ == Id::Expr_Null) {
              cval = value::Null;
            }
            else {
              if (typ == Id::Expr_True) {
                cval = Alloc<value::Bool>(true);
              }
              else {
                if (typ == Id::Expr_False) {
                  cval = Alloc<value::Bool>(false);
                }
                else {
                  if (typ == Id::Char_OneChar) {
                    cval = num::ToBig(ord(consts::LookupCharC(tok_str->at(1))));
                  }
                  else {
                    if (typ == Id::Char_UBraced) {
                      hex_str = tok_str->slice(3, -1);
                      cval = Alloc<value::Int>(mops::FromStr(hex_str, 16));
                    }
                    else {
                      if (typ == Id::Char_Pound) {
                        byte = tok_str->at(2);
                        cval = num::ToBig(ord(byte));
                      }
                      else {
                        assert(0);  // AssertionError
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  }
  return Alloc<expr::Const>(tok, cval);
}

void Transformer::_CheckLhs(syntax_asdl::expr_t* lhs) {
  syntax_asdl::expr_t* UP_lhs = nullptr;
  StackRoot _root0(&lhs);
  StackRoot _root1(&UP_lhs);

  UP_lhs = lhs;
  switch (lhs->tag()) {
    case expr_e::Var: {
      ;  // pass
    }
      break;
    case expr_e::Subscript: {
      Subscript* lhs = static_cast<Subscript*>(UP_lhs);
      this->_CheckLhs(lhs->obj);
    }
      break;
    case expr_e::Attribute: {
      Attribute* lhs = static_cast<Attribute*>(UP_lhs);
      this->_CheckLhs(lhs->obj);
    }
      break;
    default: {
      p_die(str2100, location::TokenForExpr(lhs));
    }
  }
}

List<syntax_asdl::y_lhs_t*>* Transformer::_LhsExprList(pnode::PNode* p_node) {
  List<syntax_asdl::y_lhs_t*>* lhs_list = nullptr;
  int n;
  pnode::PNode* p = nullptr;
  syntax_asdl::expr_t* e = nullptr;
  syntax_asdl::expr_t* UP_e = nullptr;
  syntax_asdl::loc_t* blame = nullptr;
  StackRoot _root0(&p_node);
  StackRoot _root1(&lhs_list);
  StackRoot _root2(&p);
  StackRoot _root3(&e);
  StackRoot _root4(&UP_e);
  StackRoot _root5(&blame);

  lhs_list = Alloc<List<syntax_asdl::y_lhs_t*>>();
  n = p_node->NumChildren();
  for (int i = 0; i < n; i += 2) {
    p = p_node->GetChild(i);
    e = this->Expr(p);
    UP_e = e;
    switch (e->tag()) {
      case expr_e::Var: {
        expr::Var* e = static_cast<expr::Var*>(UP_e);
        lhs_list->append(e->left);
      }
        break;
      case expr_e::Subscript: {
        Subscript* e = static_cast<Subscript*>(UP_e);
        this->_CheckLhs(e);
        lhs_list->append(e);
      }
        break;
      case expr_e::Attribute: {
        Attribute* e = static_cast<Attribute*>(UP_e);
        this->_CheckLhs(e);
        if (e->op->id != Id::Expr_Dot) {
          p_die(str2101, e->op);
        }
        lhs_list->append(e);
      }
        break;
      default: {
        ;  // pass
        if (p->tok) {
          blame = p->tok;
        }
        else {
          blame = loc::Missing;
        }
        p_die(str2102, blame);
      }
    }
  }
  return lhs_list;
}

command::VarDecl* Transformer::MakeVarDecl(pnode::PNode* p_node) {
  List<syntax_asdl::NameType*>* lhs = nullptr;
  int n;
  syntax_asdl::expr_t* rhs = nullptr;
  StackRoot _root0(&p_node);
  StackRoot _root1(&lhs);
  StackRoot _root2(&rhs);

  lhs = this->_NameTypeList(p_node->GetChild(0));
  n = p_node->NumChildren();
  if (n >= 3) {
    rhs = this->Expr(p_node->GetChild(2));
  }
  else {
    rhs = nullptr;
  }
  return Alloc<command::VarDecl>(nullptr, lhs, rhs);
}

command::Mutation* Transformer::MakeMutation(pnode::PNode* p_node) {
  int typ;
  List<syntax_asdl::y_lhs_t*>* lhs_list = nullptr;
  syntax_asdl::Token* op_tok = nullptr;
  syntax_asdl::expr_t* rhs = nullptr;
  StackRoot _root0(&p_node);
  StackRoot _root1(&lhs_list);
  StackRoot _root2(&op_tok);
  StackRoot _root3(&rhs);

  typ = p_node->typ;
  lhs_list = this->_LhsExprList(p_node->GetChild(0));
  op_tok = p_node->GetChild(1)->tok;
  if ((len(lhs_list) > 1 and op_tok->id != Id::Arith_Equal)) {
    p_die(str2103, op_tok);
  }
  rhs = this->Expr(p_node->GetChild(2));
  return Alloc<command::Mutation>(nullptr, lhs_list, op_tok, rhs);
}

syntax_asdl::EggexFlag* Transformer::_EggexFlag(pnode::PNode* p_node) {
  int n;
  StackRoot _root0(&p_node);

  n = p_node->NumChildren();
  if (n == 1) {
    return Alloc<EggexFlag>(false, p_node->GetChild(0)->tok);
  }
  else {
    if (n == 2) {
      return Alloc<EggexFlag>(true, p_node->GetChild(1)->tok);
    }
    else {
      assert(0);  // AssertionError
    }
  }
}

syntax_asdl::Eggex* Transformer::_Eggex(pnode::PNode* p_node) {
  syntax_asdl::Token* left = nullptr;
  syntax_asdl::re_t* regex = nullptr;
  List<syntax_asdl::EggexFlag*>* flags = nullptr;
  syntax_asdl::Token* trans_pref = nullptr;
  int i;
  pnode::PNode* current = nullptr;
  BigStr* canonical_flags = nullptr;
  StackRoot _root0(&p_node);
  StackRoot _root1(&left);
  StackRoot _root2(&regex);
  StackRoot _root3(&flags);
  StackRoot _root4(&trans_pref);
  StackRoot _root5(&current);
  StackRoot _root6(&canonical_flags);

  left = p_node->GetChild(0)->tok;
  regex = this->_Regex(p_node->GetChild(1));
  flags = Alloc<List<syntax_asdl::EggexFlag*>>();
  trans_pref = nullptr;
  i = 2;
  current = p_node->GetChild(i);
  if (current->typ == Id::Op_Semi) {
    i += 1;
    while (true) {
      current = p_node->GetChild(i);
      if (current->typ != grammar_nt::re_flag) {
        break;
      }
      flags->append(this->_EggexFlag(current));
      i += 1;
    }
    if (current->typ == Id::Op_Semi) {
      i += 1;
      trans_pref = p_node->GetChild(i)->tok;
    }
  }
  if ((trans_pref == nullptr or str_equals(lexer::TokenVal(trans_pref), str2104))) {
    canonical_flags = regex_translate::CanonicalFlags(flags);
  }
  else {
    canonical_flags = nullptr;
  }
  return Alloc<Eggex>(left, regex, flags, trans_pref, canonical_flags);
}

syntax_asdl::pat_t* Transformer::YshCasePattern(pnode::PNode* pnode) {
  pnode::PNode* pattern = nullptr;
  int typ;
  List<syntax_asdl::expr_t*>* exprs = nullptr;
  pnode::PNode* child = nullptr;
  syntax_asdl::expr_t* expr = nullptr;
  StackRoot _root0(&pnode);
  StackRoot _root1(&pattern);
  StackRoot _root2(&exprs);
  StackRoot _root3(&child);
  StackRoot _root4(&expr);

  pattern = pnode->GetChild(0);
  typ = pattern->typ;
  if (typ == Id::Op_LParen) {
    pattern = pnode->GetChild(1);
    typ = pattern->typ;
    if (typ == grammar_nt::pat_else) {
      return pat::Else;
    }
    if (typ == grammar_nt::pat_exprs) {
      exprs = Alloc<List<syntax_asdl::expr_t*>>();
      for (int i = 0; i < pattern->NumChildren(); ++i) {
        child = pattern->GetChild(i);
        if (child->typ == grammar_nt::expr) {
          expr = this->Expr(child);
          exprs->append(expr);
        }
      }
      return Alloc<pat::YshExprs>(exprs);
    }
  }
  if (typ == grammar_nt::eggex) {
    return this->_Eggex(pattern);
  }
  assert(0);  // AssertionError
}

syntax_asdl::expr_t* Transformer::_BlockArg(pnode::PNode* p_node) {
  int n;
  pnode::PNode* child = nullptr;
  StackRoot _root0(&p_node);
  StackRoot _root1(&child);

  n = p_node->NumChildren();
  if (n == 1) {
    child = p_node->GetChild(0);
    return this->Expr(child);
  }
  p_die(str2105, p_node->tok);
}

void Transformer::_Argument(pnode::PNode* p_node, bool after_semi, syntax_asdl::ArgList* arglist) {
  List<syntax_asdl::expr_t*>* pos_args = nullptr;
  List<syntax_asdl::NamedArg*>* named_args = nullptr;
  int n;
  pnode::PNode* child = nullptr;
  syntax_asdl::expr_t* arg = nullptr;
  syntax_asdl::Token* tok0 = nullptr;
  expr::Spread* spread_expr = nullptr;
  syntax_asdl::expr_t* elt = nullptr;
  syntax_asdl::Comprehension* comp = nullptr;
  syntax_asdl::NamedArg* n1 = nullptr;
  StackRoot _root0(&p_node);
  StackRoot _root1(&arglist);
  StackRoot _root2(&pos_args);
  StackRoot _root3(&named_args);
  StackRoot _root4(&child);
  StackRoot _root5(&arg);
  StackRoot _root6(&tok0);
  StackRoot _root7(&spread_expr);
  StackRoot _root8(&elt);
  StackRoot _root9(&comp);
  StackRoot _root10(&n1);

  pos_args = arglist->pos_args;
  named_args = arglist->named_args;
  n = p_node->NumChildren();
  if (n == 1) {
    child = p_node->GetChild(0);
    if (after_semi) {
      p_die(POS_ARG_MISPLACED, child->tok);
    }
    arg = this->Expr(child);
    pos_args->append(arg);
    return ;
  }
  if (n == 2) {
    tok0 = p_node->GetChild(0)->tok;
    if (tok0->id == Id::Expr_Ellipsis) {
      spread_expr = Alloc<expr::Spread>(tok0, this->Expr(p_node->GetChild(1)));
      if (after_semi) {
        named_args->append(Alloc<NamedArg>(nullptr, spread_expr));
      }
      else {
        pos_args->append(spread_expr);
      }
      return ;
    }
    if (p_node->GetChild(1)->typ == grammar_nt::comp_for) {
      child = p_node->GetChild(0);
      if (after_semi) {
        p_die(POS_ARG_MISPLACED, child->tok);
      }
      elt = this->Expr(child);
      comp = this->_CompFor(p_node->GetChild(1));
      arg = Alloc<expr::GeneratorExp>(elt, NewList<syntax_asdl::Comprehension*>(std::initializer_list<syntax_asdl::Comprehension*>{comp}));
      pos_args->append(arg);
      return ;
    }
    assert(0);  // AssertionError
  }
  if (n == 3) {
    n1 = Alloc<NamedArg>(p_node->GetChild(0)->tok, this->Expr(p_node->GetChild(2)));
    named_args->append(n1);
    return ;
  }
  assert(0);  // AssertionError
}

void Transformer::_ArgGroup(pnode::PNode* p_node, bool after_semi, syntax_asdl::ArgList* arglist) {
  pnode::PNode* p_child = nullptr;
  StackRoot _root0(&p_node);
  StackRoot _root1(&arglist);
  StackRoot _root2(&p_child);

  for (int i = 0; i < p_node->NumChildren(); ++i) {
    p_child = p_node->GetChild(i);
    if (p_child->typ == grammar_nt::argument) {
      this->_Argument(p_child, after_semi, arglist);
    }
  }
}

void Transformer::_ArgList(pnode::PNode* p_node, syntax_asdl::ArgList* arglist) {
  int n;
  int i;
  pnode::PNode* child = nullptr;
  StackRoot _root0(&p_node);
  StackRoot _root1(&arglist);
  StackRoot _root2(&child);

  n = p_node->NumChildren();
  if (n == 0) {
    return ;
  }
  i = 0;
  if (i >= n) {
    return ;
  }
  child = p_node->GetChild(i);
  if (child->typ == grammar_nt::arg_group) {
    this->_ArgGroup(child, false, arglist);
    i += 1;
  }
  if (i >= n) {
    return ;
  }
  child = p_node->GetChild(i);
  if (child->typ == Id::Op_Semi) {
    arglist->semi_tok = child->tok;
    i += 1;
  }
  if (i >= n) {
    return ;
  }
  child = p_node->GetChild(i);
  if (child->typ == grammar_nt::arg_group) {
    this->_ArgGroup(child, true, arglist);
    i += 1;
  }
  if (i >= n) {
    return ;
  }
  child = p_node->GetChild(i);
  if (child->typ == Id::Op_Semi) {
    arglist->semi_tok2 = child->tok;
    i += 1;
  }
  if (i >= n) {
    return ;
  }
  child = p_node->GetChild(i);
  if (child->typ == grammar_nt::argument) {
    arglist->block_expr = this->_BlockArg(child);
    i += 1;
  }
}

void Transformer::ProcCallArgs(pnode::PNode* pnode, syntax_asdl::ArgList* arglist) {
  int n;
  pnode::PNode* child1 = nullptr;
  StackRoot _root0(&pnode);
  StackRoot _root1(&arglist);
  StackRoot _root2(&child1);

  n = pnode->NumChildren();
  if (n == 2) {
    return ;
  }
  if (n == 3) {
    child1 = pnode->GetChild(1);
    this->_ArgList(child1, arglist);
    return ;
  }
  assert(0);  // AssertionError
}

syntax_asdl::TypeExpr* Transformer::_TypeExpr(pnode::PNode* pnode) {
  syntax_asdl::TypeExpr* ty = nullptr;
  int n;
  int i;
  syntax_asdl::TypeExpr* p = nullptr;
  StackRoot _root0(&pnode);
  StackRoot _root1(&ty);
  StackRoot _root2(&p);

  ty = TypeExpr::CreateNull();
  ty->tok = pnode->GetChild(0)->tok;
  ty->name = lexer::TokenVal(ty->tok);
  n = pnode->NumChildren();
  if (n == 1) {
    return ty;
  }
  ty->params = Alloc<List<syntax_asdl::TypeExpr*>>();
  i = 2;
  while (i < n) {
    p = this->_TypeExpr(pnode->GetChild(i));
    ty->params->append(p);
    i += 2;
  }
  return ty;
}

syntax_asdl::Param* Transformer::_Param(pnode::PNode* pnode) {
  syntax_asdl::Token* name_tok = nullptr;
  int n;
  syntax_asdl::expr_t* default_val = nullptr;
  syntax_asdl::TypeExpr* type_ = nullptr;
  StackRoot _root0(&pnode);
  StackRoot _root1(&name_tok);
  StackRoot _root2(&default_val);
  StackRoot _root3(&type_);

  name_tok = pnode->GetChild(0)->tok;
  n = pnode->NumChildren();
  default_val = nullptr;
  type_ = nullptr;
  if (n == 1) {
    ;  // pass
  }
  else {
    if (n == 2) {
      type_ = this->_TypeExpr(pnode->GetChild(1));
    }
    else {
      if (n == 3) {
        default_val = this->Expr(pnode->GetChild(2));
      }
      else {
        if (n == 4) {
          type_ = this->_TypeExpr(pnode->GetChild(1));
          default_val = this->Expr(pnode->GetChild(3));
        }
      }
    }
  }
  return Alloc<Param>(name_tok, lexer::TokenVal(name_tok), type_, default_val);
}

syntax_asdl::ParamGroup* Transformer::_ParamGroup(pnode::PNode* p_node) {
  List<syntax_asdl::Param*>* params = nullptr;
  syntax_asdl::RestParam* rest_of = nullptr;
  int n;
  int i;
  pnode::PNode* child = nullptr;
  syntax_asdl::Token* tok = nullptr;
  StackRoot _root0(&p_node);
  StackRoot _root1(&params);
  StackRoot _root2(&rest_of);
  StackRoot _root3(&child);
  StackRoot _root4(&tok);

  params = Alloc<List<syntax_asdl::Param*>>();
  rest_of = nullptr;
  n = p_node->NumChildren();
  i = 0;
  while (i < n) {
    child = p_node->GetChild(i);
    if (child->typ == grammar_nt::param) {
      params->append(this->_Param(child));
    }
    else {
      if (child->typ == Id::Expr_Ellipsis) {
        tok = p_node->GetChild((i + 1))->tok;
        rest_of = Alloc<RestParam>(tok, lexer::TokenVal(tok));
      }
    }
    i += 2;
  }
  return Alloc<ParamGroup>(params, rest_of);
}

syntax_asdl::proc_sig_t* Transformer::Proc(pnode::PNode* p_node) {
  int typ;
  int n;
  proc_sig::Closed* sig = nullptr;
  int i;
  pnode::PNode* child = nullptr;
  syntax_asdl::ParamGroup* group = nullptr;
  List<syntax_asdl::Param*>* params = nullptr;
  StackRoot _root0(&p_node);
  StackRoot _root1(&sig);
  StackRoot _root2(&child);
  StackRoot _root3(&group);
  StackRoot _root4(&params);

  typ = p_node->typ;
  n = p_node->NumChildren();
  if (n == 1) {
    return proc_sig::Open;
  }
  if (n == 3) {
    sig = proc_sig::Closed::CreateNull(true);
  }
  sig = proc_sig::Closed::CreateNull(true);
  i = 1;
  child = p_node->GetChild(i);
  if (child->typ == grammar_nt::param_group) {
    sig->word = this->_ParamGroup(p_node->GetChild(i));
    for (ListIter<syntax_asdl::Param*> it(sig->word->params); !it.Done(); it.Next()) {
      syntax_asdl::Param* word = it.Value();
      StackRoot _for(&word    );
      if (word->type) {
        if ((!str_equals(word->type->name, str2106) && !str_equals(word->type->name, str2107))) {
          p_die(str2108, word->type->tok);
        }
        if (word->type->params != nullptr) {
          p_die(str2109, word->type->tok);
        }
      }
    }
    i += 2;
  }
  else {
    i += 1;
  }
  if (i >= n) {
    return sig;
  }
  child = p_node->GetChild(i);
  if (child->typ == grammar_nt::param_group) {
    sig->positional = this->_ParamGroup(p_node->GetChild(i));
    i += 2;
  }
  else {
    i += 1;
  }
  if (i >= n) {
    return sig;
  }
  child = p_node->GetChild(i);
  if (child->typ == grammar_nt::param_group) {
    sig->named = this->_ParamGroup(p_node->GetChild(i));
    i += 2;
  }
  else {
    i += 1;
  }
  if (i >= n) {
    return sig;
  }
  child = p_node->GetChild(i);
  if (child->typ == grammar_nt::param_group) {
    group = this->_ParamGroup(p_node->GetChild(i));
    params = group->params;
    if (len(params) > 1) {
      p_die(str2110, params->at(1)->blame_tok);
    }
    if (group->rest_of) {
      p_die(str2111, group->rest_of->blame_tok);
    }
    if (len(params) == 1) {
      if (params->at(0)->type) {
        if (!(str_equals(params->at(0)->type->name, str2112))) {
          p_die(str2113, params->at(0)->type->tok);
        }
        if (params->at(0)->type->params != nullptr) {
          p_die(str2114, params->at(0)->type->tok);
        }
      }
      sig->block_param = params->at(0);
    }
  }
  return sig;
}

void Transformer::YshFunc(pnode::PNode* p_node, syntax_asdl::Func* out) {
  int n;
  int i;
  pnode::PNode* child = nullptr;
  StackRoot _root0(&p_node);
  StackRoot _root1(&out);
  StackRoot _root2(&child);

  out->name = p_node->GetChild(0)->tok;
  n = p_node->NumChildren();
  i = 2;
  child = p_node->GetChild(i);
  if (child->typ == grammar_nt::param_group) {
    out->positional = this->_ParamGroup(child);
    i += 2;
  }
  else {
    i += 1;
  }
  if (i >= n) {
    return ;
  }
  child = p_node->GetChild(i);
  if (child->typ == grammar_nt::param_group) {
    out->named = this->_ParamGroup(child);
  }
}

syntax_asdl::CharCode* Transformer::_RangeCharSingleQuoted(pnode::PNode* p_node) {
  pnode::PNode* child0 = nullptr;
  SingleQuoted* sq_part = nullptr;
  int n;
  StackRoot _root0(&p_node);
  StackRoot _root1(&child0);
  StackRoot _root2(&sq_part);

  child0 = p_node->GetChild(0);
  if (child0->typ == grammar_nt::sq_string) {
    sq_part = reinterpret_cast<SingleQuoted*>(child0->GetChild(1)->tok);
    n = len(sq_part->sval);
    if (n == 0) {
      p_die(str2115, Alloc<loc::WordPart>(sq_part));
    }
    else {
      if (n == 1) {
        return Alloc<CharCode>(sq_part->left, ord(sq_part->sval->at(0)), false);
      }
      else {
        p_die(RANGE_POINT_TOO_LONG, Alloc<loc::WordPart>(sq_part));
      }
    }
  }
  return nullptr;
}

syntax_asdl::Token* Transformer::_OtherRangeToken(pnode::PNode* p_node) {
  pnode::PNode* child0 = nullptr;
  syntax_asdl::Token* tok = nullptr;
  StackRoot _root0(&p_node);
  StackRoot _root1(&child0);
  StackRoot _root2(&tok);

  child0 = p_node->GetChild(0);
  if (child0->typ == grammar_nt::char_literal) {
    tok = child0->GetChild(0)->tok;
    return tok;
  }
  tok = p_node->tok;
  if (tok->length != 1) {
    p_die(RANGE_POINT_TOO_LONG, tok);
  }
  return tok;
}

syntax_asdl::class_literal_term_t* Transformer::_NonRangeChars(pnode::PNode* p_node) {
  pnode::PNode* child0 = nullptr;
  int typ0;
  StackRoot _root0(&p_node);
  StackRoot _root1(&child0);

  child0 = p_node->GetChild(0);
  typ0 = p_node->GetChild(0)->typ;
  if (typ0 == grammar_nt::sq_string) {
    return reinterpret_cast<SingleQuoted*>(child0->GetChild(1)->tok);
  }
  if (typ0 == grammar_nt::char_literal) {
    return word_compile::EvalCharLiteralForRegex(child0->tok);
  }
  if (typ0 == Id::Expr_Name) {
    return this->_NameInClass(nullptr, child0->tok);
  }
  assert(0);  // AssertionError
}

syntax_asdl::class_literal_term_t* Transformer::_ClassLiteralTerm(pnode::PNode* p_node) {
  int typ0;
  int n;
  pnode::PNode* left = nullptr;
  pnode::PNode* right = nullptr;
  syntax_asdl::CharCode* code1 = nullptr;
  syntax_asdl::Token* tok1 = nullptr;
  syntax_asdl::CharCode* code2 = nullptr;
  syntax_asdl::Token* tok2 = nullptr;
  StackRoot _root0(&p_node);
  StackRoot _root1(&left);
  StackRoot _root2(&right);
  StackRoot _root3(&code1);
  StackRoot _root4(&tok1);
  StackRoot _root5(&code2);
  StackRoot _root6(&tok2);

  typ0 = p_node->GetChild(0)->typ;
  if (typ0 == grammar_nt::range_char) {
    n = p_node->NumChildren();
    if (n == 1) {
      return this->_NonRangeChars(p_node->GetChild(0));
    }
    if (n == 3) {
      left = p_node->GetChild(0);
      right = p_node->GetChild(2);
      code1 = this->_RangeCharSingleQuoted(left);
      if (code1 == nullptr) {
        tok1 = this->_OtherRangeToken(left);
        code1 = word_compile::EvalCharLiteralForRegex(tok1);
      }
      code2 = this->_RangeCharSingleQuoted(right);
      if (code2 == nullptr) {
        tok2 = this->_OtherRangeToken(right);
        code2 = word_compile::EvalCharLiteralForRegex(tok2);
      }
      return Alloc<CharRange>(code1, code2);
    }
    assert(0);  // AssertionError
  }
  if (typ0 == Id::Expr_At) {
    tok1 = p_node->GetChild(1)->tok;
    return Alloc<class_literal_term::Splice>(tok1, lexer::TokenVal(tok1));
  }
  if (typ0 == Id::Expr_Bang) {
    return this->_NameInClass(p_node->GetChild(0)->tok, p_node->GetChild(1)->tok);
  }
  p_die(str2116, p_node->GetChild(0)->tok);
}

List<syntax_asdl::class_literal_term_t*>* Transformer::_ClassLiteral(pnode::PNode* p_node) {
  List<syntax_asdl::class_literal_term_t*>* terms = nullptr;
  StackRoot _root0(&p_node);
  StackRoot _root1(&terms);

  terms = Alloc<List<syntax_asdl::class_literal_term_t*>>();
  for (int i = 1; i < (p_node->NumChildren() - 1); ++i) {
    terms->append(this->_ClassLiteralTerm(p_node->GetChild(i)));
  }
  return terms;
}

syntax_asdl::re_t* Transformer::_NameInRegex(syntax_asdl::Token* negated_tok, syntax_asdl::Token* tok) {
  BigStr* tok_str = nullptr;
  BigStr* perl = nullptr;
  StackRoot _root0(&negated_tok);
  StackRoot _root1(&tok);
  StackRoot _root2(&tok_str);
  StackRoot _root3(&perl);

  tok_str = lexer::TokenVal(tok);
  if (str_equals(tok_str, str2117)) {
    if (negated_tok) {
      p_die(str2118, tok);
    }
    return Alloc<re::Primitive>(tok, Id::Eggex_Dot);
  }
  if (list_contains(POSIX_CLASSES, tok_str)) {
    return Alloc<PosixClass>(negated_tok, tok_str);
  }
  perl = PERL_CLASSES->get(tok_str);
  if (perl != nullptr) {
    return Alloc<PerlClass>(negated_tok, perl);
  }
  if (tok_str->at(0)->isupper()) {
    return Alloc<re::Splice>(tok, lexer::TokenVal(tok));
  }
  p_die(StrFormat("%r isn't a character class", tok_str), tok);
}

syntax_asdl::class_literal_term_t* Transformer::_NameInClass(syntax_asdl::Token* negated_tok, syntax_asdl::Token* tok) {
  BigStr* tok_str = nullptr;
  BigStr* perl = nullptr;
  StackRoot _root0(&negated_tok);
  StackRoot _root1(&tok);
  StackRoot _root2(&tok_str);
  StackRoot _root3(&perl);

  tok_str = lexer::TokenVal(tok);
  if (len(tok_str) == 1) {
    if (negated_tok) {
      p_die(str2120, tok);
    }
    return word_compile::EvalCharLiteralForRegex(tok);
  }
  if (list_contains(POSIX_CLASSES, tok_str)) {
    return Alloc<PosixClass>(negated_tok, tok_str);
  }
  perl = PERL_CLASSES->get(tok_str);
  if (perl != nullptr) {
    return Alloc<PerlClass>(negated_tok, perl);
  }
  p_die(StrFormat("%r isn't a character class", tok_str), tok);
}

syntax_asdl::re_t* Transformer::_ReAtom(pnode::PNode* p_atom) {
  pnode::PNode* child0 = nullptr;
  int typ0;
  syntax_asdl::Token* tok0 = nullptr;
  BigStr* s = nullptr;
  BigStr* tok_str = nullptr;
  syntax_asdl::Token* tok1 = nullptr;
  int n;
  pnode::PNode* child1 = nullptr;
  syntax_asdl::re_t* regex = nullptr;
  syntax_asdl::Token* as_name = nullptr;
  syntax_asdl::Token* func_name = nullptr;
  int i;
  int typ;
  StackRoot _root0(&p_atom);
  StackRoot _root1(&child0);
  StackRoot _root2(&tok0);
  StackRoot _root3(&s);
  StackRoot _root4(&tok_str);
  StackRoot _root5(&tok1);
  StackRoot _root6(&child1);
  StackRoot _root7(&regex);
  StackRoot _root8(&as_name);
  StackRoot _root9(&func_name);

  child0 = p_atom->GetChild(0);
  typ0 = p_atom->GetChild(0)->typ;
  tok0 = p_atom->GetChild(0)->tok;
  if (typ0 == grammar_nt::class_literal) {
    return Alloc<re::CharClassLiteral>(false, this->_ClassLiteral(child0));
  }
  if (typ0 == grammar_nt::sq_string) {
    return reinterpret_cast<SingleQuoted*>(child0->GetChild(1)->tok);
  }
  if (typ0 == grammar_nt::char_literal) {
    s = word_compile::EvalCStringToken(tok0->id, lexer::TokenVal(tok0));
    return Alloc<re::LiteralChars>(tok0, s);
  }
  if (typ0 == Id::Expr_Dot) {
    return Alloc<re::Primitive>(tok0, Id::Eggex_Dot);
  }
  if (typ0 == Id::Arith_Caret) {
    return Alloc<re::Primitive>(tok0, Id::Eggex_Start);
  }
  if (typ0 == Id::Expr_Dollar) {
    return Alloc<re::Primitive>(tok0, Id::Eggex_End);
  }
  if (typ0 == Id::Expr_Name) {
    return this->_NameInRegex(nullptr, tok0);
  }
  if (typ0 == Id::Expr_Symbol) {
    tok_str = lexer::TokenVal(tok0);
    if (str_equals(tok_str, str2122)) {
      return Alloc<re::Primitive>(tok0, Id::Eggex_Start);
    }
    if (str_equals(tok_str, str2123)) {
      return Alloc<re::Primitive>(tok0, Id::Eggex_End);
    }
    p_die(StrFormat("Unexpected token %r in regex", tok_str), tok0);
  }
  if (typ0 == Id::Expr_At) {
    tok1 = p_atom->GetChild(1)->tok;
    return Alloc<re::Splice>(tok0, lexer::TokenVal(tok1));
  }
  if (typ0 == Id::Expr_Bang) {
    n = p_atom->NumChildren();
    if (n == 2) {
      child1 = p_atom->GetChild(1);
      if (child1->typ == grammar_nt::class_literal) {
        return Alloc<re::CharClassLiteral>(true, this->_ClassLiteral(child1));
      }
      else {
        return this->_NameInRegex(tok0, p_atom->GetChild(1)->tok);
      }
    }
    else {
      p_die(str2125, p_atom->GetChild(1)->tok);
    }
  }
  if (typ0 == Id::Op_LParen) {
    return Alloc<re::Group>(this->_Regex(p_atom->GetChild(1)));
  }
  if (typ0 == Id::Arith_Less) {
    n = p_atom->NumChildren();
    regex = this->_Regex(p_atom->GetChild(2));
    as_name = nullptr;
    func_name = nullptr;
    i = 3;
    typ = p_atom->GetChild(i)->typ;
    if (typ == Id::Expr_As) {
      as_name = p_atom->GetChild((i + 1))->tok;
      i += 2;
    }
    typ = p_atom->GetChild(i)->typ;
    if (typ == Id::Arith_Colon) {
      func_name = p_atom->GetChild((i + 1))->tok;
    }
    return Alloc<re::Capture>(regex, as_name, func_name);
  }
  assert(0);  // AssertionError
}

syntax_asdl::re_repeat_t* Transformer::_RepeatOp(pnode::PNode* p_repeat) {
  syntax_asdl::Token* tok = nullptr;
  int id_;
  pnode::PNode* child1 = nullptr;
  int n;
  syntax_asdl::Token* left = nullptr;
  syntax_asdl::Token* right = nullptr;
  StackRoot _root0(&p_repeat);
  StackRoot _root1(&tok);
  StackRoot _root2(&child1);
  StackRoot _root3(&left);
  StackRoot _root4(&right);

  tok = p_repeat->GetChild(0)->tok;
  id_ = tok->id;
  if ((id_ == Id::Arith_Plus || id_ == Id::Arith_Star || id_ == Id::Arith_QMark)) {
    return tok;
  }
  if (id_ == Id::Op_LBrace) {
    child1 = p_repeat->GetChild(1);
    if (child1->typ != grammar_nt::repeat_range) {
      p_die(str2126, child1->tok);
    }
    n = child1->NumChildren();
    if (n == 1) {
      tok = child1->GetChild(0)->tok;
      return tok;
    }
    if (n == 2) {
      if (child1->GetChild(0)->typ == Id::Expr_DecInt) {
        left = child1->GetChild(0)->tok;
        return Alloc<re_repeat::Range>(left, lexer::TokenVal(left), str2127, nullptr);
      }
      else {
        right = child1->GetChild(1)->tok;
        return Alloc<re_repeat::Range>(nullptr, str2128, lexer::TokenVal(right), right);
      }
    }
    if (n == 3) {
      left = child1->GetChild(0)->tok;
      right = child1->GetChild(2)->tok;
      return Alloc<re_repeat::Range>(left, lexer::TokenVal(left), lexer::TokenVal(right), right);
    }
    assert(0);  // AssertionError
  }
  assert(0);  // AssertionError
}

syntax_asdl::re_t* Transformer::_ReAlt(pnode::PNode* p_node) {
  int i;
  int n;
  List<syntax_asdl::re_t*>* seq = nullptr;
  syntax_asdl::re_t* r = nullptr;
  syntax_asdl::re_repeat_t* repeat_op = nullptr;
  StackRoot _root0(&p_node);
  StackRoot _root1(&seq);
  StackRoot _root2(&r);
  StackRoot _root3(&repeat_op);

  i = 0;
  n = p_node->NumChildren();
  seq = Alloc<List<syntax_asdl::re_t*>>();
  while (i < n) {
    r = this->_ReAtom(p_node->GetChild(i));
    i += 1;
    if ((i < n and p_node->GetChild(i)->typ == grammar_nt::repeat_op)) {
      repeat_op = this->_RepeatOp(p_node->GetChild(i));
      r = Alloc<re::Repeat>(r, repeat_op);
      i += 1;
    }
    seq->append(r);
  }
  if (len(seq) == 1) {
    return seq->at(0);
  }
  else {
    return Alloc<re::Seq>(seq);
  }
}

syntax_asdl::re_t* Transformer::_Regex(pnode::PNode* p_node) {
  int n;
  List<syntax_asdl::re_t*>* alts = nullptr;
  pnode::PNode* c = nullptr;
  StackRoot _root0(&p_node);
  StackRoot _root1(&alts);
  StackRoot _root2(&c);

  n = p_node->NumChildren();
  alts = Alloc<List<syntax_asdl::re_t*>>();
  for (int i = 0; i < n; i += 2) {
    c = p_node->GetChild(i);
    alts->append(this->_ReAlt(c));
  }
  if (len(alts) == 1) {
    return alts->at(0);
  }
  else {
    return Alloc<re::Alt>(alts);
  }
}

}  // define namespace expr_to_ast

namespace func_proc {  // define

using id_kind_asdl::Id;
using runtime_asdl::cmd_value;
using syntax_asdl::proc_sig;
using syntax_asdl::proc_sig_e;
using syntax_asdl::Param;
using syntax_asdl::ParamGroup;
using syntax_asdl::NamedArg;
using syntax_asdl::Func;
using syntax_asdl::loc;
using syntax_asdl::ArgList;
using syntax_asdl::expr;
using syntax_asdl::expr_e;
using syntax_asdl::expr_t;
using value_asdl::value;
using value_asdl::value_e;
using value_asdl::value_t;
using value_asdl::ProcDefaults;
using value_asdl::LeftName;
using error::e_die;

void _DisallowMutableDefault(value_asdl::value_t* val, syntax_asdl::loc_t* blame_loc) {
  StackRoot _root0(&val);
  StackRoot _root1(&blame_loc);

  if ((val->tag() == value_e::List || val->tag() == value_e::Dict)) {
    throw Alloc<error::TypeErr>(val, str2129, blame_loc);
  }
}

List<value_asdl::value_t*>* _EvalPosDefaults(expr_eval::ExprEvaluator* expr_ev, List<syntax_asdl::Param*>* pos_params) {
  value_asdl::value_t* no_val = nullptr;
  List<value_asdl::value_t*>* pos_defaults = nullptr;
  int i;
  value_asdl::value_t* val = nullptr;
  StackRoot _root0(&expr_ev);
  StackRoot _root1(&pos_params);
  StackRoot _root2(&no_val);
  StackRoot _root3(&pos_defaults);
  StackRoot _root4(&val);

  no_val = nullptr;
  pos_defaults = list_repeat(no_val, len(pos_params));
  i = 0;
  for (ListIter<syntax_asdl::Param*> it(pos_params); !it.Done(); it.Next(), ++i) {
    syntax_asdl::Param* p = it.Value();
    StackRoot _for(&p  );
    if (p->default_val) {
      val = expr_ev->EvalExpr(p->default_val, p->blame_tok);
      _DisallowMutableDefault(val, p->blame_tok);
      pos_defaults->set(i, val);
    }
  }
  return pos_defaults;
}

Dict<BigStr*, value_asdl::value_t*>* _EvalNamedDefaults(expr_eval::ExprEvaluator* expr_ev, List<syntax_asdl::Param*>* named_params) {
  Dict<BigStr*, value_asdl::value_t*>* named_defaults = nullptr;
  int i;
  value_asdl::value_t* val = nullptr;
  StackRoot _root0(&expr_ev);
  StackRoot _root1(&named_params);
  StackRoot _root2(&named_defaults);
  StackRoot _root3(&val);

  named_defaults = Alloc<Dict<BigStr*, value_asdl::value_t*>>();
  i = 0;
  for (ListIter<syntax_asdl::Param*> it(named_params); !it.Done(); it.Next(), ++i) {
    syntax_asdl::Param* p = it.Value();
    StackRoot _for(&p  );
    if (p->default_val) {
      val = expr_ev->EvalExpr(p->default_val, p->blame_tok);
      _DisallowMutableDefault(val, p->blame_tok);
      named_defaults->set(p->name, val);
    }
  }
  return named_defaults;
}

Tuple2<List<value_asdl::value_t*>*, Dict<BigStr*, value_asdl::value_t*>*> EvalFuncDefaults(expr_eval::ExprEvaluator* expr_ev, syntax_asdl::Func* func) {
  List<value_asdl::value_t*>* pos_defaults = nullptr;
  Dict<BigStr*, value_asdl::value_t*>* named_defaults = nullptr;
  StackRoot _root0(&expr_ev);
  StackRoot _root1(&func);
  StackRoot _root2(&pos_defaults);
  StackRoot _root3(&named_defaults);

  if (func->positional) {
    pos_defaults = _EvalPosDefaults(expr_ev, func->positional->params);
  }
  else {
    pos_defaults = nullptr;
  }
  if (func->named) {
    named_defaults = _EvalNamedDefaults(expr_ev, func->named->params);
  }
  else {
    named_defaults = nullptr;
  }
  return Tuple2<List<value_asdl::value_t*>*, Dict<BigStr*, value_asdl::value_t*>*>(pos_defaults, named_defaults);
}

value_asdl::ProcDefaults* EvalProcDefaults(expr_eval::ExprEvaluator* expr_ev, proc_sig::Closed* sig) {
  value_asdl::value_t* no_val = nullptr;
  List<value_asdl::value_t*>* word_defaults = nullptr;
  int i;
  value_asdl::value_t* val = nullptr;
  List<value_asdl::value_t*>* pos_defaults = nullptr;
  Dict<BigStr*, value_asdl::value_t*>* named_defaults = nullptr;
  syntax_asdl::expr_t* exp = nullptr;
  value_asdl::value_t* block_default = nullptr;
  StackRoot _root0(&expr_ev);
  StackRoot _root1(&sig);
  StackRoot _root2(&no_val);
  StackRoot _root3(&word_defaults);
  StackRoot _root4(&val);
  StackRoot _root5(&pos_defaults);
  StackRoot _root6(&named_defaults);
  StackRoot _root7(&exp);
  StackRoot _root8(&block_default);

  no_val = nullptr;
  if (sig->word) {
    word_defaults = list_repeat(no_val, len(sig->word->params));
    i = 0;
    for (ListIter<syntax_asdl::Param*> it(sig->word->params); !it.Done(); it.Next(), ++i) {
      syntax_asdl::Param* p = it.Value();
      StackRoot _for(&p    );
      if (p->default_val) {
        val = expr_ev->EvalExpr(p->default_val, p->blame_tok);
        if (val->tag() != value_e::Str) {
          throw Alloc<error::TypeErr>(val, str2130, p->blame_tok);
        }
        word_defaults->set(i, val);
      }
    }
  }
  else {
    word_defaults = nullptr;
  }
  if (sig->positional) {
    pos_defaults = _EvalPosDefaults(expr_ev, sig->positional->params);
  }
  else {
    pos_defaults = nullptr;
  }
  if (sig->named) {
    named_defaults = _EvalNamedDefaults(expr_ev, sig->named->params);
  }
  else {
    named_defaults = nullptr;
  }
  if (sig->block_param) {
    exp = sig->block_param->default_val;
    if (exp) {
      block_default = expr_ev->EvalExpr(exp, sig->block_param->blame_tok);
      if ((block_default->tag() != value_e::Null && block_default->tag() != value_e::Command)) {
        throw Alloc<error::TypeErr>(block_default, str2131, sig->block_param->blame_tok);
      }
    }
    else {
      block_default = nullptr;
    }
  }
  else {
    block_default = nullptr;
  }
  return Alloc<ProcDefaults>(word_defaults, pos_defaults, named_defaults, block_default);
}

void _EvalPosArgs(expr_eval::ExprEvaluator* expr_ev, List<syntax_asdl::expr_t*>* exprs, List<value_asdl::value_t*>* pos_args) {
  syntax_asdl::expr_t* UP_e = nullptr;
  value_asdl::value_t* val = nullptr;
  StackRoot _root0(&expr_ev);
  StackRoot _root1(&exprs);
  StackRoot _root2(&pos_args);
  StackRoot _root3(&UP_e);
  StackRoot _root4(&val);

  for (ListIter<syntax_asdl::expr_t*> it(exprs); !it.Done(); it.Next()) {
    syntax_asdl::expr_t* e = it.Value();
    StackRoot _for(&e  );
    UP_e = e;
    if (e->tag() == expr_e::Spread) {
      expr::Spread* e = static_cast<expr::Spread*>(UP_e);
      val = expr_ev->_EvalExpr(e->child);
      if (val->tag() != value_e::List) {
        throw Alloc<error::TypeErr>(val, str2132, e->left);
      }
      pos_args->extend(static_cast<value::List*>(val)->items);
    }
    else {
      pos_args->append(expr_ev->_EvalExpr(e));
    }
  }
}

Dict<BigStr*, value_asdl::value_t*>* _EvalNamedArgs(expr_eval::ExprEvaluator* expr_ev, List<syntax_asdl::NamedArg*>* named_exprs) {
  Dict<BigStr*, value_asdl::value_t*>* named_args = nullptr;
  syntax_asdl::expr_t* val_expr = nullptr;
  syntax_asdl::expr_t* UP_val_expr = nullptr;
  value_asdl::value_t* val = nullptr;
  BigStr* name = nullptr;
  StackRoot _root0(&expr_ev);
  StackRoot _root1(&named_exprs);
  StackRoot _root2(&named_args);
  StackRoot _root3(&val_expr);
  StackRoot _root4(&UP_val_expr);
  StackRoot _root5(&val);
  StackRoot _root6(&name);

  named_args = Alloc<Dict<BigStr*, value_asdl::value_t*>>();
  for (ListIter<syntax_asdl::NamedArg*> it(named_exprs); !it.Done(); it.Next()) {
    syntax_asdl::NamedArg* n = it.Value();
    StackRoot _for(&n  );
    val_expr = n->value;
    UP_val_expr = val_expr;
    if (val_expr->tag() == expr_e::Spread) {
      expr::Spread* val_expr = static_cast<expr::Spread*>(UP_val_expr);
      val = expr_ev->_EvalExpr(val_expr->child);
      if (val->tag() != value_e::Dict) {
        throw Alloc<error::TypeErr>(val, str2133, val_expr->left);
      }
      named_args->update(static_cast<value::Dict*>(val)->d);
    }
    else {
      val = expr_ev->EvalExpr(n->value, n->name);
      name = lexer::TokenVal(n->name);
      named_args->set(name, val);
    }
  }
  return named_args;
}

Tuple2<List<value_asdl::value_t*>*, Dict<BigStr*, value_asdl::value_t*>*> _EvalArgList(expr_eval::ExprEvaluator* expr_ev, syntax_asdl::ArgList* args, value_asdl::value_t* me) {
  List<value_asdl::value_t*>* pos_args = nullptr;
  Dict<BigStr*, value_asdl::value_t*>* named_args = nullptr;
  StackRoot _root0(&expr_ev);
  StackRoot _root1(&args);
  StackRoot _root2(&me);
  StackRoot _root3(&pos_args);
  StackRoot _root4(&named_args);

  pos_args = Alloc<List<value_asdl::value_t*>>();
  if (me) {
    pos_args->append(me);
  }
  _EvalPosArgs(expr_ev, args->pos_args, pos_args);
  named_args = nullptr;
  if (args->named_args != nullptr) {
    named_args = _EvalNamedArgs(expr_ev, args->named_args);
  }
  return Tuple2<List<value_asdl::value_t*>*, Dict<BigStr*, value_asdl::value_t*>*>(pos_args, named_args);
}

void EvalTypedArgsToProc(expr_eval::ExprEvaluator* expr_ev, state::MutableOpts* mutable_opts, command::Simple* node, cmd_value::Argv* cmd_val) {
  syntax_asdl::ArgList* ty = nullptr;
  List<syntax_asdl::NamedArg*>* n1 = nullptr;
  Dict<BigStr*, value_asdl::value_t*>* named_args = nullptr;
  BigStr* name = nullptr;
  StackRoot _root0(&expr_ev);
  StackRoot _root1(&mutable_opts);
  StackRoot _root2(&node);
  StackRoot _root3(&cmd_val);
  StackRoot _root4(&ty);
  StackRoot _root5(&n1);
  StackRoot _root6(&named_args);
  StackRoot _root7(&name);

  cmd_val->typed_args = node->typed_args;
  cmd_val->pos_args = Alloc<List<value_asdl::value_t*>>();
  ty = node->typed_args;
  if (ty) {
    if (ty->left->id == Id::Op_LBracket) {
      for (ListIter<syntax_asdl::expr_t*> it(ty->pos_args); !it.Done(); it.Next()) {
        syntax_asdl::expr_t* exp = it.Value();
        StackRoot _for(&exp      );
        cmd_val->pos_args->append(Alloc<value::Expr>(exp));
      }
      n1 = ty->named_args;
      if (n1 != nullptr) {
        named_args = Alloc<Dict<BigStr*, value_asdl::value_t*>>();
        for (ListIter<syntax_asdl::NamedArg*> it(n1); !it.Done(); it.Next()) {
          syntax_asdl::NamedArg* named_arg = it.Value();
          StackRoot _for(&named_arg        );
          name = lexer::TokenVal(named_arg->name);
          cmd_val->named_args->set(name, Alloc<value::Expr>(named_arg->value));
        }
      }
    }
    else {
      {  // with
        state::ctx_YshExpr ctx{mutable_opts};

        _EvalPosArgs(expr_ev, ty->pos_args, cmd_val->pos_args);
        if (ty->named_args != nullptr) {
          cmd_val->named_args = _EvalNamedArgs(expr_ev, ty->named_args);
        }
      }
    }
    if ((ty->block_expr and node->block)) {
      e_die(str2134, node->block->brace_group->left);
    }
    if (ty->block_expr) {
      cmd_val->block_arg = expr_ev->EvalExpr(ty->block_expr, ty->left);
    }
  }
  if (node->block) {
    cmd_val->block_arg = Alloc<value::Block>(node->block);
    if (!cmd_val->typed_args) {
      cmd_val->typed_args = ArgList::CreateNull();
      cmd_val->typed_args->left = node->block->brace_group->left;
      cmd_val->typed_args->right = node->block->brace_group->right;
    }
  }
}

void _BindWords(BigStr* proc_name, syntax_asdl::ParamGroup* group, List<value_asdl::value_t*>* defaults, cmd_value::Argv* cmd_val, state::Mem* mem, syntax_asdl::loc_t* blame_loc) {
  List<BigStr*>* argv = nullptr;
  int num_args;
  int i;
  value_asdl::value_t* val = nullptr;
  int num_params;
  syntax_asdl::RestParam* rest = nullptr;
  value_asdl::LeftName* lval = nullptr;
  List<value_asdl::value_t*>* items = nullptr;
  value::List* rest_val = nullptr;
  syntax_asdl::loc_t* extra_loc = nullptr;
  StackRoot _root0(&proc_name);
  StackRoot _root1(&group);
  StackRoot _root2(&defaults);
  StackRoot _root3(&cmd_val);
  StackRoot _root4(&mem);
  StackRoot _root5(&blame_loc);
  StackRoot _root6(&argv);
  StackRoot _root7(&val);
  StackRoot _root8(&rest);
  StackRoot _root9(&lval);
  StackRoot _root10(&items);
  StackRoot _root11(&rest_val);
  StackRoot _root12(&extra_loc);

  argv = cmd_val->argv->slice(1);
  num_args = len(argv);
  i = 0;
  for (ListIter<syntax_asdl::Param*> it(group->params); !it.Done(); it.Next(), ++i) {
    syntax_asdl::Param* p = it.Value();
    StackRoot _for(&p  );
    if (i < num_args) {
      val = Alloc<value::Str>(argv->at(i));
    }
    else {
      val = defaults->at(i);
      if (val == nullptr) {
        throw Alloc<error::Expr>(StrFormat("proc %r wasn't passed word param %r", proc_name, p->name), blame_loc);
      }
    }
    mem->SetLocalName(Alloc<LeftName>(p->name, p->blame_tok), val);
  }
  num_params = len(group->params);
  rest = group->rest_of;
  if (rest) {
    lval = Alloc<LeftName>(rest->name, rest->blame_tok);
    items = Alloc<List<value_asdl::value_t*>>();
    for (ListIter<BigStr*> it(argv->slice(num_params)); !it.Done(); it.Next()) {
      BigStr* s = it.Value();
      items->append(Alloc<value::Str>(s));
    }
    rest_val = Alloc<value::List>(items);
    mem->SetLocalName(lval, rest_val);
  }
  else {
    if (num_args > num_params) {
      if (len(cmd_val->arg_locs)) {
        extra_loc = cmd_val->arg_locs->at((num_params + 1));
      }
      else {
        extra_loc = loc::Missing;
      }
      throw Alloc<error::Expr>(StrFormat("proc %r takes %d words, but got %d", proc_name, num_params, num_args), extra_loc);
    }
  }
}

void _BindTyped(BigStr* code_name, syntax_asdl::ParamGroup* group, List<value_asdl::value_t*>* defaults, List<value_asdl::value_t*>* pos_args, state::Mem* mem, syntax_asdl::loc_t* blame_loc) {
  int num_args;
  int num_params;
  int i;
  value_asdl::value_t* val = nullptr;
  syntax_asdl::RestParam* rest = nullptr;
  value_asdl::LeftName* lval = nullptr;
  value::List* rest_val = nullptr;
  StackRoot _root0(&code_name);
  StackRoot _root1(&group);
  StackRoot _root2(&defaults);
  StackRoot _root3(&pos_args);
  StackRoot _root4(&mem);
  StackRoot _root5(&blame_loc);
  StackRoot _root6(&val);
  StackRoot _root7(&rest);
  StackRoot _root8(&lval);
  StackRoot _root9(&rest_val);

  if (pos_args == nullptr) {
    pos_args = Alloc<List<value_asdl::value_t*>>();
  }
  num_args = len(pos_args);
  num_params = 0;
  i = 0;
  if (group) {
    for (ListIter<syntax_asdl::Param*> it(group->params); !it.Done(); it.Next()) {
      syntax_asdl::Param* p = it.Value();
      StackRoot _for(&p    );
      if (i < num_args) {
        val = pos_args->at(i);
      }
      else {
        val = defaults->at(i);
        if (val == nullptr) {
          throw Alloc<error::Expr>(StrFormat("%r wasn't passed typed param %r", code_name, p->name), blame_loc);
        }
      }
      mem->SetLocalName(Alloc<LeftName>(p->name, p->blame_tok), val);
      i += 1;
    }
    num_params += len(group->params);
  }
  if (group) {
    rest = group->rest_of;
    if (rest) {
      lval = Alloc<LeftName>(rest->name, rest->blame_tok);
      rest_val = Alloc<value::List>(pos_args->slice(num_params));
      mem->SetLocalName(lval, rest_val);
    }
    else {
      if (num_args > num_params) {
        throw Alloc<error::Expr>(StrFormat("%r takes %d typed args, but got %d", code_name, num_params, num_args), blame_loc);
      }
    }
  }
}

void _BindNamed(BigStr* code_name, syntax_asdl::ParamGroup* group, Dict<BigStr*, value_asdl::value_t*>* defaults, Dict<BigStr*, value_asdl::value_t*>* named_args, state::Mem* mem, syntax_asdl::loc_t* blame_loc) {
  value_asdl::value_t* val = nullptr;
  syntax_asdl::RestParam* rest = nullptr;
  value_asdl::LeftName* lval = nullptr;
  int num_args;
  int num_params;
  StackRoot _root0(&code_name);
  StackRoot _root1(&group);
  StackRoot _root2(&defaults);
  StackRoot _root3(&named_args);
  StackRoot _root4(&mem);
  StackRoot _root5(&blame_loc);
  StackRoot _root6(&val);
  StackRoot _root7(&rest);
  StackRoot _root8(&lval);

  if (named_args == nullptr) {
    named_args = Alloc<Dict<BigStr*, value_asdl::value_t*>>();
  }
  for (ListIter<syntax_asdl::Param*> it(group->params); !it.Done(); it.Next()) {
    syntax_asdl::Param* p = it.Value();
    StackRoot _for(&p  );
    val = named_args->get(p->name);
    if (val == nullptr) {
      val = defaults->get(p->name);
    }
    if (val == nullptr) {
      throw Alloc<error::Expr>(StrFormat("%r wasn't passed named param %r", code_name, p->name), blame_loc);
    }
    mem->SetLocalName(Alloc<LeftName>(p->name, p->blame_tok), val);
    mylib::dict_erase(named_args, p->name);
  }
  rest = group->rest_of;
  if (rest) {
    lval = Alloc<LeftName>(rest->name, rest->blame_tok);
    mem->SetLocalName(lval, Alloc<value::Dict>(named_args));
  }
  else {
    num_args = len(named_args);
    num_params = len(group->params);
    if (num_args > num_params) {
      throw Alloc<error::Expr>(StrFormat("%r takes %d named args, but got %d", code_name, num_params, num_args), blame_loc);
    }
  }
}

void _BindFuncArgs(value::Func* func, typed_args::Reader* rd, state::Mem* mem) {
  syntax_asdl::Func* node = nullptr;
  syntax_asdl::loc_t* blame_loc = nullptr;
  int num_pos;
  syntax_asdl::Token* semi = nullptr;
  int num_named;
  StackRoot _root0(&func);
  StackRoot _root1(&rd);
  StackRoot _root2(&mem);
  StackRoot _root3(&node);
  StackRoot _root4(&blame_loc);
  StackRoot _root5(&semi);

  node = func->parsed;
  blame_loc = rd->LeftParenToken();
  if (node->positional) {
    _BindTyped(func->name, node->positional, func->pos_defaults, rd->pos_args, mem, blame_loc);
  }
  else {
    if (rd->pos_args != nullptr) {
      num_pos = len(rd->pos_args);
      if (num_pos != 0) {
        throw Alloc<error::Expr>(StrFormat("Func %r takes no positional args, but got %d", func->name, num_pos), blame_loc);
      }
    }
  }
  semi = rd->arg_list->semi_tok;
  if (semi != nullptr) {
    blame_loc = semi;
  }
  if (node->named) {
    _BindNamed(func->name, node->named, func->named_defaults, rd->named_args, mem, blame_loc);
  }
  else {
    if (rd->named_args != nullptr) {
      num_named = len(rd->named_args);
      if (num_named != 0) {
        throw Alloc<error::Expr>(StrFormat("Func %r takes no named args, but got %d", func->name, num_named), blame_loc);
      }
    }
  }
}

void BindProcArgs(value::Proc* proc, cmd_value::Argv* cmd_val, state::Mem* mem) {
  syntax_asdl::proc_sig_t* UP_sig = nullptr;
  syntax_asdl::loc_t* blame_loc = nullptr;
  int num_word;
  int num_pos;
  syntax_asdl::Token* semi = nullptr;
  int num_named;
  syntax_asdl::Param* block_param = nullptr;
  value_asdl::value_t* block_arg = nullptr;
  StackRoot _root0(&proc);
  StackRoot _root1(&cmd_val);
  StackRoot _root2(&mem);
  StackRoot _root3(&UP_sig);
  StackRoot _root4(&blame_loc);
  StackRoot _root5(&semi);
  StackRoot _root6(&block_param);
  StackRoot _root7(&block_arg);

  UP_sig = proc->sig;
  if (UP_sig->tag() != proc_sig_e::Closed) {
    return ;
  }
  proc_sig::Closed* sig = static_cast<proc_sig::Closed*>(UP_sig);
  blame_loc = loc::Missing;
  if (len(cmd_val->arg_locs) > 0) {
    blame_loc = cmd_val->arg_locs->at(0);
  }
  if (sig->word) {
    _BindWords(proc->name, sig->word, proc->defaults->for_word, cmd_val, mem, blame_loc);
  }
  else {
    num_word = len(cmd_val->argv);
    if (num_word != 1) {
      throw Alloc<error::Expr>(StrFormat("Proc %r takes no word args, but got %d", proc->name, (num_word - 1)), blame_loc);
    }
  }
  if (cmd_val->typed_args) {
    blame_loc = cmd_val->typed_args->left;
  }
  if (sig->positional) {
    _BindTyped(proc->name, sig->positional, proc->defaults->for_typed, cmd_val->pos_args, mem, blame_loc);
  }
  else {
    if (cmd_val->pos_args != nullptr) {
      num_pos = len(cmd_val->pos_args);
      if (num_pos != 0) {
        throw Alloc<error::Expr>(StrFormat("Proc %r takes no typed args, but got %d", proc->name, num_pos), blame_loc);
      }
    }
  }
  if (cmd_val->typed_args) {
    semi = cmd_val->typed_args->semi_tok;
    if (semi != nullptr) {
      blame_loc = semi;
    }
  }
  if (sig->named) {
    _BindNamed(proc->name, sig->named, proc->defaults->for_named, cmd_val->named_args, mem, blame_loc);
  }
  else {
    if (cmd_val->named_args != nullptr) {
      num_named = len(cmd_val->named_args);
      if (num_named != 0) {
        throw Alloc<error::Expr>(StrFormat("Proc %r takes no named args, but got %d", proc->name, num_named), blame_loc);
      }
    }
  }
  if (cmd_val->typed_args) {
    semi = cmd_val->typed_args->semi_tok2;
    if (semi != nullptr) {
      blame_loc = semi;
    }
  }
  block_param = sig->block_param;
  block_arg = cmd_val->block_arg;
  if (block_param) {
    if (block_arg == nullptr) {
      block_arg = proc->defaults->for_block;
    }
    if (block_arg == nullptr) {
      throw Alloc<error::Expr>(StrFormat("%r wasn't passed block param %r", proc->name, block_param->name), blame_loc);
    }
    mem->SetLocalName(Alloc<LeftName>(block_param->name, block_param->blame_tok), block_arg);
  }
  else {
    if (block_arg != nullptr) {
      throw Alloc<error::Expr>(StrFormat("Proc %r doesn't accept a block argument", proc->name), blame_loc);
    }
  }
}

value_asdl::value_t* CallUserFunc(value::Func* func, typed_args::Reader* rd, state::Mem* mem, cmd_eval::CommandEvaluator* cmd_ev) {
  StackRoot _root0(&func);
  StackRoot _root1(&rd);
  StackRoot _root2(&mem);
  StackRoot _root3(&cmd_ev);

  {  // with
    state::ctx_FuncCall ctx{mem, func};

    _BindFuncArgs(func, rd, mem);
    try {
      cmd_ev->_Execute(func->parsed->body);
      return value::Null;
    }
    catch (vm::ValueControlFlow* e) {
      return e->value;
    }
    catch (vm::IntControlFlow* e) {
      assert(0);  // AssertionError
    }
  }
  assert(0);  // AssertionError
}

}  // define namespace func_proc

namespace regex_translate {  // define

using syntax_asdl::PosixClass;
using syntax_asdl::PerlClass;
using syntax_asdl::CharCode;
using syntax_asdl::CharRange;
using syntax_asdl::char_class_term_e;
using syntax_asdl::char_class_term_t;
using syntax_asdl::re;
using syntax_asdl::re_e;
using syntax_asdl::re_repeat;
using syntax_asdl::re_repeat_e;
using syntax_asdl::EggexFlag;
using syntax_asdl::Token;
using id_kind_asdl::Id;
using value_asdl::value;
using error::e_die;
using error::p_die;
GLOBAL_DICT(PERL_CLASS, BigStr*, BigStr*, 3, {str2150 COMMA str2152 COMMA str2154}, {str2151 COMMA str2153 COMMA str2155});
int CH_RBRACKET = 93;
int CH_BACKSLASH = 92;
int CH_CARET = 94;
int CH_HYPHEN = 45;
int FLAG_RBRACKET = 1;
int FLAG_BACKSLASH = 2;
int FLAG_CARET = 4;
int FLAG_HYPHEN = 8;

void _CharCodeToEre(syntax_asdl::CharCode* term, List<BigStr*>* parts, List<int>* special_char_flags) {
  int char_int;
  int mask;
  StackRoot _root0(&term);
  StackRoot _root1(&parts);
  StackRoot _root2(&special_char_flags);

  char_int = term->i;
  if ((char_int >= 128 and term->u_braced)) {
    e_die(StrFormat("ERE can't express char code %d", char_int), term->blame_tok);
  }
  mask = special_char_flags->at(0);
  if (char_int == CH_HYPHEN) {
    mask |= FLAG_HYPHEN;
  }
  else {
    if (char_int == CH_CARET) {
      mask |= FLAG_CARET;
    }
    else {
      if (char_int == CH_RBRACKET) {
        mask |= FLAG_RBRACKET;
      }
      else {
        if (char_int == CH_BACKSLASH) {
          mask |= FLAG_BACKSLASH;
        }
        else {
          parts->append(chr(char_int));
        }
      }
    }
  }
  special_char_flags->set(0, mask);
}

void _CharClassTermToEre(syntax_asdl::char_class_term_t* term, List<BigStr*>* parts, List<int>* special_char_flags) {
  syntax_asdl::char_class_term_t* UP_term = nullptr;
  List<int>* range_no_special = nullptr;
  BigStr* n = nullptr;
  BigStr* chars = nullptr;
  BigStr* pat = nullptr;
  StackRoot _root0(&term);
  StackRoot _root1(&parts);
  StackRoot _root2(&special_char_flags);
  StackRoot _root3(&UP_term);
  StackRoot _root4(&range_no_special);
  StackRoot _root5(&n);
  StackRoot _root6(&chars);
  StackRoot _root7(&pat);

  UP_term = term;
  switch (term->tag()) {
    case char_class_term_e::CharRange: {
      CharRange* term = static_cast<CharRange*>(UP_term);
      range_no_special = NewList<int>(std::initializer_list<int>{0});
      _CharCodeToEre(term->start, parts, range_no_special);
      if (range_no_special->at(0) != 0) {
        e_die(StrFormat("Can't use char %d as start of range in ERE syntax", term->start->i), term->start->blame_tok);
      }
      parts->append(str2158);
      _CharCodeToEre(term->end, parts, range_no_special);
      if (range_no_special->at(0) != 0) {
        e_die(StrFormat("Can't use char %d as end of range in ERE syntax", term->end->i), term->end->blame_tok);
      }
    }
      break;
    case char_class_term_e::CharCode: {
      CharCode* term = static_cast<CharCode*>(UP_term);
      _CharCodeToEre(term, parts, special_char_flags);
    }
      break;
    case char_class_term_e::PerlClass: {
      PerlClass* term = static_cast<PerlClass*>(UP_term);
      n = term->name;
      chars = PERL_CLASS->at(term->name);
      if (term->negated) {
        e_die(str2160, term->negated);
      }
      else {
        pat = StrFormat("%s", chars);
      }
      parts->append(pat);
    }
      break;
    case char_class_term_e::PosixClass: {
      PosixClass* term = static_cast<PosixClass*>(UP_term);
      n = term->name;
      if (term->negated) {
        e_die(str2162, term->negated);
      }
      else {
        pat = StrFormat("[:%s:]", n);
      }
      parts->append(pat);
    }
      break;
    default: {
      assert(0);  // AssertionError
    }
  }
}

void _AsPosixEre(syntax_asdl::re_t* node, List<BigStr*>* parts, List<BigStr*>* capture_names) {
  syntax_asdl::re_t* UP_node = nullptr;
  int tag;
  int i;
  re::LiteralChars* child = nullptr;
  syntax_asdl::re_repeat_t* op = nullptr;
  int op_tag;
  syntax_asdl::re_repeat_t* UP_op = nullptr;
  BigStr* capture_str = nullptr;
  BigStr* n = nullptr;
  BigStr* chars = nullptr;
  BigStr* pat = nullptr;
  List<int>* special_char_flags = nullptr;
  List<BigStr*>* non_special_parts = nullptr;
  StackRoot _root0(&node);
  StackRoot _root1(&parts);
  StackRoot _root2(&capture_names);
  StackRoot _root3(&UP_node);
  StackRoot _root4(&child);
  StackRoot _root5(&op);
  StackRoot _root6(&UP_op);
  StackRoot _root7(&capture_str);
  StackRoot _root8(&n);
  StackRoot _root9(&chars);
  StackRoot _root10(&pat);
  StackRoot _root11(&special_char_flags);
  StackRoot _root12(&non_special_parts);

  UP_node = node;
  tag = node->tag();
  if (tag == re_e::Primitive) {
    re::Primitive* node = static_cast<re::Primitive*>(UP_node);
    if (node->id == Id::Eggex_Dot) {
      parts->append(str2164);
    }
    else {
      if (node->id == Id::Eggex_Start) {
        parts->append(str2165);
      }
      else {
        if (node->id == Id::Eggex_End) {
          parts->append(str2166);
        }
        else {
          assert(0);  // AssertionError
        }
      }
    }
    return ;
  }
  if (tag == re_e::LiteralChars) {
    re::LiteralChars* node = static_cast<re::LiteralChars*>(UP_node);
    parts->append(glob_::ExtendedRegexEscape(node->s));
    return ;
  }
  if (tag == re_e::Seq) {
    re::Seq* node = static_cast<re::Seq*>(UP_node);
    for (ListIter<syntax_asdl::re_t*> it(node->children); !it.Done(); it.Next()) {
      syntax_asdl::re_t* c = it.Value();
      StackRoot _for(&c    );
      _AsPosixEre(c, parts, capture_names);
    }
    return ;
  }
  if (tag == re_e::Alt) {
    re::Alt* node = static_cast<re::Alt*>(UP_node);
    i = 0;
    for (ListIter<syntax_asdl::re_t*> it(node->children); !it.Done(); it.Next(), ++i) {
      syntax_asdl::re_t* c = it.Value();
      StackRoot _for(&c    );
      if (i != 0) {
        parts->append(str2167);
      }
      _AsPosixEre(c, parts, capture_names);
    }
    return ;
  }
  if (tag == re_e::Repeat) {
    re::Repeat* node = static_cast<re::Repeat*>(UP_node);
    if (node->child->tag() == re_e::LiteralChars) {
      child = static_cast<re::LiteralChars*>(node->child);
      if (len(child->s) > 1) {
        e_die(str2168, child->blame_tok);
      }
    }
    _AsPosixEre(node->child, parts, capture_names);
    op = node->op;
    op_tag = op->tag();
    UP_op = op;
    if (op_tag == re_repeat_e::Op) {
      Token* op = static_cast<Token*>(UP_op);
      switch (op->id) {
        case Id::Arith_Plus: {
          parts->append(str2169);
        }
          break;
        case Id::Arith_Star: {
          parts->append(str2170);
        }
          break;
        case Id::Arith_QMark: {
          parts->append(str2171);
        }
          break;
        case Id::Expr_DecInt: {
          parts->append(StrFormat("{%s}", lexer::LazyStr(op)));
        }
          break;
        default: {
          assert(0);  // AssertionError
        }
      }
      return ;
    }
    if (op_tag == re_repeat_e::Range) {
      re_repeat::Range* op = static_cast<re_repeat::Range*>(UP_op);
      parts->append(StrFormat("{%s,%s}", op->lower, op->upper));
      return ;
    }
    FAIL(kNotImplemented);  // Python NotImplementedError
  }
  if (tag == re_e::Group) {
    re::Group* node = static_cast<re::Group*>(UP_node);
    capture_names->append(nullptr);
    parts->append(str2174);
    _AsPosixEre(node->child, parts, capture_names);
    parts->append(str2175);
    return ;
  }
  if (tag == re_e::Capture) {
    re::Capture* node = static_cast<re::Capture*>(UP_node);
    capture_str = node->name ? lexer::TokenVal(node->name) : nullptr;
    capture_names->append(capture_str);
    parts->append(str2176);
    _AsPosixEre(node->child, parts, capture_names);
    parts->append(str2177);
    return ;
  }
  if (tag == re_e::PerlClass) {
    PerlClass* node = static_cast<PerlClass*>(UP_node);
    n = node->name;
    chars = PERL_CLASS->at(node->name);
    if (node->negated) {
      pat = StrFormat("[^%s]", chars);
    }
    else {
      pat = StrFormat("[%s]", chars);
    }
    parts->append(pat);
    return ;
  }
  if (tag == re_e::PosixClass) {
    PosixClass* node = static_cast<PosixClass*>(UP_node);
    n = node->name;
    if (node->negated) {
      pat = StrFormat("[^[:%s:]]", n);
    }
    else {
      pat = StrFormat("[[:%s:]]", n);
    }
    parts->append(pat);
    return ;
  }
  if (tag == re_e::CharClass) {
    re::CharClass* node = static_cast<re::CharClass*>(UP_node);
    special_char_flags = NewList<int>(std::initializer_list<int>{0});
    non_special_parts = Alloc<List<BigStr*>>();
    for (ListIter<syntax_asdl::char_class_term_t*> it(node->terms); !it.Done(); it.Next()) {
      syntax_asdl::char_class_term_t* term = it.Value();
      StackRoot _for(&term    );
      _CharClassTermToEre(term, non_special_parts, special_char_flags);
    }
    parts->append(str2182);
    if (node->negated) {
      parts->append(str2183);
    }
    if ((special_char_flags->at(0) & FLAG_RBRACKET)) {
      parts->append(str2184);
    }
    parts->extend(non_special_parts);
    if ((special_char_flags->at(0) & FLAG_BACKSLASH)) {
      parts->append(str2185);
    }
    if ((special_char_flags->at(0) & FLAG_CARET)) {
      parts->append(str2186);
    }
    if ((special_char_flags->at(0) & FLAG_HYPHEN)) {
      parts->append(str2187);
    }
    parts->append(str2188);
    return ;
  }
  FAIL(kNotImplemented);  // Python NotImplementedError
}

BigStr* AsPosixEre(value::Eggex* eggex) {
  List<BigStr*>* parts = nullptr;
  StackRoot _root0(&eggex);
  StackRoot _root1(&parts);

  if (eggex->as_ere != nullptr) {
    return eggex->as_ere;
  }
  parts = Alloc<List<BigStr*>>();
  _AsPosixEre(eggex->spliced, parts, eggex->capture_names);
  eggex->as_ere = str2189->join(parts);
  return eggex->as_ere;
}

BigStr* CanonicalFlags(List<syntax_asdl::EggexFlag*>* flags) {
  List<BigStr*>* letters = nullptr;
  BigStr* flag_name = nullptr;
  StackRoot _root0(&flags);
  StackRoot _root1(&letters);
  StackRoot _root2(&flag_name);

  letters = Alloc<List<BigStr*>>();
  for (ListIter<syntax_asdl::EggexFlag*> it(flags); !it.Done(); it.Next()) {
    syntax_asdl::EggexFlag* flag = it.Value();
    StackRoot _for(&flag  );
    if (flag->negated) {
      p_die(str2190, flag->flag);
    }
    flag_name = lexer::TokenVal(flag->flag);
    if ((str_equals(flag_name, str2191) || str_equals(flag_name, str2192))) {
      letters->append(str2193);
    }
    else {
      if (str_equals(flag_name, str2194)) {
        letters->append(str2195);
      }
      else {
        p_die(StrFormat("Invalid regex flag %r", flag_name), flag->flag);
      }
    }
  }
  letters->sort();
  return str2197->join(letters);
}

int LibcFlags(BigStr* canonical_flags) {
  int libc_flags;
  StackRoot _root0(&canonical_flags);

  if (canonical_flags == nullptr) {
    return 0;
  }
  libc_flags = 0;
  for (StrIter it(canonical_flags); !it.Done(); it.Next()) {
    BigStr* ch = it.Value();
    StackRoot _for(&ch  );
    if (str_equals(ch, str2198)) {
      libc_flags |= REG_ICASE;
    }
    else {
      if (str_equals(ch, str2199)) {
        libc_flags |= REG_NEWLINE;
      }
      else {
        assert(0);  // AssertionError
      }
    }
  }
  return libc_flags;
}

}  // define namespace regex_translate

namespace val_ops {  // define

using syntax_asdl::loc;
using syntax_asdl::loc_t;
using syntax_asdl::command_t;
using value_asdl::value;
using value_asdl::value_e;
using value_asdl::value_t;
using value_asdl::eggex_ops;
using value_asdl::eggex_ops_t;
using value_asdl::regex_match;
using value_asdl::RegexMatch;
using error::e_die;

int ToInt(value_asdl::value_t* val, BigStr* msg, syntax_asdl::loc_t* blame_loc) {
  value_asdl::value_t* UP_val = nullptr;
  StackRoot _root0(&val);
  StackRoot _root1(&msg);
  StackRoot _root2(&blame_loc);
  StackRoot _root3(&UP_val);

  UP_val = val;
  if (val->tag() == value_e::Int) {
    value::Int* val = static_cast<value::Int*>(UP_val);
    return mops::BigTruncate(val->i);
  }
  throw Alloc<error::TypeErr>(val, msg, blame_loc);
}

double ToFloat(value_asdl::value_t* val, BigStr* msg, syntax_asdl::loc_t* blame_loc) {
  value_asdl::value_t* UP_val = nullptr;
  StackRoot _root0(&val);
  StackRoot _root1(&msg);
  StackRoot _root2(&blame_loc);
  StackRoot _root3(&UP_val);

  UP_val = val;
  if (val->tag() == value_e::Float) {
    value::Float* val = static_cast<value::Float*>(UP_val);
    return val->f;
  }
  throw Alloc<error::TypeErr>(val, msg, blame_loc);
}

BigStr* ToStr(value_asdl::value_t* val, BigStr* msg, syntax_asdl::loc_t* blame_loc) {
  value_asdl::value_t* UP_val = nullptr;
  StackRoot _root0(&val);
  StackRoot _root1(&msg);
  StackRoot _root2(&blame_loc);
  StackRoot _root3(&UP_val);

  UP_val = val;
  if (val->tag() == value_e::Str) {
    value::Str* val = static_cast<value::Str*>(UP_val);
    return val->s;
  }
  throw Alloc<error::TypeErr>(val, msg, blame_loc);
}

List<value_asdl::value_t*>* ToList(value_asdl::value_t* val, BigStr* msg, syntax_asdl::loc_t* blame_loc) {
  value_asdl::value_t* UP_val = nullptr;
  StackRoot _root0(&val);
  StackRoot _root1(&msg);
  StackRoot _root2(&blame_loc);
  StackRoot _root3(&UP_val);

  UP_val = val;
  if (val->tag() == value_e::List) {
    value::List* val = static_cast<value::List*>(UP_val);
    return val->items;
  }
  throw Alloc<error::TypeErr>(val, msg, blame_loc);
}

Dict<BigStr*, value_asdl::value_t*>* ToDict(value_asdl::value_t* val, BigStr* msg, syntax_asdl::loc_t* blame_loc) {
  value_asdl::value_t* UP_val = nullptr;
  StackRoot _root0(&val);
  StackRoot _root1(&msg);
  StackRoot _root2(&blame_loc);
  StackRoot _root3(&UP_val);

  UP_val = val;
  if (val->tag() == value_e::Dict) {
    value::Dict* val = static_cast<value::Dict*>(UP_val);
    return val->d;
  }
  throw Alloc<error::TypeErr>(val, msg, blame_loc);
}

syntax_asdl::command_t* ToCommand(value_asdl::value_t* val, BigStr* msg, syntax_asdl::loc_t* blame_loc) {
  value_asdl::value_t* UP_val = nullptr;
  StackRoot _root0(&val);
  StackRoot _root1(&msg);
  StackRoot _root2(&blame_loc);
  StackRoot _root3(&UP_val);

  UP_val = val;
  if (val->tag() == value_e::Command) {
    value::Command* val = static_cast<value::Command*>(UP_val);
    return val->c;
  }
  throw Alloc<error::TypeErr>(val, msg, blame_loc);
}

BigStr* Stringify(value_asdl::value_t* val, syntax_asdl::loc_t* blame_loc, BigStr* prefix) {
  value_asdl::value_t* UP_val = nullptr;
  BigStr* s = nullptr;
  StackRoot _root0(&val);
  StackRoot _root1(&blame_loc);
  StackRoot _root2(&prefix);
  StackRoot _root3(&UP_val);
  StackRoot _root4(&s);

  if (blame_loc == nullptr) {
    blame_loc = loc::Missing;
  }
  UP_val = val;
  switch (val->tag()) {
    case value_e::Str: {
      value::Str* val = static_cast<value::Str*>(UP_val);
      return val->s;
    }
      break;
    case value_e::Null: {
      s = str2201;
    }
      break;
    case value_e::Bool: {
      value::Bool* val = static_cast<value::Bool*>(UP_val);
      s = val->b ? str2202 : str2203;
    }
      break;
    case value_e::Int: {
      value::Int* val = static_cast<value::Int*>(UP_val);
      s = mops::ToStr(val->i);
    }
      break;
    case value_e::Float: {
      value::Float* val = static_cast<value::Float*>(UP_val);
      s = str(val->f);
    }
      break;
    case value_e::Eggex: {
      value::Eggex* val = static_cast<value::Eggex*>(UP_val);
      s = regex_translate::AsPosixEre(val);
    }
      break;
    case value_e::List: {
      throw Alloc<error::TypeErrVerbose>(StrFormat("%sgot a List, which can't be stringified. Perhaps use @ instead of $, or use join()", prefix), blame_loc);
    }
      break;
    default: {
      throw Alloc<error::TypeErr>(val, StrFormat("%sexpected Null, Bool, Int, Float, Eggex", prefix), blame_loc);
    }
  }
  return s;
}

List<BigStr*>* ToShellArray(value_asdl::value_t* val, syntax_asdl::loc_t* blame_loc, BigStr* prefix) {
  value_asdl::value_t* UP_val = nullptr;
  List<BigStr*>* strs = nullptr;
  StackRoot _root0(&val);
  StackRoot _root1(&blame_loc);
  StackRoot _root2(&prefix);
  StackRoot _root3(&UP_val);
  StackRoot _root4(&strs);

  UP_val = val;
  switch (val->tag()) {
    case value_e::List: {
      value::List* val = static_cast<value::List*>(UP_val);
      strs = Alloc<List<BigStr*>>();
      for (ListIter<value_asdl::value_t*> it(val->items); !it.Done(); it.Next()) {
        value_asdl::value_t* item = it.Value();
        StackRoot _for(&item      );
        strs->append(Stringify(item, blame_loc, prefix));
      }
    }
      break;
    case value_e::BashArray: {
      value::BashArray* val = static_cast<value::BashArray*>(UP_val);
      strs = val->strs;
    }
      break;
    default: {
      throw Alloc<error::TypeErr>(val, StrFormat("%sexpected List", prefix), blame_loc);
    }
  }
  return strs;
}

Iterator::Iterator() {
  this->i = 0;
}

int Iterator::Index() {
  return this->i;
}

void Iterator::Next() {
  this->i += 1;
}

value_asdl::value_t* Iterator::FirstValue() {
  FAIL(kNotImplemented);  // Python NotImplementedError
}

value_asdl::value_t* Iterator::SecondValue() {
  assert(0);  // AssertionError
}

StdinIterator::StdinIterator(syntax_asdl::loc_t* blame_loc) : ::val_ops::Iterator() {
  this->blame_loc = blame_loc;
  this->f = mylib::Stdin();
}

value_asdl::value_t* StdinIterator::FirstValue() {
  BigStr* line = nullptr;
  StackRoot _root0(&line);

  try {
    line = this->f->readline();
  }
  catch (IOError_OSError* e) {
    if (e->errno_ == EINTR) {
      return value::Interrupted;
    }
    else {
      e_die(StrFormat("I/O error in for <> loop: %s", posix::strerror(e->errno_)), this->blame_loc);
    }
  }
  if (len(line) == 0) {
    return nullptr;
  }
  else {
    if (line->endswith(str2210)) {
      line = line->slice(0, -1);
    }
  }
  return Alloc<value::Str>(line);
}

ArrayIter::ArrayIter(List<BigStr*>* strs) : ::val_ops::Iterator() {
  this->strs = strs;
  this->n = len(strs);
}

value_asdl::value_t* ArrayIter::FirstValue() {
  if (this->i == this->n) {
    return nullptr;
  }
  return Alloc<value::Str>(this->strs->at(this->i));
}

RangeIterator::RangeIterator(value::Range* val) : ::val_ops::Iterator() {
  this->val = val;
}

value_asdl::value_t* RangeIterator::FirstValue() {
  if ((this->val->lower + this->i) >= this->val->upper) {
    return nullptr;
  }
  return Alloc<value::Int>(mops::IntWiden((this->val->lower + this->i)));
}

ListIterator::ListIterator(value::List* val) : ::val_ops::Iterator() {
  this->val = val;
  this->n = len(val->items);
}

value_asdl::value_t* ListIterator::FirstValue() {
  if (this->i == this->n) {
    return nullptr;
  }
  return this->val->items->at(this->i);
}

DictIterator::DictIterator(value::Dict* val) : ::val_ops::Iterator() {
  this->keys = val->d->keys();
  this->values = val->d->values();
  this->n = len(val->d);
}

value_asdl::value_t* DictIterator::FirstValue() {
  if (this->i == this->n) {
    return nullptr;
  }
  return Alloc<value::Str>(this->keys->at(this->i));
}

value_asdl::value_t* DictIterator::SecondValue() {
  return this->values->at(this->i);
}

bool ToBool(value_asdl::value_t* val) {
  value_asdl::value_t* UP_val = nullptr;
  StackRoot _root0(&val);
  StackRoot _root1(&UP_val);

  UP_val = val;
  switch (val->tag()) {
    case value_e::Undef: {
      return false;
    }
      break;
    case value_e::Null: {
      return false;
    }
      break;
    case value_e::Str: {
      value::Str* val = static_cast<value::Str*>(UP_val);
      return len(val->s) != 0;
    }
      break;
    case value_e::BashArray: {
      value::BashArray* val = static_cast<value::BashArray*>(UP_val);
      return len(val->strs) != 0;
    }
      break;
    case value_e::BashAssoc: {
      value::BashAssoc* val = static_cast<value::BashAssoc*>(UP_val);
      return len(val->d) != 0;
    }
      break;
    case value_e::Bool: {
      value::Bool* val = static_cast<value::Bool*>(UP_val);
      return val->b;
    }
      break;
    case value_e::Int: {
      value::Int* val = static_cast<value::Int*>(UP_val);
      return !mops::Equal(val->i, mops::BigInt(0));
    }
      break;
    case value_e::Float: {
      value::Float* val = static_cast<value::Float*>(UP_val);
      return val->f != 0.0;
    }
      break;
    case value_e::List: {
      value::List* val = static_cast<value::List*>(UP_val);
      return len(val->items) > 0;
    }
      break;
    case value_e::Dict: {
      value::Dict* val = static_cast<value::Dict*>(UP_val);
      return len(val->d) > 0;
    }
      break;
    default: {
      return true;
    }
  }
}

bool ExactlyEqual(value_asdl::value_t* left, value_asdl::value_t* right, syntax_asdl::loc_t* blame_loc) {
  value_asdl::value_t* UP_left = nullptr;
  value_asdl::value_t* UP_right = nullptr;
  StackRoot _root0(&left);
  StackRoot _root1(&right);
  StackRoot _root2(&blame_loc);
  StackRoot _root3(&UP_left);
  StackRoot _root4(&UP_right);

  if (left->tag() != right->tag()) {
    return false;
  }
  UP_left = left;
  UP_right = right;
  switch (left->tag()) {
    case value_e::Undef: {
      return true;
    }
      break;
    case value_e::Null: {
      return true;
    }
      break;
    case value_e::Bool: {
      value::Bool* left = static_cast<value::Bool*>(UP_left);
      value::Bool* right = static_cast<value::Bool*>(UP_right);
      return left->b == right->b;
    }
      break;
    case value_e::Int: {
      value::Int* left = static_cast<value::Int*>(UP_left);
      value::Int* right = static_cast<value::Int*>(UP_right);
      return mops::Equal(left->i, right->i);
    }
      break;
    case value_e::Float: {
      throw Alloc<error::TypeErrVerbose>(str2211, blame_loc);
    }
      break;
    case value_e::Str: {
      value::Str* left = static_cast<value::Str*>(UP_left);
      value::Str* right = static_cast<value::Str*>(UP_right);
      return str_equals(left->s, right->s);
    }
      break;
    case value_e::BashArray: {
      value::BashArray* left = static_cast<value::BashArray*>(UP_left);
      value::BashArray* right = static_cast<value::BashArray*>(UP_right);
      if (len(left->strs) != len(right->strs)) {
        return false;
      }
      for (int i = 0; i < len(left->strs); ++i) {
        if (!(str_equals(left->strs->at(i), right->strs->at(i)))) {
          return false;
        }
      }
      return true;
    }
      break;
    case value_e::List: {
      value::List* left = static_cast<value::List*>(UP_left);
      value::List* right = static_cast<value::List*>(UP_right);
      if (len(left->items) != len(right->items)) {
        return false;
      }
      for (int i = 0; i < len(left->items); ++i) {
        if (!ExactlyEqual(left->items->at(i), right->items->at(i), blame_loc)) {
          return false;
        }
      }
      return true;
    }
      break;
    case value_e::BashAssoc: {
      value::Dict* left = static_cast<value::Dict*>(UP_left);
      value::Dict* right = static_cast<value::Dict*>(UP_right);
      if (len(left->d) != len(right->d)) {
        return false;
      }
      for (ListIter<BigStr*> it(left->d->keys()); !it.Done(); it.Next()) {
        BigStr* k = it.Value();
        StackRoot _for(&k      );
        if ((!dict_contains(right->d, k) or right->d->at(k) != left->d->at(k))) {
          return false;
        }
      }
      return true;
    }
      break;
    case value_e::Dict: {
      value::Dict* left = static_cast<value::Dict*>(UP_left);
      value::Dict* right = static_cast<value::Dict*>(UP_right);
      if (len(left->d) != len(right->d)) {
        return false;
      }
      for (ListIter<BigStr*> it(left->d->keys()); !it.Done(); it.Next()) {
        BigStr* k = it.Value();
        StackRoot _for(&k      );
        if ((!dict_contains(right->d, k) or !ExactlyEqual(right->d->at(k), left->d->at(k), blame_loc))) {
          return false;
        }
      }
      return true;
    }
      break;
  }
  throw Alloc<error::TypeErrVerbose>(StrFormat("Can't compare two values of type %s", ui::ValType(left)), blame_loc);
}

bool Contains(value_asdl::value_t* needle, value_asdl::value_t* haystack) {
  value_asdl::value_t* UP_haystack = nullptr;
  BigStr* s = nullptr;
  StackRoot _root0(&needle);
  StackRoot _root1(&haystack);
  StackRoot _root2(&UP_haystack);
  StackRoot _root3(&s);

  UP_haystack = haystack;
  switch (haystack->tag()) {
    case value_e::Dict: {
      value::Dict* haystack = static_cast<value::Dict*>(UP_haystack);
      s = ToStr(needle, str2213, loc::Missing);
      return dict_contains(haystack->d, s);
    }
      break;
    default: {
      throw Alloc<error::TypeErr>(haystack, str2214, loc::Missing);
    }
  }
  return false;
}

bool MatchRegex(value_asdl::value_t* left, value_asdl::value_t* right, state::Mem* mem) {
  value_asdl::value_t* UP_right = nullptr;
  BigStr* right_s = nullptr;
  int regex_flags;
  value_asdl::eggex_ops_t* capture = nullptr;
  value_asdl::value_t* UP_left = nullptr;
  BigStr* left_s = nullptr;
  List<int>* indices = nullptr;
  StackRoot _root0(&left);
  StackRoot _root1(&right);
  StackRoot _root2(&mem);
  StackRoot _root3(&UP_right);
  StackRoot _root4(&right_s);
  StackRoot _root5(&capture);
  StackRoot _root6(&UP_left);
  StackRoot _root7(&left_s);
  StackRoot _root8(&indices);

  UP_right = right;
  switch (right->tag()) {
    case value_e::Str: {
      value::Str* right = static_cast<value::Str*>(UP_right);
      right_s = right->s;
      regex_flags = 0;
      capture = eggex_ops::No;
    }
      break;
    case value_e::Eggex: {
      value::Eggex* right = static_cast<value::Eggex*>(UP_right);
      right_s = regex_translate::AsPosixEre(right);
      regex_flags = regex_translate::LibcFlags(right->canonical_flags);
      capture = Alloc<eggex_ops::Yes>(right->convert_funcs, right->convert_toks, right->capture_names);
    }
      break;
    default: {
      throw Alloc<error::TypeErr>(right, str2215, loc::Missing);
    }
  }
  UP_left = left;
  left_s = nullptr;
  switch (left->tag()) {
    case value_e::Str: {
      value::Str* left = static_cast<value::Str*>(UP_left);
      left_s = left->s;
    }
      break;
    default: {
      throw Alloc<error::TypeErrVerbose>(str2216, loc::Missing);
    }
  }
  indices = libc::regex_search(right_s, regex_flags, left_s, 0);
  if (indices != nullptr) {
    if (mem) {
      mem->SetRegexMatch(Alloc<RegexMatch>(left_s, indices, capture));
    }
    return true;
  }
  else {
    if (mem) {
      mem->SetRegexMatch(regex_match::No);
    }
    return false;
  }
}

}  // define namespace val_ops

namespace bracket_osh {  // define

using id_kind_asdl::Id;
using syntax_asdl::loc;
using syntax_asdl::word;
using syntax_asdl::word_e;
using syntax_asdl::word_t;
using syntax_asdl::bool_expr;
using types_asdl::lex_mode_e;
using value_asdl::value;
using error::e_usage;
using error::p_die;

_StringWordEmitter::_StringWordEmitter(cmd_value::Argv* cmd_val) {
  this->cmd_val = cmd_val;
  this->i = 0;
  this->n = len(cmd_val->argv);
}

word::String* _StringWordEmitter::ReadWord(types_asdl::lex_mode_t unused_lex_mode) {
  word::String* w = nullptr;
  BigStr* s = nullptr;
  syntax_asdl::CompoundWord* arg_loc = nullptr;
  int id_;
  StackRoot _root0(&w);
  StackRoot _root1(&s);
  StackRoot _root2(&arg_loc);

  if (this->i == this->n) {
    w = Alloc<word::String>(Id::Eof_Real, str2217, nullptr);
    return w;
  }
  s = this->cmd_val->argv->at(this->i);
  arg_loc = this->cmd_val->arg_locs->at(this->i);
  this->i += 1;
  id_ = match::BracketUnary(s);
  if (id_ == Id::Undefined_Tok) {
    id_ = match::BracketBinary(s);
  }
  if (id_ == Id::Undefined_Tok) {
    id_ = match::BracketOther(s);
  }
  if (id_ == Id::Undefined_Tok) {
    id_ = Id::Word_Compound;
  }
  return Alloc<word::String>(id_, s, arg_loc);
}

word::String* _StringWordEmitter::Read() {
  return this->ReadWord(lex_mode_e::ShCommand);
}

BigStr* _StringWordEmitter::Peek(int offset) {
  return this->cmd_val->argv->at((this->i + offset));
}

void _StringWordEmitter::Rewind(int offset) {
  this->i -= offset;
}

_WordEvaluator::_WordEvaluator() : ::word_eval::StringWordEvaluator() {
}

value::Str* _WordEvaluator::EvalWordToString(syntax_asdl::word_t* w, int eval_flags) {
  word::String* string_word = nullptr;
  StackRoot _root0(&w);
  StackRoot _root1(&string_word);

  string_word = static_cast<word::String*>(w);
  return Alloc<value::Str>(string_word->s);
}

syntax_asdl::bool_expr_t* _TwoArgs(bracket_osh::_StringWordEmitter* w_parser) {
  word::String* w0 = nullptr;
  word::String* w1 = nullptr;
  BigStr* s0 = nullptr;
  int unary_id;
  StackRoot _root0(&w_parser);
  StackRoot _root1(&w0);
  StackRoot _root2(&w1);
  StackRoot _root3(&s0);

  w0 = w_parser->Read();
  w1 = w_parser->Read();
  s0 = w0->s;
  if (str_equals(s0, str2218)) {
    return Alloc<bool_expr::LogicalNot>(Alloc<bool_expr::WordTest>(w1));
  }
  unary_id = Id::Undefined_Tok;
  if (w0->s->startswith(str2219)) {
    if (str_equals(s0, str2220)) {
      unary_id = Id::BoolUnary_d;
    }
    else {
      if (str_equals(s0, str2221)) {
        unary_id = Id::BoolUnary_e;
      }
      else {
        if (str_equals(s0, str2222)) {
          unary_id = Id::BoolUnary_f;
        }
        else {
          if (str_equals(s0, str2223)) {
            unary_id = Id::BoolUnary_L;
          }
        }
      }
    }
  }
  if (unary_id == Id::Undefined_Tok) {
    unary_id = match::BracketUnary(w0->s);
  }
  if (unary_id == Id::Undefined_Tok) {
    p_die(StrFormat("Expected unary operator, got %r (2 args)", w0->s), Alloc<loc::Word>(w0));
  }
  return Alloc<bool_expr::Unary>(unary_id, w1);
}

syntax_asdl::bool_expr_t* _ThreeArgs(bracket_osh::_StringWordEmitter* w_parser) {
  word::String* w0 = nullptr;
  word::String* w1 = nullptr;
  word::String* w2 = nullptr;
  int binary_id;
  syntax_asdl::bool_expr_t* child = nullptr;
  StackRoot _root0(&w_parser);
  StackRoot _root1(&w0);
  StackRoot _root2(&w1);
  StackRoot _root3(&w2);
  StackRoot _root4(&child);

  w0 = w_parser->Read();
  w1 = w_parser->Read();
  w2 = w_parser->Read();
  binary_id = match::BracketBinary(w1->s);
  if (binary_id != Id::Undefined_Tok) {
    return Alloc<bool_expr::Binary>(binary_id, w0, w2);
  }
  if (str_equals(w1->s, str2225)) {
    return Alloc<bool_expr::LogicalAnd>(Alloc<bool_expr::WordTest>(w0), Alloc<bool_expr::WordTest>(w2));
  }
  if (str_equals(w1->s, str2226)) {
    return Alloc<bool_expr::LogicalOr>(Alloc<bool_expr::WordTest>(w0), Alloc<bool_expr::WordTest>(w2));
  }
  if (str_equals(w0->s, str2227)) {
    w_parser->Rewind(2);
    child = _TwoArgs(w_parser);
    return Alloc<bool_expr::LogicalNot>(child);
  }
  if ((str_equals(w0->s, str2228) and str_equals(w2->s, str2229))) {
    return Alloc<bool_expr::WordTest>(w1);
  }
  p_die(StrFormat("Expected binary operator, got %r (3 args)", w1->s), Alloc<loc::Word>(w1));
}

Test::Test(bool need_right_bracket, optview::Exec* exec_opts, state::Mem* mem, ui::ErrorFormatter* errfmt) {
  this->need_right_bracket = need_right_bracket;
  this->exec_opts = exec_opts;
  this->mem = mem;
  this->errfmt = errfmt;
}

int Test::Run(cmd_value::Argv* cmd_val) {
  List<BigStr*>* strs = nullptr;
  bracket_osh::_StringWordEmitter* w_parser = nullptr;
  bool_parse::BoolParser* b_parser = nullptr;
  syntax_asdl::bool_expr_t* bool_node = nullptr;
  int n;
  word::String* w = nullptr;
  BigStr* a0 = nullptr;
  syntax_asdl::bool_expr_t* child = nullptr;
  bracket_osh::_WordEvaluator* word_ev = nullptr;
  sh_expr_eval::BoolEvaluator* bool_ev = nullptr;
  bool b;
  int status;
  StackRoot _root0(&cmd_val);
  StackRoot _root1(&strs);
  StackRoot _root2(&w_parser);
  StackRoot _root3(&b_parser);
  StackRoot _root4(&bool_node);
  StackRoot _root5(&w);
  StackRoot _root6(&a0);
  StackRoot _root7(&child);
  StackRoot _root8(&word_ev);
  StackRoot _root9(&bool_ev);

  if (this->need_right_bracket) {
    if (this->exec_opts->simple_test_builtin()) {
      e_usage(str2231, loc::Missing);
    }
    strs = cmd_val->argv;
    if ((len(strs) == 0 or !(str_equals(strs->at(-1), str2232)))) {
      this->errfmt->Print_(str2233, cmd_val->arg_locs->at(0));
      return 2;
    }
    cmd_val->argv->pop();
    cmd_val->arg_locs->pop();
  }
  w_parser = Alloc<_StringWordEmitter>(cmd_val);
  w_parser->Read();
  b_parser = Alloc<bool_parse::BoolParser>(w_parser);
  bool_node = nullptr;
  n = (len(cmd_val->argv) - 1);
  if ((this->exec_opts->simple_test_builtin() and n > 3)) {
    e_usage(str2234, loc::Missing);
  }
  try {
    if (n == 0) {
      return 1;
    }
    else {
      if (n == 1) {
        w = w_parser->Read();
        bool_node = Alloc<bool_expr::WordTest>(w);
      }
      else {
        if (n == 2) {
          bool_node = _TwoArgs(w_parser);
        }
        else {
          if (n == 3) {
            bool_node = _ThreeArgs(w_parser);
          }
        }
      }
    }
    if (n == 4) {
      a0 = w_parser->Peek(0);
      if (str_equals(a0, str2235)) {
        w_parser->Read();
        child = _ThreeArgs(w_parser);
        bool_node = Alloc<bool_expr::LogicalNot>(child);
      }
      else {
        if ((str_equals(a0, str2236) and str_equals(w_parser->Peek(3), str2237))) {
          w_parser->Read();
          bool_node = _TwoArgs(w_parser);
        }
        else {
          ;  // pass
        }
      }
    }
    if (bool_node == nullptr) {
      bool_node = b_parser->ParseForBuiltin();
    }
  }
  catch (error::Parse* e) {
    this->errfmt->PrettyPrintError(e, str2238);
    return 2;
  }
  word_ev = Alloc<_WordEvaluator>();
  bool_ev = Alloc<sh_expr_eval::BoolEvaluator>(this->mem, this->exec_opts, nullptr, nullptr, this->errfmt, true);
  bool_ev->word_ev = word_ev;
  bool_ev->CheckCircularDeps();
  try {
    b = bool_ev->EvalB(bool_node);
  }
  catch (error::_ErrorWithLocation* e) {
    this->errfmt->PrettyPrintError(e, str2239);
    return 2;
  }
  status = b ? 0 : 1;
  return status;
}

}  // define namespace bracket_osh

namespace completion_osh {  // define

using syntax_asdl::loc;
using value_asdl::value;
using value_asdl::value_e;
using mylib::print_stderr;

_FixedWordsAction::_FixedWordsAction(List<BigStr*>* d) {
  this->d = d;
}

void _FixedWordsAction::Matches(completion::Api* comp, List<BigStr*>* _out_yield_acc) {
  StackRoot _root0(&comp);

  for (ListIter<BigStr*> it(sorted(this->d)); !it.Done(); it.Next()) {
    BigStr* name = it.Value();
    StackRoot _for(&name  );
    if (name->startswith(comp->to_complete)) {
            _out_yield_acc->append(name);
;
    }
  }
}

void _FixedWordsAction::Print(mylib::BufWriter* f) {
  StackRoot _root0(&f);

  f->write(str2240);
}

_DynamicProcDictAction::_DynamicProcDictAction(Dict<BigStr*, value::Proc*>* d) {
  this->d = d;
}

void _DynamicProcDictAction::Matches(completion::Api* comp, List<BigStr*>* _out_yield_acc) {
  StackRoot _root0(&comp);

  for (ListIter<BigStr*> it(sorted(this->d)); !it.Done(); it.Next()) {
    BigStr* name = it.Value();
    StackRoot _for(&name  );
    if (name->startswith(comp->to_complete)) {
            _out_yield_acc->append(name);
;
    }
  }
}

void _DynamicProcDictAction::Print(mylib::BufWriter* f) {
  StackRoot _root0(&f);

  f->write(str2241);
}

_DynamicStrDictAction::_DynamicStrDictAction(Dict<BigStr*, BigStr*>* d) {
  this->d = d;
}

void _DynamicStrDictAction::Matches(completion::Api* comp, List<BigStr*>* _out_yield_acc) {
  StackRoot _root0(&comp);

  for (ListIter<BigStr*> it(sorted(this->d)); !it.Done(); it.Next()) {
    BigStr* name = it.Value();
    StackRoot _for(&name  );
    if (name->startswith(comp->to_complete)) {
            _out_yield_acc->append(name);
;
    }
  }
}

void _DynamicStrDictAction::Print(mylib::BufWriter* f) {
  StackRoot _root0(&f);

  f->write(str2242);
}

SpecBuilder::SpecBuilder(cmd_eval::CommandEvaluator* cmd_ev, parse_lib::ParseContext* parse_ctx, word_eval::NormalWordEvaluator* word_ev, split::SplitContext* splitter, completion::Lookup* comp_lookup, Dict<BigStr*, BigStr*>* help_data, ui::ErrorFormatter* errfmt) {
  this->cmd_ev = cmd_ev;
  this->parse_ctx = parse_ctx;
  this->word_ev = word_ev;
  this->splitter = splitter;
  this->comp_lookup = comp_lookup;
  this->help_data = help_data;
  this->topic_list = nullptr;
  this->errfmt = errfmt;
}

completion::UserSpec* SpecBuilder::Build(List<BigStr*>* argv, args::_Attributes* attrs, Dict<BigStr*, bool>* base_opts) {
  cmd_eval::CommandEvaluator* cmd_ev = nullptr;
  arg_types::compgen* arg = nullptr;
  List<completion::CompletionAction*>* actions = nullptr;
  BigStr* func_name = nullptr;
  value::Proc* func = nullptr;
  BigStr* command = nullptr;
  completion::CompletionAction* a = nullptr;
  word_parse::WordParser* w_parser = nullptr;
  syntax_asdl::CompoundWord* arg_word = nullptr;
  List<completion::CompletionAction*>* extra_actions = nullptr;
  List<completion::CompletionAction*>* else_actions = nullptr;
  completion::_Predicate* p = nullptr;
  BigStr* filter_pat = nullptr;
  BigStr* prefix = nullptr;
  BigStr* suffix = nullptr;
  StackRoot _root0(&argv);
  StackRoot _root1(&attrs);
  StackRoot _root2(&base_opts);
  StackRoot _root3(&cmd_ev);
  StackRoot _root4(&arg);
  StackRoot _root5(&actions);
  StackRoot _root6(&func_name);
  StackRoot _root7(&func);
  StackRoot _root8(&command);
  StackRoot _root9(&a);
  StackRoot _root10(&w_parser);
  StackRoot _root11(&arg_word);
  StackRoot _root12(&extra_actions);
  StackRoot _root13(&else_actions);
  StackRoot _root14(&p);
  StackRoot _root15(&filter_pat);
  StackRoot _root16(&prefix);
  StackRoot _root17(&suffix);

  cmd_ev = this->cmd_ev;
  arg = Alloc<arg_types::compgen>(attrs->attrs);
  actions = Alloc<List<completion::CompletionAction*>>();
  if (arg->F != nullptr) {
    func_name = arg->F;
    func = cmd_ev->procs->get(func_name);
    if (func == nullptr) {
      throw Alloc<error::Usage>(StrFormat("function %r not found", func_name), loc::Missing);
    }
    actions->append(Alloc<completion::ShellFuncAction>(cmd_ev, func, this->comp_lookup));
  }
  if (arg->C != nullptr) {
    command = arg->C;
    actions->append(Alloc<completion::CommandAction>(cmd_ev, command));
    print_stderr(str2244);
  }
  for (ListIter<BigStr*> it(attrs->actions); !it.Done(); it.Next()) {
    BigStr* name = it.Value();
    StackRoot _for(&name  );
    if (str_equals(name, str2245)) {
      a = Alloc<_DynamicStrDictAction>(this->parse_ctx->aliases);
    }
    else {
      if (str_equals(name, str2246)) {
        a = Alloc<_FixedWordsAction>(NewList<BigStr*>(std::initializer_list<BigStr*>{str2247}));
      }
      else {
        if (str_equals(name, str2248)) {
          a = Alloc<_FixedWordsAction>(consts::BUILTIN_NAMES);
        }
        else {
          if (str_equals(name, str2249)) {
            actions->append(Alloc<_FixedWordsAction>(consts::BUILTIN_NAMES));
            actions->append(Alloc<_DynamicStrDictAction>(this->parse_ctx->aliases));
            actions->append(Alloc<_DynamicProcDictAction>(cmd_ev->procs));
            actions->append(Alloc<_FixedWordsAction>(consts::OSH_KEYWORD_NAMES));
            actions->append(Alloc<completion::FileSystemAction>(false, true, false));
            a = Alloc<completion::ExternalCommandAction>(cmd_ev->mem);
          }
          else {
            if (str_equals(name, str2250)) {
              a = Alloc<completion::FileSystemAction>(true, false, false);
            }
            else {
              if (str_equals(name, str2251)) {
                a = Alloc<completion::ExportedVarsAction>(cmd_ev->mem);
              }
              else {
                if (str_equals(name, str2252)) {
                  a = Alloc<completion::FileSystemAction>(false, false, false);
                }
                else {
                  if (str_equals(name, str2253)) {
                    a = Alloc<_DynamicProcDictAction>(cmd_ev->procs);
                  }
                  else {
                    if (str_equals(name, str2254)) {
                      a = Alloc<_FixedWordsAction>(NewList<BigStr*>(std::initializer_list<BigStr*>{str2255}));
                    }
                    else {
                      if (str_equals(name, str2256)) {
                        a = Alloc<_FixedWordsAction>(consts::OSH_KEYWORD_NAMES);
                      }
                      else {
                        if (str_equals(name, str2257)) {
                          a = Alloc<completion::UsersAction>();
                        }
                        else {
                          if (str_equals(name, str2258)) {
                            a = Alloc<completion::VariablesAction>(cmd_ev->mem);
                          }
                          else {
                            if (str_equals(name, str2259)) {
                              if (this->topic_list == nullptr) {
                                this->topic_list = this->help_data->keys();
                              }
                              a = Alloc<_FixedWordsAction>(this->topic_list);
                            }
                            else {
                              if (str_equals(name, str2260)) {
                                a = Alloc<_FixedWordsAction>(consts::SET_OPTION_NAMES);
                              }
                              else {
                                if (str_equals(name, str2261)) {
                                  a = Alloc<_FixedWordsAction>(consts::SHOPT_OPTION_NAMES);
                                }
                                else {
                                  if (str_equals(name, str2262)) {
                                    a = Alloc<_FixedWordsAction>(NewList<BigStr*>(std::initializer_list<BigStr*>{str2263}));
                                  }
                                  else {
                                    if (str_equals(name, str2264)) {
                                      a = Alloc<_FixedWordsAction>(NewList<BigStr*>(std::initializer_list<BigStr*>{str2265}));
                                    }
                                    else {
                                      assert(0);  // AssertionError
                                    }
                                  }
                                }
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
    actions->append(a);
  }
  if (arg->W != nullptr) {
    w_parser = this->parse_ctx->MakeWordParserForPlugin(arg->W);
    try {
      arg_word = w_parser->ReadForPlugin();
    }
    catch (error::Parse* e) {
      this->errfmt->PrettyPrintError(e);
      throw ;
    }
    a = Alloc<completion::DynamicWordsAction>(this->word_ev, this->splitter, arg_word, this->errfmt);
    actions->append(a);
  }
  extra_actions = Alloc<List<completion::CompletionAction*>>();
  if (base_opts->get(str2266, false)) {
    extra_actions->append(Alloc<completion::FileSystemAction>(true, false, false));
  }
  else_actions = Alloc<List<completion::CompletionAction*>>();
  if (base_opts->get(str2267, false)) {
    else_actions->append(Alloc<completion::FileSystemAction>(false, false, false));
  }
  if (base_opts->get(str2268, false)) {
    else_actions->append(Alloc<completion::FileSystemAction>(true, false, false));
  }
  if ((len(actions) == 0 and len(else_actions) == 0)) {
    throw Alloc<error::Usage>(StrFormat("No actions defined in completion: %s", str2270->join(argv)), loc::Missing);
  }
  p = Alloc<completion::DefaultPredicate>();
  if (arg->X != nullptr) {
    filter_pat = arg->X;
    if (filter_pat->startswith(str2271)) {
      p = Alloc<completion::GlobPredicate>(false, filter_pat->slice(1));
    }
    else {
      p = Alloc<completion::GlobPredicate>(true, filter_pat);
    }
  }
  prefix = arg->P;
  if (prefix == nullptr) {
    prefix = str2272;
  }
  suffix = arg->S;
  if (suffix == nullptr) {
    suffix = str2273;
  }
  return Alloc<completion::UserSpec>(actions, extra_actions, else_actions, p, prefix, suffix);
}

Complete::Complete(completion_osh::SpecBuilder* spec_builder, completion::Lookup* comp_lookup) {
  this->spec_builder = spec_builder;
  this->comp_lookup = comp_lookup;
}

int Complete::Run(cmd_value::Argv* cmd_val) {
  args::Reader* arg_r = nullptr;
  args::_Attributes* attrs = nullptr;
  arg_types::complete* arg = nullptr;
  List<BigStr*>* commands = nullptr;
  Dict<BigStr*, bool>* base_opts = nullptr;
  completion::UserSpec* user_spec = nullptr;
  List<BigStr*>* patterns = nullptr;
  StackRoot _root0(&cmd_val);
  StackRoot _root1(&arg_r);
  StackRoot _root2(&attrs);
  StackRoot _root3(&arg);
  StackRoot _root4(&commands);
  StackRoot _root5(&base_opts);
  StackRoot _root6(&user_spec);
  StackRoot _root7(&patterns);

  arg_r = Alloc<args::Reader>(cmd_val->argv, cmd_val->arg_locs);
  arg_r->Next();
  attrs = flag_util::ParseMore(str2274, arg_r);
  arg = Alloc<arg_types::complete>(attrs->attrs);
  commands = arg_r->Rest();
  if (arg->D) {
    commands->append(str2275);
  }
  if (arg->E) {
    commands->append(str2276);
  }
  if (len(commands) == 0) {
    if (len(cmd_val->argv) == 1) {
      this->comp_lookup->PrintSpecs();
      return 0;
    }
    else {
      throw Alloc<error::Usage>(str2277, loc::Missing);
    }
  }
  base_opts = dict(attrs->opt_changes);
  try {
    user_spec = this->spec_builder->Build(cmd_val->argv, attrs, base_opts);
  }
  catch (error::Parse* e) {
    return 2;
  }
  for (ListIter<BigStr*> it(commands); !it.Done(); it.Next()) {
    BigStr* command = it.Value();
    StackRoot _for(&command  );
    this->comp_lookup->RegisterName(command, base_opts, user_spec);
  }
  patterns = Alloc<List<BigStr*>>();
  for (ListIter<BigStr*> it(patterns); !it.Done(); it.Next()) {
    BigStr* pat = it.Value();
    StackRoot _for(&pat  );
    this->comp_lookup->RegisterGlob(pat, base_opts, user_spec);
  }
  return 0;
}

CompGen::CompGen(completion_osh::SpecBuilder* spec_builder) {
  this->spec_builder = spec_builder;
}

int CompGen::Run(cmd_value::Argv* cmd_val) {
  args::Reader* arg_r = nullptr;
  args::_Attributes* arg = nullptr;
  BigStr* to_complete = nullptr;
  bool matched;
  Dict<BigStr*, bool>* base_opts = nullptr;
  completion::UserSpec* user_spec = nullptr;
  completion::Api* comp = nullptr;
  BigStr* m = nullptr;
  StackRoot _root0(&cmd_val);
  StackRoot _root1(&arg_r);
  StackRoot _root2(&arg);
  StackRoot _root3(&to_complete);
  StackRoot _root4(&base_opts);
  StackRoot _root5(&user_spec);
  StackRoot _root6(&comp);
  StackRoot _root7(&m);

  arg_r = Alloc<args::Reader>(cmd_val->argv, cmd_val->arg_locs);
  arg_r->Next();
  arg = flag_util::ParseMore(str2278, arg_r);
  if (arg_r->AtEnd()) {
    to_complete = str2279;
  }
  else {
    to_complete = arg_r->Peek();
    arg_r->Next();
  }
  matched = false;
  base_opts = dict(arg->opt_changes);
  try {
    user_spec = this->spec_builder->Build(cmd_val->argv, arg, base_opts);
  }
  catch (error::Parse* e) {
    return 2;
  }
  matched = false;
  comp = Alloc<completion::Api>(str2280, 0, 0);
  comp->Update(str2281, to_complete, str2282, -1, nullptr);
  try {
    List<Tuple2<BigStr*, runtime_asdl::comp_action_t>*> _for_yield_acc0;
    user_spec->AllMatches(comp, &_for_yield_acc0);
    for (ListIter<Tuple2<BigStr*, runtime_asdl::comp_action_t>*> it(&_for_yield_acc0); !it.Done(); it.Next()) {
      Tuple2<BigStr*, runtime_asdl::comp_action_t>* tup1 = it.Value();
      m = tup1->at0();
      matched = true;
      print(m);
    }
  }
  catch (error::FatalRuntime*) {
    return 1;
  }
  return matched ? 0 : 1;
}

CompOpt::CompOpt(completion::OptionState* comp_state, ui::ErrorFormatter* errfmt) {
  this->comp_state = comp_state;
  this->errfmt = errfmt;
}

int CompOpt::Run(cmd_value::Argv* cmd_val) {
  args::Reader* arg_r = nullptr;
  args::_Attributes* arg = nullptr;
  StackRoot _root0(&cmd_val);
  StackRoot _root1(&arg_r);
  StackRoot _root2(&arg);

  arg_r = Alloc<args::Reader>(cmd_val->argv, cmd_val->arg_locs);
  arg_r->Next();
  arg = flag_util::ParseMore(str2283, arg_r);
  if (!this->comp_state->currently_completing) {
    this->errfmt->Print_(str2284);
    return 1;
  }
  this->comp_state->dynamic_opts->update(arg->opt_changes);
  return 0;
}

CompAdjust::CompAdjust(state::Mem* mem) {
  this->mem = mem;
}

int CompAdjust::Run(cmd_value::Argv* cmd_val) {
  args::Reader* arg_r = nullptr;
  args::_Attributes* attrs = nullptr;
  arg_types::compadjust* arg = nullptr;
  List<BigStr*>* var_names = nullptr;
  value_asdl::value_t* val = nullptr;
  List<BigStr*>* comp_argv = nullptr;
  List<BigStr*>* break_chars = nullptr;
  BigStr* omit_chars = nullptr;
  List<BigStr*>* adjusted_argv = nullptr;
  int n;
  BigStr* cur = nullptr;
  BigStr* prev = nullptr;
  BigStr* split = nullptr;
  StackRoot _root0(&cmd_val);
  StackRoot _root1(&arg_r);
  StackRoot _root2(&attrs);
  StackRoot _root3(&arg);
  StackRoot _root4(&var_names);
  StackRoot _root5(&val);
  StackRoot _root6(&comp_argv);
  StackRoot _root7(&break_chars);
  StackRoot _root8(&omit_chars);
  StackRoot _root9(&adjusted_argv);
  StackRoot _root10(&cur);
  StackRoot _root11(&prev);
  StackRoot _root12(&split);

  arg_r = Alloc<args::Reader>(cmd_val->argv, cmd_val->arg_locs);
  arg_r->Next();
  attrs = flag_util::ParseMore(str2285, arg_r);
  arg = Alloc<arg_types::compadjust>(attrs->attrs);
  var_names = arg_r->Rest();
  for (ListIter<BigStr*> it(var_names); !it.Done(); it.Next()) {
    BigStr* name = it.Value();
    StackRoot _for(&name  );
    if (!list_contains(NewList<BigStr*>(std::initializer_list<BigStr*>{str2286, str2287, str2288, str2289}), name)) {
      throw Alloc<error::Usage>(StrFormat("Invalid output variable name %r", name), loc::Missing);
    }
  }
  val = this->mem->GetValue(str2291);
  if (val->tag() != value_e::BashArray) {
    throw Alloc<error::Usage>(str2292, loc::Missing);
  }
  comp_argv = static_cast<value::BashArray*>(val)->strs;
  break_chars = NewList<BigStr*>(std::initializer_list<BigStr*>{str2293, str2294});
  if (arg->s) {
    break_chars->remove(str2295);
  }
  omit_chars = arg->n;
  if (omit_chars == nullptr) {
    omit_chars = str2296;
  }
  for (StrIter it(omit_chars); !it.Done(); it.Next()) {
    BigStr* c = it.Value();
    StackRoot _for(&c  );
    if (list_contains(break_chars, c)) {
      break_chars->remove(c);
    }
  }
  adjusted_argv = Alloc<List<BigStr*>>();
  for (ListIter<BigStr*> it(comp_argv); !it.Done(); it.Next()) {
    BigStr* a = it.Value();
    StackRoot _for(&a  );
    completion::AdjustArg(a, break_chars, adjusted_argv);
  }
  if (list_contains(var_names, str2297)) {
    state::BuiltinSetArray(this->mem, str2298, adjusted_argv);
  }
  n = len(adjusted_argv);
  cur = adjusted_argv->at(-1);
  prev = n < 2 ? str2299 : adjusted_argv->at(-2);
  if (arg->s) {
    if ((cur->startswith(str2300) and str_contains(cur, str2301))) {
      Tuple2<BigStr*, BigStr*> tup2 = mylib::split_once(cur, str2302);
      prev = tup2.at0();
      cur = tup2.at1();
      split = str2303;
    }
    else {
      split = str2304;
    }
    state::BuiltinSetString(this->mem, str2305, split);
  }
  if (list_contains(var_names, str2306)) {
    state::BuiltinSetString(this->mem, str2307, cur);
  }
  if (list_contains(var_names, str2308)) {
    state::BuiltinSetString(this->mem, str2309, prev);
  }
  if (list_contains(var_names, str2310)) {
    state::BuiltinSetString(this->mem, str2311, str((n - 1)));
  }
  return 0;
}

}  // define namespace completion_osh

namespace shell {  // define

using option_asdl::option_i;
using option_asdl::builtin_i;
using runtime_asdl::scope_e;
using syntax_asdl::loc;
using syntax_asdl::source;
using syntax_asdl::source_t;
using syntax_asdl::IntParamBox;
using syntax_asdl::debug_frame;
using syntax_asdl::debug_frame_t;
using value_asdl::value;
using value_asdl::value_e;
using mylib::print_stderr;

void _InitDefaultCompletions(cmd_eval::CommandEvaluator* cmd_ev, completion_osh::Complete* complete_builtin, completion::Lookup* comp_lookup) {
  StackRoot _root0(&cmd_ev);
  StackRoot _root1(&complete_builtin);
  StackRoot _root2(&comp_lookup);

  complete_builtin->Run(cmd_eval::MakeBuiltinArgv(NewList<BigStr*>(std::initializer_list<BigStr*>{str2312, str2313, str2314})));
  complete_builtin->Run(cmd_eval::MakeBuiltinArgv(NewList<BigStr*>(std::initializer_list<BigStr*>{str2315, str2316, str2317})));
}

void _CompletionDemo(completion::Lookup* comp_lookup) {
  completion::TestAction* A1 = nullptr;
  List<BigStr*>* l = nullptr;
  completion::TestAction* A2 = nullptr;
  completion::UserSpec* C1 = nullptr;
  StackRoot _root0(&comp_lookup);
  StackRoot _root1(&A1);
  StackRoot _root2(&l);
  StackRoot _root3(&A2);
  StackRoot _root4(&C1);

  A1 = Alloc<completion::TestAction>(NewList<BigStr*>(std::initializer_list<BigStr*>{str2318, str2319, str2320}), 0.0);
  l = Alloc<List<BigStr*>>();
  for (int i = 0; i < 5; ++i) {
    l->append(StrFormat("m%d", i));
  }
  A2 = Alloc<completion::TestAction>(l, 0.1);
  C1 = Alloc<completion::UserSpec>(NewList<completion::CompletionAction*>(std::initializer_list<completion::CompletionAction*>{A1, A2}), Alloc<List<completion::CompletionAction*>>(), Alloc<List<completion::CompletionAction*>>(), Alloc<completion::DefaultPredicate>(), str2322, str2323);
  comp_lookup->RegisterName(str2324, Alloc<Dict<BigStr*, bool>>(), C1);
}

void SourceStartupFile(process::FdState* fd_state, BigStr* rc_path, BigStr* lang, parse_lib::ParseContext* parse_ctx, cmd_eval::CommandEvaluator* cmd_ev, ui::ErrorFormatter* errfmt) {
  mylib::LineReader* f = nullptr;
  alloc::Arena* arena = nullptr;
  reader::FileLineReader* rc_line_reader = nullptr;
  cmd_parse::CommandParser* rc_c_parser = nullptr;
  int unused;
  StackRoot _root0(&fd_state);
  StackRoot _root1(&rc_path);
  StackRoot _root2(&lang);
  StackRoot _root3(&parse_ctx);
  StackRoot _root4(&cmd_ev);
  StackRoot _root5(&errfmt);
  StackRoot _root6(&f);
  StackRoot _root7(&arena);
  StackRoot _root8(&rc_line_reader);
  StackRoot _root9(&rc_c_parser);

  try {
    f = fd_state->Open(rc_path);
  }
  catch (IOError_OSError* e) {
    if (e->errno_ != ENOENT) {
      throw ;
    }
    return ;
  }
  arena = parse_ctx->arena;
  rc_line_reader = Alloc<reader::FileLineReader>(f, arena);
  rc_c_parser = parse_ctx->MakeOshParser(rc_line_reader);
  {  // with
    alloc::ctx_SourceCode ctx{arena, Alloc<source::SourcedFile>(rc_path, loc::Missing)};

    unused = main_loop::Batch(cmd_ev, rc_c_parser, errfmt);
  }
  f->close();
}

ShellOptHook::ShellOptHook(py_readline::Readline* readline) {
  this->readline = readline;
}

bool ShellOptHook::OnChange(List<bool>* opt0_array, BigStr* opt_name, bool b) {
  StackRoot _root0(&opt0_array);
  StackRoot _root1(&opt_name);

  if ((str_equals(opt_name, str2325) or str_equals(opt_name, str2326))) {
    if (this->readline) {
      this->readline->parse_and_bind(str_concat(str2327, opt_name));
    }
    else {
      print_stderr(StrFormat("Warning: Can't set option %r because shell wasn't compiled with GNU readline", opt_name));
      return false;
    }
    if (str_equals(opt_name, str2329)) {
      opt0_array->set(option_i::emacs, !b);
    }
    else {
      if (str_equals(opt_name, str2330)) {
        opt0_array->set(option_i::vi, !b);
      }
    }
  }
  return true;
}

void _SetGlobalFunc(state::Mem* mem, BigStr* name, vm::_Callable* func) {
  StackRoot _root0(&mem);
  StackRoot _root1(&name);
  StackRoot _root2(&func);

  mem->SetNamed(location::LName(name), Alloc<value::BuiltinFunc>(func), scope_e::GlobalOnly);
}

Dict<int, vm::_AssignBuiltin*>* InitAssignmentBuiltins(state::Mem* mem, Dict<BigStr*, value::Proc*>* procs, optview::Exec* exec_opts, ui::ErrorFormatter* errfmt) {
  Dict<int, vm::_AssignBuiltin*>* assign_b = nullptr;
  assign_osh::NewVar* new_var = nullptr;
  StackRoot _root0(&mem);
  StackRoot _root1(&procs);
  StackRoot _root2(&exec_opts);
  StackRoot _root3(&errfmt);
  StackRoot _root4(&assign_b);
  StackRoot _root5(&new_var);

  assign_b = Alloc<Dict<int, vm::_AssignBuiltin*>>();
  new_var = Alloc<assign_osh::NewVar>(mem, procs, exec_opts, errfmt);
  assign_b->set(builtin_i::declare, new_var);
  assign_b->set(builtin_i::typeset, new_var);
  assign_b->set(builtin_i::local, new_var);
  assign_b->set(builtin_i::export_, Alloc<assign_osh::Export>(mem, errfmt));
  assign_b->set(builtin_i::readonly, Alloc<assign_osh::Readonly>(mem, errfmt));
  return assign_b;
}

ShellFiles::ShellFiles(BigStr* lang, BigStr* home_dir, state::Mem* mem, arg_types::main* flag) {
  this->lang = lang;
  this->home_dir = home_dir;
  this->mem = mem;
  this->flag = flag;
}

BigStr* ShellFiles::_HistVar() {
  return str_equals(this->lang, str2331) ? str2332 : str2333;
}

BigStr* ShellFiles::_DefaultHistoryFile() {
  return os_path::join(this->home_dir, StrFormat(".local/share/oils/%s_history", this->lang));
}

void ShellFiles::InitAfterLoadingEnv() {
  BigStr* hist_var = nullptr;
  StackRoot _root0(&hist_var);

  hist_var = this->_HistVar();
  if (this->mem->GetValue(hist_var)->tag() == value_e::Undef) {
    state::SetGlobalString(this->mem, hist_var, this->_DefaultHistoryFile());
  }
}

BigStr* ShellFiles::HistoryFile() {
  value_asdl::value_t* UP_val = nullptr;
  StackRoot _root0(&UP_val);

  UP_val = this->mem->GetValue(this->_HistVar());
  if (UP_val->tag() == value_e::Str) {
    value::Str* val = static_cast<value::Str*>(UP_val);
    return val->s;
  }
  else {
    return nullptr;
  }
}

int Main(BigStr* lang, args::Reader* arg_r, Dict<BigStr*, BigStr*>* environ, bool login_shell, pyutil::_ResourceLoader* loader, py_readline::Readline* readline) {
  BigStr* argv0 = nullptr;
  args::_Attributes* attrs = nullptr;
  arg_types::main* flag = nullptr;
  alloc::Arena* arena = nullptr;
  ui::ErrorFormatter* errfmt = nullptr;
  List<BigStr*>* paths = nullptr;
  int status;
  BigStr* contents = nullptr;
  List<syntax_asdl::debug_frame_t*>* debug_stack = nullptr;
  BigStr* dollar0 = nullptr;
  debug_frame::Main* frame0 = nullptr;
  BigStr* script_name = nullptr;
  state::Mem* mem = nullptr;
  shell::ShellOptHook* opt_hook = nullptr;
  optview::Parse* parse_opts = nullptr;
  optview::Exec* exec_opts = nullptr;
  state::MutableOpts* mutable_opts = nullptr;
  BigStr* version_str = nullptr;
  Dict<BigStr*, BigStr*>* aliases = nullptr;
  grammar::Grammar* ysh_grammar = nullptr;
  bool do_lossless;
  parse_lib::ParseContext* parse_ctx = nullptr;
  alloc::Arena* comp_arena = nullptr;
  parse_lib::Trail* trail1 = nullptr;
  parse_lib::ParseContext* comp_ctx = nullptr;
  alloc::Arena* hist_arena = nullptr;
  parse_lib::Trail* trail2 = nullptr;
  parse_lib::ParseContext* hist_ctx = nullptr;
  cmd_eval::Deps* cmd_deps = nullptr;
  process::JobControl* job_control = nullptr;
  process::JobList* job_list = nullptr;
  process::FdState* fd_state = nullptr;
  int my_pid;
  BigStr* debug_path = nullptr;
  BigStr* debug_dir = nullptr;
  util::_DebugFile* debug_f = nullptr;
  util::_DebugFile* trace_f = nullptr;
  BigStr* trace_dir = nullptr;
  BigStr* dumps = nullptr;
  BigStr* streams = nullptr;
  dev::MultiTracer* multi_trace = nullptr;
  dev::Tracer* tracer = nullptr;
  pyos::SignalSafe* signal_safe = nullptr;
  trap_osh::TrapState* trap_state = nullptr;
  process::Waiter* waiter = nullptr;
  double now;
  BigStr* iso_stamp = nullptr;
  mylib::BufWriter* argv_buf = nullptr;
  BigStr* interp = nullptr;
  state::SearchPath* search_path = nullptr;
  process::ExternalProgram* ext_prog = nullptr;
  split::SplitContext* splitter = nullptr;
  glob_::Globber* globber = nullptr;
  BigStr* crash_dump_dir = nullptr;
  completion::Lookup* comp_lookup = nullptr;
  completion::OptionState* compopt_state = nullptr;
  comp_ui::State* comp_ui_state = nullptr;
  comp_ui::PromptState* prompt_state = nullptr;
  word_eval::TildeEvaluator* tilde_ev = nullptr;
  BigStr* home_dir = nullptr;
  shell::ShellFiles* sh_files = nullptr;
  Dict<BigStr*, value::Proc*>* procs = nullptr;
  Dict<int, vm::_Builtin*>* builtins = nullptr;
  Dict<int, Dict<BigStr*, vm::_Callable*>*>* methods = nullptr;
  hay_ysh::HayState* hay_state = nullptr;
  executor::ShellExecutor* shell_ex = nullptr;
  sh_expr_eval::ArithEvaluator* arith_ev = nullptr;
  sh_expr_eval::BoolEvaluator* bool_ev = nullptr;
  expr_eval::ExprEvaluator* expr_ev = nullptr;
  word_eval::NormalWordEvaluator* word_ev = nullptr;
  Dict<int, vm::_AssignBuiltin*>* assign_b = nullptr;
  cmd_eval::CommandEvaluator* cmd_ev = nullptr;
  prompt::Evaluator* prompt_ev = nullptr;
  value::IO* global_io = nullptr;
  value::Guts* global_guts = nullptr;
  sh_expr_eval::UnsafeArith* unsafe_arith = nullptr;
  Dict<int, vm::_Builtin*>* b = nullptr;
  Dict<BigStr*, BigStr*>* help_data = nullptr;
  meta_osh::Source* source_builtin = nullptr;
  Dict<BigStr*, bool>* guards = nullptr;
  pure_osh::Boolean* true_ = nullptr;
  io_osh::MapFile* mapfile = nullptr;
  dirs_osh::DirStack* dir_stack = nullptr;
  completion_osh::SpecBuilder* spec_builder = nullptr;
  completion_osh::Complete* complete_builtin = nullptr;
  word_eval::CompletionWordEvaluator* comp_ev = nullptr;
  completion::RootCompleter* root_comp = nullptr;
  func_hay::ParseHay* parse_hay = nullptr;
  func_hay::EvalHay* eval_hay = nullptr;
  func_hay::HayFunc* hay_func = nullptr;
  func_eggex::MatchFunc* g = nullptr;
  history::Evaluator* hist_ev = nullptr;
  syntax_asdl::source_t* src = nullptr;
  reader::_Reader* line_reader = nullptr;
  mylib::LineReader* stdin_ = nullptr;
  mylib::LineReader* f = nullptr;
  int location_start_line;
  BigStr* config_dir = nullptr;
  List<BigStr*>* rc_paths = nullptr;
  BigStr* rc_path = nullptr;
  BigStr* rc_dir = nullptr;
  main_loop::Headless* loop = nullptr;
  syntax_asdl::IntParamBox* mut_status = nullptr;
  cmd_parse::CommandParser* c_parser = nullptr;
  int term_width;
  comp_ui::_IDisplay* display = nullptr;
  prompt::UserPlugin* prompt_plugin = nullptr;
  BigStr* hist_file = nullptr;
  BigStr* tool_name = nullptr;
  syntax_asdl::command_t* node = nullptr;
  StackRoot _root0(&lang);
  StackRoot _root1(&arg_r);
  StackRoot _root2(&environ);
  StackRoot _root3(&loader);
  StackRoot _root4(&readline);
  StackRoot _root5(&argv0);
  StackRoot _root6(&attrs);
  StackRoot _root7(&flag);
  StackRoot _root8(&arena);
  StackRoot _root9(&errfmt);
  StackRoot _root10(&paths);
  StackRoot _root11(&contents);
  StackRoot _root12(&debug_stack);
  StackRoot _root13(&dollar0);
  StackRoot _root14(&frame0);
  StackRoot _root15(&script_name);
  StackRoot _root16(&mem);
  StackRoot _root17(&opt_hook);
  StackRoot _root18(&parse_opts);
  StackRoot _root19(&exec_opts);
  StackRoot _root20(&mutable_opts);
  StackRoot _root21(&version_str);
  StackRoot _root22(&aliases);
  StackRoot _root23(&ysh_grammar);
  StackRoot _root24(&parse_ctx);
  StackRoot _root25(&comp_arena);
  StackRoot _root26(&trail1);
  StackRoot _root27(&comp_ctx);
  StackRoot _root28(&hist_arena);
  StackRoot _root29(&trail2);
  StackRoot _root30(&hist_ctx);
  StackRoot _root31(&cmd_deps);
  StackRoot _root32(&job_control);
  StackRoot _root33(&job_list);
  StackRoot _root34(&fd_state);
  StackRoot _root35(&debug_path);
  StackRoot _root36(&debug_dir);
  StackRoot _root37(&debug_f);
  StackRoot _root38(&trace_f);
  StackRoot _root39(&trace_dir);
  StackRoot _root40(&dumps);
  StackRoot _root41(&streams);
  StackRoot _root42(&multi_trace);
  StackRoot _root43(&tracer);
  StackRoot _root44(&signal_safe);
  StackRoot _root45(&trap_state);
  StackRoot _root46(&waiter);
  StackRoot _root47(&iso_stamp);
  StackRoot _root48(&argv_buf);
  StackRoot _root49(&interp);
  StackRoot _root50(&search_path);
  StackRoot _root51(&ext_prog);
  StackRoot _root52(&splitter);
  StackRoot _root53(&globber);
  StackRoot _root54(&crash_dump_dir);
  StackRoot _root55(&comp_lookup);
  StackRoot _root56(&compopt_state);
  StackRoot _root57(&comp_ui_state);
  StackRoot _root58(&prompt_state);
  StackRoot _root59(&tilde_ev);
  StackRoot _root60(&home_dir);
  StackRoot _root61(&sh_files);
  StackRoot _root62(&procs);
  StackRoot _root63(&builtins);
  StackRoot _root64(&methods);
  StackRoot _root65(&hay_state);
  StackRoot _root66(&shell_ex);
  StackRoot _root67(&arith_ev);
  StackRoot _root68(&bool_ev);
  StackRoot _root69(&expr_ev);
  StackRoot _root70(&word_ev);
  StackRoot _root71(&assign_b);
  StackRoot _root72(&cmd_ev);
  StackRoot _root73(&prompt_ev);
  StackRoot _root74(&global_io);
  StackRoot _root75(&global_guts);
  StackRoot _root76(&unsafe_arith);
  StackRoot _root77(&b);
  StackRoot _root78(&help_data);
  StackRoot _root79(&source_builtin);
  StackRoot _root80(&guards);
  StackRoot _root81(&true_);
  StackRoot _root82(&mapfile);
  StackRoot _root83(&dir_stack);
  StackRoot _root84(&spec_builder);
  StackRoot _root85(&complete_builtin);
  StackRoot _root86(&comp_ev);
  StackRoot _root87(&root_comp);
  StackRoot _root88(&parse_hay);
  StackRoot _root89(&eval_hay);
  StackRoot _root90(&hay_func);
  StackRoot _root91(&g);
  StackRoot _root92(&hist_ev);
  StackRoot _root93(&src);
  StackRoot _root94(&line_reader);
  StackRoot _root95(&stdin_);
  StackRoot _root96(&f);
  StackRoot _root97(&config_dir);
  StackRoot _root98(&rc_paths);
  StackRoot _root99(&rc_path);
  StackRoot _root100(&rc_dir);
  StackRoot _root101(&loop);
  StackRoot _root102(&mut_status);
  StackRoot _root103(&c_parser);
  StackRoot _root104(&display);
  StackRoot _root105(&prompt_plugin);
  StackRoot _root106(&hist_file);
  StackRoot _root107(&tool_name);
  StackRoot _root108(&node);

  argv0 = arg_r->Peek();
  arg_r->Next();
  try {
    attrs = flag_util::ParseMore(str2335, arg_r);
  }
  catch (error::Usage* e) {
    print_stderr(StrFormat("%s usage error: %s", lang, e->msg));
    return 2;
  }
  flag = Alloc<arg_types::main>(attrs->attrs);
  arena = Alloc<alloc::Arena>();
  errfmt = Alloc<ui::ErrorFormatter>();
  if (flag->help) {
    util::HelpFlag(loader, StrFormat("%s-usage", lang), mylib::Stdout());
    return 0;
  }
  if (flag->version) {
    util::VersionFlag(loader, mylib::Stdout());
    return 0;
  }
  if (maybe_str_equals(flag->tool, str2338)) {
    paths = arg_r->Rest();
    status = 0;
    for (ListIter<BigStr*> it(paths); !it.Done(); it.Next()) {
      BigStr* p = it.Value();
      StackRoot _for(&p    );
      try {
        contents = loader->Get(p);
        print(contents);
      }
      catch (IOError_OSError*) {
        print_stderr(StrFormat("cat-em: %r not found", p));
        status = 1;
      }
    }
    return status;
  }
  debug_stack = Alloc<List<syntax_asdl::debug_frame_t*>>();
  if (arg_r->AtEnd()) {
    dollar0 = argv0;
  }
  else {
    dollar0 = arg_r->Peek();
    frame0 = Alloc<debug_frame::Main>(dollar0);
    debug_stack->append(frame0);
  }
  script_name = arg_r->Peek();
  arg_r->Next();
  mem = Alloc<state::Mem>(dollar0, arg_r->Rest(), arena, debug_stack);
  opt_hook = Alloc<ShellOptHook>(readline);
  Tuple3<optview::Parse*, optview::Exec*, state::MutableOpts*> tup0 = state::MakeOpts(mem, opt_hook);
  parse_opts = tup0.at0();
  exec_opts = tup0.at1();
  mutable_opts = tup0.at2();
  mem->exec_opts = exec_opts;
  mutable_opts->Init();
  version_str = pyutil::GetVersion(loader);
  state::InitMem(mem, environ, version_str);
  if (attrs->show_options) {
    mutable_opts->ShowOptions(Alloc<List<BigStr*>>());
    return 0;
  }
  if (str_equals(lang, str2340)) {
    mutable_opts->SetAnyOption(str2341, true);
  }
  pure_osh::SetOptionsFromFlags(mutable_opts, attrs->opt_changes, attrs->shopt_changes);
  aliases = Alloc<Dict<BigStr*, BigStr*>>();
  ysh_grammar = pyutil::LoadYshGrammar(loader);
  if ((flag->do_lossless and !exec_opts->noexec())) {
    throw Alloc<error::Usage>(str2342, loc::Missing);
  }
  do_lossless = len(flag->tool) ? true : flag->do_lossless;
  parse_ctx = Alloc<parse_lib::ParseContext>(arena, parse_opts, aliases, ysh_grammar, do_lossless);
  comp_arena = Alloc<alloc::Arena>();
  comp_arena->PushSource(Alloc<source::Unused>(str2343));
  trail1 = Alloc<parse_lib::Trail>();
  comp_ctx = Alloc<parse_lib::ParseContext>(comp_arena, parse_opts, aliases, ysh_grammar, true);
  comp_ctx->Init_Trail(trail1);
  hist_arena = Alloc<alloc::Arena>();
  hist_arena->PushSource(Alloc<source::Unused>(str2344));
  trail2 = Alloc<parse_lib::Trail>();
  hist_ctx = Alloc<parse_lib::ParseContext>(hist_arena, parse_opts, aliases, ysh_grammar);
  hist_ctx->Init_Trail(trail2);
  cmd_deps = Alloc<cmd_eval::Deps>();
  cmd_deps->mutable_opts = mutable_opts;
  job_control = Alloc<process::JobControl>();
  job_list = Alloc<process::JobList>();
  fd_state = Alloc<process::FdState>(errfmt, job_control, job_list, mem, nullptr, nullptr);
  my_pid = posix::getpid();
  debug_path = str2345;
  debug_dir = environ->get(str2346);
  if (flag->debug_file != nullptr) {
    debug_path = flag->debug_file;
  }
  else {
    if (debug_dir != nullptr) {
      debug_path = os_path::join(debug_dir, StrFormat("%d-osh.log", my_pid));
    }
  }
  if (len(debug_path)) {
    try {
      debug_f = Alloc<util::DebugFile>(fd_state->OpenForWrite(debug_path));
    }
    catch (IOError_OSError* e) {
      print_stderr(StrFormat("%s: Couldn't open %r: %s", lang, debug_path, posix::strerror(e->errno_)));
      return 2;
    }
  }
  else {
    debug_f = Alloc<util::NullDebugFile>();
  }
  if (flag->xtrace_to_debug_file) {
    trace_f = debug_f;
  }
  else {
    trace_f = Alloc<util::DebugFile>(mylib::Stderr());
  }
  trace_dir = environ->get(str2349, str2350);
  dumps = environ->get(str2351, str2352);
  streams = environ->get(str2353, str2354);
  multi_trace = Alloc<dev::MultiTracer>(my_pid, trace_dir, dumps, streams, fd_state);
  tracer = Alloc<dev::Tracer>(parse_ctx, exec_opts, mutable_opts, mem, trace_f, multi_trace);
  fd_state->tracer = tracer;
  signal_safe = pyos::InitSignalSafe();
  trap_state = Alloc<trap_osh::TrapState>(signal_safe);
  waiter = Alloc<process::Waiter>(job_list, exec_opts, signal_safe, tracer);
  fd_state->waiter = waiter;
  cmd_deps->debug_f = debug_f;
  now = time_::time();
  iso_stamp = time_::strftime(str2355, time_::localtime(now));
  argv_buf = Alloc<mylib::BufWriter>();
  dev::PrintShellArgv(arg_r->argv, argv_buf);
  debug_f->writeln(StrFormat("%s [%d] Oils started with argv %s", iso_stamp, my_pid, argv_buf->getvalue()));
  if (len(debug_path)) {
    debug_f->writeln(StrFormat("Writing logs to %r", debug_path));
  }
  interp = environ->get(str2358, str2359);
  search_path = Alloc<state::SearchPath>(mem);
  ext_prog = Alloc<process::ExternalProgram>(interp, fd_state, errfmt, debug_f);
  splitter = Alloc<split::SplitContext>(mem);
  globber = Alloc<glob_::Globber>(exec_opts);
  crash_dump_dir = environ->get(str2360, str2361);
  cmd_deps->dumper = Alloc<dev::CrashDumper>(crash_dump_dir, fd_state);
  comp_lookup = Alloc<completion::Lookup>();
  compopt_state = Alloc<completion::OptionState>();
  comp_ui_state = Alloc<comp_ui::State>();
  prompt_state = Alloc<comp_ui::PromptState>();
  tilde_ev = Alloc<word_eval::TildeEvaluator>(mem, exec_opts);
  home_dir = tilde_ev->GetMyHomeDir();
  if (home_dir == nullptr) {
    print_stderr(StrFormat("%s: Failed to get home dir from $HOME or getpwuid()", lang));
    return 1;
  }
  sh_files = Alloc<ShellFiles>(lang, home_dir, mem, flag);
  sh_files->InitAfterLoadingEnv();
  procs = Alloc<Dict<BigStr*, value::Proc*>>();
  builtins = Alloc<Dict<int, vm::_Builtin*>>();
  methods = Alloc<Dict<int, Dict<BigStr*, vm::_Callable*>*>>();
  hay_state = Alloc<hay_ysh::HayState>();
  shell_ex = Alloc<executor::ShellExecutor>(mem, exec_opts, mutable_opts, procs, hay_state, builtins, search_path, ext_prog, waiter, tracer, job_control, job_list, fd_state, trap_state, errfmt);
  arith_ev = Alloc<sh_expr_eval::ArithEvaluator>(mem, exec_opts, mutable_opts, parse_ctx, errfmt);
  bool_ev = Alloc<sh_expr_eval::BoolEvaluator>(mem, exec_opts, mutable_opts, parse_ctx, errfmt);
  expr_ev = Alloc<expr_eval::ExprEvaluator>(mem, mutable_opts, methods, splitter, errfmt);
  word_ev = Alloc<word_eval::NormalWordEvaluator>(mem, exec_opts, mutable_opts, tilde_ev, splitter, errfmt);
  assign_b = InitAssignmentBuiltins(mem, procs, exec_opts, errfmt);
  cmd_ev = Alloc<cmd_eval::CommandEvaluator>(mem, exec_opts, errfmt, procs, assign_b, arena, cmd_deps, trap_state, signal_safe);
  prompt_ev = Alloc<prompt::Evaluator>(lang, version_str, parse_ctx, mem);
  global_io = Alloc<value::IO>(cmd_ev, prompt_ev);
  global_guts = Alloc<value::Guts>(nullptr);
  vm::InitCircularDeps(arith_ev, bool_ev, expr_ev, word_ev, cmd_ev, shell_ex, prompt_ev, global_io, tracer);
  unsafe_arith = Alloc<sh_expr_eval::UnsafeArith>(mem, exec_opts, mutable_opts, parse_ctx, arith_ev, errfmt);
  vm::InitUnsafeArith(mem, word_ev, unsafe_arith);
  b = builtins;
  // if not PYTHON
  {
    help_data = help_meta::TopicMetadata();
  }
  // endif MYCPP
  b->set(builtin_i::help, Alloc<misc_osh::Help>(lang, loader, help_data, errfmt));
  b->set(builtin_i::set, Alloc<pure_osh::Set>(mutable_opts, mem));
  b->set(builtin_i::shopt, Alloc<pure_osh::Shopt>(mutable_opts, cmd_ev));
  b->set(builtin_i::hash, Alloc<pure_osh::Hash>(search_path));
  b->set(builtin_i::trap, Alloc<trap_osh::Trap>(trap_state, parse_ctx, tracer, errfmt));
  b->set(builtin_i::shvar, Alloc<pure_ysh::Shvar>(mem, search_path, cmd_ev));
  b->set(builtin_i::ctx, Alloc<pure_ysh::Ctx>(mem, cmd_ev));
  b->set(builtin_i::push_registers, Alloc<pure_ysh::PushRegisters>(mem, cmd_ev));
  b->set(builtin_i::hay, Alloc<hay_ysh::Hay>(hay_state, mutable_opts, mem, cmd_ev));
  b->set(builtin_i::haynode, Alloc<hay_ysh::HayNode_>(hay_state, mem, cmd_ev));
  b->set(builtin_i::type, Alloc<meta_osh::Type>(procs, aliases, search_path, errfmt));
  b->set(builtin_i::builtin, Alloc<meta_osh::Builtin>(shell_ex, errfmt));
  b->set(builtin_i::command, Alloc<meta_osh::Command>(shell_ex, procs, aliases, search_path));
  b->set(builtin_i::runproc, Alloc<meta_osh::RunProc>(shell_ex, procs, errfmt));
  source_builtin = Alloc<meta_osh::Source>(parse_ctx, search_path, cmd_ev, fd_state, tracer, errfmt, loader);
  b->set(builtin_i::source, source_builtin);
  b->set(builtin_i::dot, source_builtin);
  b->set(builtin_i::eval, Alloc<meta_osh::Eval>(parse_ctx, exec_opts, cmd_ev, tracer, errfmt));
  guards = Alloc<Dict<BigStr*, bool>>();
  b->set(builtin_i::source_guard, Alloc<module_ysh::SourceGuard>(guards, exec_opts, errfmt));
  b->set(builtin_i::is_main, Alloc<module_ysh::IsMain>(mem));
  b->set(builtin_i::use, Alloc<module_ysh::Use>(mem, errfmt));
  b->set(builtin_i::error, Alloc<error_ysh::Error>());
  b->set(builtin_i::failed, Alloc<error_ysh::Failed>(mem));
  b->set(builtin_i::boolstatus, Alloc<error_ysh::BoolStatus>(shell_ex, errfmt));
  b->set(builtin_i::try_, Alloc<error_ysh::Try>(mutable_opts, mem, cmd_ev, shell_ex, errfmt));
  true_ = Alloc<pure_osh::Boolean>(0);
  b->set(builtin_i::colon, true_);
  b->set(builtin_i::true_, true_);
  b->set(builtin_i::false_, Alloc<pure_osh::Boolean>(1));
  b->set(builtin_i::alias, Alloc<pure_osh::Alias>(aliases, errfmt));
  b->set(builtin_i::unalias, Alloc<pure_osh::UnAlias>(aliases, errfmt));
  b->set(builtin_i::getopts, Alloc<pure_osh::GetOpts>(mem, errfmt));
  b->set(builtin_i::shift, Alloc<assign_osh::Shift>(mem));
  b->set(builtin_i::unset, Alloc<assign_osh::Unset>(mem, procs, unsafe_arith, errfmt));
  b->set(builtin_i::append, Alloc<pure_ysh::Append>(mem, errfmt));
  b->set(builtin_i::test, Alloc<bracket_osh::Test>(false, exec_opts, mem, errfmt));
  b->set(builtin_i::bracket, Alloc<bracket_osh::Test>(true, exec_opts, mem, errfmt));
  b->set(builtin_i::echo, Alloc<io_osh::Echo>(exec_opts));
  b->set(builtin_i::printf, Alloc<printf_osh::Printf>(mem, parse_ctx, unsafe_arith, errfmt));
  b->set(builtin_i::write, Alloc<io_ysh::Write>(mem, errfmt));
  b->set(builtin_i::fopen, Alloc<io_ysh::Fopen>(mem, cmd_ev));
  b->set(builtin_i::pp, Alloc<io_ysh::Pp>(mem, errfmt, procs, arena));
  b->set(builtin_i::cat, Alloc<io_osh::Cat>());
  b->set(builtin_i::read, Alloc<read_osh::Read>(splitter, mem, parse_ctx, cmd_ev, errfmt));
  mapfile = Alloc<io_osh::MapFile>(mem, errfmt, cmd_ev);
  b->set(builtin_i::mapfile, mapfile);
  b->set(builtin_i::readarray, mapfile);
  dir_stack = Alloc<dirs_osh::DirStack>();
  b->set(builtin_i::cd, Alloc<dirs_osh::Cd>(mem, dir_stack, cmd_ev, errfmt));
  b->set(builtin_i::pushd, Alloc<dirs_osh::Pushd>(mem, dir_stack, errfmt));
  b->set(builtin_i::popd, Alloc<dirs_osh::Popd>(mem, dir_stack, errfmt));
  b->set(builtin_i::dirs, Alloc<dirs_osh::Dirs>(mem, dir_stack, errfmt));
  b->set(builtin_i::pwd, Alloc<dirs_osh::Pwd>(mem, errfmt));
  b->set(builtin_i::times, Alloc<misc_osh::Times>());
  b->set(builtin_i::json, Alloc<json_ysh::Json>(mem, errfmt, false));
  b->set(builtin_i::json8, Alloc<json_ysh::Json>(mem, errfmt, true));
  b->set(builtin_i::exec_, Alloc<process_osh::Exec>(mem, ext_prog, fd_state, search_path, errfmt));
  b->set(builtin_i::umask, Alloc<process_osh::Umask>());
  b->set(builtin_i::ulimit, Alloc<process_osh::Ulimit>());
  b->set(builtin_i::wait, Alloc<process_osh::Wait>(waiter, job_list, mem, tracer, errfmt));
  b->set(builtin_i::jobs, Alloc<process_osh::Jobs>(job_list));
  b->set(builtin_i::fg, Alloc<process_osh::Fg>(job_control, job_list, waiter));
  b->set(builtin_i::bg, Alloc<process_osh::Bg>(job_list));
  b->set(builtin_i::fork, Alloc<process_osh::Fork>(shell_ex));
  b->set(builtin_i::forkwait, Alloc<process_osh::ForkWait>(shell_ex));
  b->set(builtin_i::bind, Alloc<readline_osh::Bind>(readline, errfmt));
  b->set(builtin_i::history, Alloc<readline_osh::History>(readline, sh_files, errfmt, mylib::Stdout()));
  spec_builder = Alloc<completion_osh::SpecBuilder>(cmd_ev, parse_ctx, word_ev, splitter, comp_lookup, help_data, errfmt);
  complete_builtin = Alloc<completion_osh::Complete>(spec_builder, comp_lookup);
  b->set(builtin_i::complete, complete_builtin);
  b->set(builtin_i::compgen, Alloc<completion_osh::CompGen>(spec_builder));
  b->set(builtin_i::compopt, Alloc<completion_osh::CompOpt>(compopt_state, errfmt));
  b->set(builtin_i::compadjust, Alloc<completion_osh::CompAdjust>(mem));
  comp_ev = Alloc<word_eval::CompletionWordEvaluator>(mem, exec_opts, mutable_opts, tilde_ev, splitter, errfmt);
  comp_ev->arith_ev = arith_ev;
  comp_ev->expr_ev = expr_ev;
  comp_ev->prompt_ev = prompt_ev;
  comp_ev->CheckCircularDeps();
  root_comp = Alloc<completion::RootCompleter>(comp_ev, mem, comp_lookup, compopt_state, comp_ui_state, comp_ctx, debug_f);
  b->set(builtin_i::compexport, Alloc<completion_ysh::CompExport>(root_comp));
  methods->set(value_e::Str, Alloc<Dict<BigStr*, vm::_Callable*>>(std::initializer_list<BigStr*>{str2363, str2364, str2365, str2366, str2367, str2368, str2369, str2370, str2371, str2372, str2373, str2374}, std::initializer_list<vm::_Callable*>{Alloc<method_str::HasAffix>(method_str::START), Alloc<method_str::HasAffix>(method_str::END), Alloc<method_str::Trim>((method_str::START | method_str::END)), Alloc<method_str::Trim>(method_str::START), Alloc<method_str::Trim>(method_str::END), Alloc<method_str::Upper>(), Alloc<method_str::Lower>(), nullptr, Alloc<method_str::Replace>(mem, expr_ev), Alloc<method_str::SearchMatch>(method_str::SEARCH), Alloc<method_str::SearchMatch>(method_str::LEFT_MATCH), nullptr}));
  methods->set(value_e::Dict, Alloc<Dict<BigStr*, vm::_Callable*>>(std::initializer_list<BigStr*>{str2375, str2376, str2377, str2378, str2379, str2380}, std::initializer_list<vm::_Callable*>{nullptr, nullptr, Alloc<method_dict::Keys>(), Alloc<method_dict::Values>(), nullptr, nullptr}));
  methods->set(value_e::List, Alloc<Dict<BigStr*, vm::_Callable*>>(std::initializer_list<BigStr*>{str2381, str2382, str2383, str2384, str2385, str2386, str2387, str2388}, std::initializer_list<vm::_Callable*>{Alloc<method_list::Reverse>(), Alloc<method_list::Append>(), Alloc<method_list::Extend>(), Alloc<method_list::Pop>(), nullptr, nullptr, Alloc<method_list::IndexOf>(), Alloc<func_misc::Join>()}));
  methods->set(value_e::Match, Alloc<Dict<BigStr*, vm::_Callable*>>(std::initializer_list<BigStr*>{str2389, str2390, str2391}, std::initializer_list<vm::_Callable*>{Alloc<func_eggex::MatchMethod>(func_eggex::G, expr_ev), Alloc<func_eggex::MatchMethod>(func_eggex::S, nullptr), Alloc<func_eggex::MatchMethod>(func_eggex::E, nullptr)}));
  methods->set(value_e::IO, Alloc<Dict<BigStr*, vm::_Callable*>>(std::initializer_list<BigStr*>{str2392, str2393, str2394, str2395, str2396}, std::initializer_list<vm::_Callable*>{Alloc<method_io::Eval>(), Alloc<method_io::CaptureStdout>(), Alloc<method_io::PromptVal>(), Alloc<method_io::Time>(), Alloc<method_io::Strftime>()}));
  methods->set(value_e::Place, Alloc<Dict<BigStr*, vm::_Callable*>>(std::initializer_list<BigStr*>{str2397}, std::initializer_list<vm::_Callable*>{Alloc<method_other::SetValue>(mem)}));
  methods->set(value_e::Command, Alloc<Dict<BigStr*, vm::_Callable*>>(std::initializer_list<BigStr*>{str2398}, std::initializer_list<vm::_Callable*>{nullptr}));
  parse_hay = Alloc<func_hay::ParseHay>(fd_state, parse_ctx, errfmt);
  eval_hay = Alloc<func_hay::EvalHay>(hay_state, mutable_opts, mem, cmd_ev);
  hay_func = Alloc<func_hay::HayFunc>(hay_state);
  _SetGlobalFunc(mem, str2399, parse_hay);
  _SetGlobalFunc(mem, str2400, eval_hay);
  _SetGlobalFunc(mem, str2401, hay_func);
  _SetGlobalFunc(mem, str2402, Alloc<func_misc::Len>());
  _SetGlobalFunc(mem, str2403, Alloc<func_misc::Type>());
  _SetGlobalFunc(mem, str2404, Alloc<func_misc::Repeat>());
  g = Alloc<func_eggex::MatchFunc>(func_eggex::G, expr_ev, mem);
  _SetGlobalFunc(mem, str2405, g);
  _SetGlobalFunc(mem, str2406, g);
  _SetGlobalFunc(mem, str2407, Alloc<func_eggex::MatchFunc>(func_eggex::S, nullptr, mem));
  _SetGlobalFunc(mem, str2408, Alloc<func_eggex::MatchFunc>(func_eggex::E, nullptr, mem));
  _SetGlobalFunc(mem, str2409, Alloc<func_misc::Join>());
  _SetGlobalFunc(mem, str2410, Alloc<func_misc::Maybe>());
  _SetGlobalFunc(mem, str2411, Alloc<func_misc::EvalExpr>(expr_ev));
  _SetGlobalFunc(mem, str2412, Alloc<func_misc::Bool>());
  _SetGlobalFunc(mem, str2413, Alloc<func_misc::Int>());
  _SetGlobalFunc(mem, str2414, Alloc<func_misc::Float>());
  _SetGlobalFunc(mem, str2415, Alloc<func_misc::Str_>());
  _SetGlobalFunc(mem, str2416, Alloc<func_misc::List_>());
  _SetGlobalFunc(mem, str2417, Alloc<func_misc::Dict_>());
  _SetGlobalFunc(mem, str2418, Alloc<func_misc::Runes>());
  _SetGlobalFunc(mem, str2419, Alloc<func_misc::EncodeRunes>());
  _SetGlobalFunc(mem, str2420, Alloc<func_misc::Bytes>());
  _SetGlobalFunc(mem, str2421, Alloc<func_misc::EncodeBytes>());
  _SetGlobalFunc(mem, str2422, Alloc<func_misc::Split>(splitter));
  _SetGlobalFunc(mem, str2423, Alloc<func_misc::Split>(splitter));
  _SetGlobalFunc(mem, str2424, Alloc<func_misc::Glob>(globber));
  _SetGlobalFunc(mem, str2425, Alloc<func_misc::Shvar_get>(mem));
  _SetGlobalFunc(mem, str2426, Alloc<func_misc::GetVar>(mem));
  _SetGlobalFunc(mem, str2427, Alloc<func_misc::Assert>());
  _SetGlobalFunc(mem, str2428, Alloc<func_misc::ToJson8>(true));
  _SetGlobalFunc(mem, str2429, Alloc<func_misc::ToJson8>(false));
  _SetGlobalFunc(mem, str2430, Alloc<func_misc::FromJson8>(true));
  _SetGlobalFunc(mem, str2431, Alloc<func_misc::FromJson8>(false));
  _SetGlobalFunc(mem, str2432, Alloc<func_misc::BashArrayToSparse>());
  _SetGlobalFunc(mem, str2433, Alloc<func_misc::DictToSparse>());
  _SetGlobalFunc(mem, str2434, Alloc<func_misc::SparseOp>());
  mem->SetNamed(location::LName(str2435), global_io, scope_e::GlobalOnly);
  mem->SetNamed(location::LName(str2436), global_guts, scope_e::GlobalOnly);
  mem->SetNamed(location::LName(str2437), value::Stdin, scope_e::GlobalOnly);
  hist_ev = Alloc<history::Evaluator>(readline, hist_ctx, debug_f);
  if (flag->c != nullptr) {
    src = source::CFlag;
    line_reader = reader::StringLineReader(flag->c, arena);
    if (flag->i) {
      mutable_opts->set_interactive();
    }
  }
  else {
    if (flag->i) {
      src = Alloc<source::Stdin>(str2438);
      line_reader = Alloc<reader::InteractiveLineReader>(arena, prompt_ev, hist_ev, readline, prompt_state);
      mutable_opts->set_interactive();
    }
    else {
      if (script_name == nullptr) {
        if (flag->headless) {
          src = source::Headless;
          line_reader = nullptr;
        }
        else {
          stdin_ = mylib::Stdin();
          if ((len(flag->tool) == 0 and stdin_->isatty())) {
            src = source::Interactive;
            line_reader = Alloc<reader::InteractiveLineReader>(arena, prompt_ev, hist_ev, readline, prompt_state);
            mutable_opts->set_interactive();
          }
          else {
            src = Alloc<source::Stdin>(str2439);
            line_reader = Alloc<reader::FileLineReader>(stdin_, arena);
          }
        }
      }
      else {
        src = Alloc<source::MainFile>(script_name);
        try {
          f = fd_state->Open(script_name);
        }
        catch (IOError_OSError* e) {
          print_stderr(StrFormat("%s: Couldn't open %r: %s", lang, script_name, posix::strerror(e->errno_)));
          return 1;
        }
        line_reader = Alloc<reader::FileLineReader>(f, arena);
      }
    }
  }
  if (flag->location_str != nullptr) {
    src = Alloc<source::Synthetic>(flag->location_str);
    location_start_line = mops::BigTruncate(flag->location_start_line);
    if (location_start_line != -1) {
      line_reader->SetLineOffset(location_start_line);
    }
  }
  arena->PushSource(src);
  config_dir = str2441;
  rc_paths = Alloc<List<BigStr*>>();
  if ((!flag->norc and (flag->headless or exec_opts->interactive()))) {
    rc_path = flag->rcfile;
    if (rc_path == nullptr) {
      rc_paths->append(os_path::join(home_dir, StrFormat("%s/%src", config_dir, lang)));
    }
    else {
      rc_paths->append(rc_path);
    }
    rc_dir = flag->rcdir;
    if (rc_dir == nullptr) {
      rc_dir = os_path::join(home_dir, StrFormat("%s/%src.d", config_dir, lang));
    }
    rc_paths->extend(libc::glob(os_path::join(rc_dir, str2444)));
  }
  else {
    if (flag->rcfile != nullptr) {
      print_stderr(StrFormat("%s warning: --rcfile ignored with --norc", lang));
    }
    if (flag->rcdir != nullptr) {
      print_stderr(StrFormat("%s warning: --rcdir ignored with --norc", lang));
    }
  }
  _InitDefaultCompletions(cmd_ev, complete_builtin, comp_lookup);
  if (flag->headless) {
    state::InitInteractive(mem);
    mutable_opts->set_redefine_proc_func();
    mutable_opts->set_redefine_module();
    for (ListIter<BigStr*> it(rc_paths); !it.Done(); it.Next()) {
      BigStr* rc_path = it.Value();
      StackRoot _for(&rc_path    );
      {  // with
        state::ctx_ThisDir ctx{mem, rc_path};

        try {
          SourceStartupFile(fd_state, rc_path, lang, parse_ctx, cmd_ev, errfmt);
        }
        catch (util::UserExit* e) {
          return e->status;
        }
      }
    }
    loop = Alloc<main_loop::Headless>(cmd_ev, parse_ctx, errfmt);
    try {
      status = loop->Loop();
    }
    catch (util::UserExit* e) {
      status = e->status;
    }
    mut_status = Alloc<IntParamBox>(status);
    cmd_ev->MaybeRunExitTrap(mut_status);
    status = mut_status->i;
    return status;
  }
  c_parser = parse_ctx->MakeOshParser(line_reader);
  if (exec_opts->interactive()) {
    state::InitInteractive(mem);
    mutable_opts->set_emacs();
    mutable_opts->set_redefine_proc_func();
    mutable_opts->set_redefine_module();
    if (readline) {
      term_width = 0;
      if (maybe_str_equals(flag->completion_display, str2447)) {
        try {
          term_width = libc::get_terminal_width();
        }
        catch (IOError_OSError*) {
          ;  // pass
        }
      }
      if (term_width != 0) {
        display = Alloc<comp_ui::NiceDisplay>(term_width, comp_ui_state, prompt_state, debug_f, readline, signal_safe);
      }
      else {
        display = Alloc<comp_ui::MinimalDisplay>(comp_ui_state, prompt_state, debug_f);
      }
      comp_ui::InitReadline(readline, sh_files->HistoryFile(), root_comp, display, debug_f);
      _InitDefaultCompletions(cmd_ev, complete_builtin, comp_lookup);
      if (flag->completion_demo) {
        _CompletionDemo(comp_lookup);
      }
    }
    else {
      display = Alloc<comp_ui::MinimalDisplay>(comp_ui_state, prompt_state, debug_f);
    }
    process::InitInteractiveShell();
    {  // with
      process::ctx_TerminalControl ctx{job_control, errfmt};

      for (ListIter<BigStr*> it(rc_paths); !it.Done(); it.Next()) {
        BigStr* rc_path = it.Value();
        StackRoot _for(&rc_path      );
        {  // with
          state::ctx_ThisDir ctx{mem, rc_path};

          try {
            SourceStartupFile(fd_state, rc_path, lang, parse_ctx, cmd_ev, errfmt);
          }
          catch (util::UserExit* e) {
            return e->status;
          }
        }
      }
      line_reader->Reset();
      prompt_plugin = Alloc<prompt::UserPlugin>(mem, parse_ctx, cmd_ev, errfmt);
      try {
        status = main_loop::Interactive(flag, cmd_ev, c_parser, display, prompt_plugin, waiter, errfmt);
      }
      catch (util::UserExit* e) {
        status = e->status;
      }
      mut_status = Alloc<IntParamBox>(status);
      cmd_ev->MaybeRunExitTrap(mut_status);
      status = mut_status->i;
    }
    if (readline) {
      hist_file = sh_files->HistoryFile();
      if (hist_file != nullptr) {
        try {
          readline->write_history_file(hist_file);
        }
        catch (IOError_OSError*) {
          ;  // pass
        }
      }
    }
    return status;
  }
  if (flag->rcfile != nullptr) {
    print_stderr(StrFormat("%s warning: --rcfile ignored in non-interactive shell", lang));
  }
  if (flag->rcdir != nullptr) {
    print_stderr(StrFormat("%s warning: --rcdir ignored in non-interactive shell", lang));
  }
  tool_name = exec_opts->noexec() ? str2450 : flag->tool;
  if (len(tool_name)) {
    if (!(maybe_str_equals(tool_name, str2451))) {
      arena->SaveTokens();
    }
    try {
      node = main_loop::ParseWholeFile(c_parser);
    }
    catch (error::Parse* e) {
      errfmt->PrettyPrintError(e);
      return 2;
    }
    if (maybe_str_equals(tool_name, str2452)) {
      ui::PrintAst(node, flag);
    }
    else {
      if (maybe_str_equals(tool_name, str2453)) {
        ysh_ify::PrintTokens(arena);
      }
      else {
        if (maybe_str_equals(tool_name, str2454)) {
          ysh_ify::LosslessCat(arena);
        }
        else {
          if (maybe_str_equals(tool_name, str2455)) {
            fmt::Format(arena, node);
          }
          else {
            if (maybe_str_equals(tool_name, str2456)) {
              assert(0);  // AssertionError
            }
            else {
              if (maybe_str_equals(tool_name, str2458)) {
                ysh_ify::Ysh_ify(arena, node);
              }
              else {
                if (maybe_str_equals(tool_name, str2459)) {
                }
                else {
                  assert(0);  // AssertionError
                }
              }
            }
          }
        }
      }
    }
    return 0;
  }
  {  // with
    state::ctx_ThisDir ctx{mem, script_name};

    try {
      status = main_loop::Batch(cmd_ev, c_parser, errfmt, cmd_eval::IsMainProgram);
    }
    catch (util::UserExit* e) {
      status = e->status;
    }
  }
  mut_status = Alloc<IntParamBox>(status);
  cmd_ev->MaybeRunExitTrap(mut_status);
  multi_trace->WriteDumps();
  return mut_status->i;
}

}  // define namespace shell

int main(int argc, char **argv) {
  mylib::InitCppOnly();  // Initializes gHeap

  auto* args = Alloc<List<BigStr*>>();
  for (int i = 0; i < argc; ++i) {
    args->append(StrFromC(argv[i]));
  }

  int status = oils_for_unix::main(args);

  gHeap.ProcessExit();

  return status;
}
