code: def _parse_expression_inputs(expressions):
      """Given a list of string expressions, parse out column names and string
      literals using regex and return a list of lists that contain three items
      in each inner list:
  
      0: the original expression that the user typed
      1: the parsed expression that will be computed
      2: a `dict` of column IDs (`COLUMN0`, `COLUMN1` etc.) to actual column
         names, which will be used by the engine.
      """
      validated_expressions = []
      alias_map = {}
  
      if isinstance(expressions, dict):
          for alias in expressions.keys():
              expression = expressions[alias]
  
              column_id_map = {}
              column_name_map = {}
  
              # we need to be able to modify the running_cidx inside of every call to
              # replacer_fn - must pass by reference unfortunately
              running_cidx = [0]
  
              replacer_fn = partial(
                  _replace_expression_column_name,
                  column_name_map,
                  column_id_map,
                  running_cidx,
              )
  
              parsed = expression
              parsed = re.sub(
                  BOOLEAN_LITERAL_REGEX,
                  lambda match: "True"
                  if match.group(0) == "true"
                  else (
                      "False"
                      if match.group(0) == "false"
                      else match.group(0)
                  ),
                  parsed,
              )
  
              parsed = re.sub(
                  EXPRESSION_COLUMN_NAME_REGEX, replacer_fn, parsed
              )
              parsed = re.sub(
                  STRING_LITERAL_REGEX,
                  lambda match: "intern({0})".format(match.group(0)),
                  parsed,
              )
  
              # remove the `intern()` in bucket and regex functions that take
              # string literal parameters. TODO this logic should be centralized
              # in C++ instead of being duplicated.
              parsed = re.sub(
                  FUNCTION_LITERAL_REGEX,
                  _replace_interned_param,
                  parsed,
              )
              parsed = re.sub(
                  REPLACE_FN_REGEX, _replace_interned_param, parsed
              )
  
              validated = [alias, expression, parsed, column_id_map]
  
              if alias_map.get(alias) is not None:
                  idx = alias_map[alias]
                  validated_expressions[idx] = validated
              else:
                  validated_expressions.append(validated)
                  alias_map[alias] = len(validated_expressions) - 1
      if isinstance(expressions, list):
          for expression in expressions:
              expr_raw = expression
              parsed = expr_raw
              alias_match = re.match(ALIAS_REGEX, expr_raw)
              if alias_match:
                  alias = alias_match.group(1).strip()
              else:
                  alias = expr_raw
  
              if '""' in expr_raw:
                  raise ValueError(
                      "Cannot reference empty column in expression!"
                  )
  
              column_id_map = {}
              column_name_map = {}
  
              # we need to be able to modify the running_cidx inside of every call to
              # replacer_fn - must pass by reference unfortunately
              running_cidx = [0]
  
              replacer_fn = partial(
                  _replace_expression_column_name,
                  column_name_map,
                  column_id_map,
                  running_cidx,
              )
  
              parsed = re.sub(
                  BOOLEAN_LITERAL_REGEX,
                  lambda match: "True"
                  if match.group(0) == "true"
                  else (
                      "False"
                      if match.group(0) == "false"
                      else match.group(0)
                  ),
                  parsed,
              )
  
              parsed = re.sub(
                  EXPRESSION_COLUMN_NAME_REGEX, replacer_fn, parsed
              )
              parsed = re.sub(
                  STRING_LITERAL_REGEX,
                  lambda match: "intern({0})".format(match.group(0)),
                  parsed,
              )
  
              # remove the `intern()` in bucket and regex functions that take
              # string literal parameters. TODO this logic should be centralized
              # in C++ instead of being duplicated.
              parsed = re.sub(
                  FUNCTION_LITERAL_REGEX,
                  _replace_interned_param,
                  parsed,
              )
              parsed = re.sub(
                  REPLACE_FN_REGEX, _replace_interned_param, parsed
              )
  
              validated = [alias, expr_raw, parsed, column_id_map]
  
              if alias_map.get(alias) is not None:
                  idx = alias_map[alias]
                  validated_expressions[idx] = validated
              else:
                  validated_expressions.append(validated)
                  alias_map[alias] = len(validated_expressions) - 1
  
      return validated_expressions
  
file_path: perspective/python/perspective/perspective/table/_utils.py
imports: import re
  from datetime import date, datetime
  from functools import partial
  from .libpsppy import t_dtype
label_desc: Use image node_id 8 for calling a global function with example usage: _parse_expression_inputs(expressions) and returns: validated_expressions