static void cg_one_stmt()

in sources/cg_c.c [6812:6932]


static void cg_one_stmt(ast_node *stmt, ast_node *misc_attrs) {
  // we're going to compute the fragment name if needed but we always start clean
  base_fragment_name = NULL;

  // reset the temp stack
  stack_level = 0;

  symtab_entry *entry = symtab_find(cg_stmts, stmt->type);
  Contract(entry);

  if (!in_proc) {
    // DDL operations not in a procedure are ignored
    // but they can declare schema during the semantic pass
    if (entry->val == cg_any_ddl_stmt) {
       return;
    }

    // loose select statements also have no codegen, the global proc has no result type
    if (is_select_stmt(stmt)) {
       return;
    }
  }


  // don't emit a # line directive for the echo statement because it will messed up
  // if the echo doesn't end in a linefeed and that's legal.  And there is normally
  // no visible code for these things anyway.
  if (!is_ast_echo_stmt(stmt)) {
    charbuf *line_out = (stmt_nesting_level == 1) ? cg_declarations_output : cg_main_output;
    cg_line_directive_min(stmt, line_out);
  }

  CHARBUF_OPEN(tmp_header);
  CHARBUF_OPEN(tmp_declarations);
  CHARBUF_OPEN(tmp_main);
  CHARBUF_OPEN(tmp_scratch);

  charbuf *header_saved = cg_header_output;
  charbuf *declarations_saved = cg_declarations_output;
  charbuf *main_saved = cg_main_output;
  charbuf *scratch_saved = cg_scratch_vars_output;

  // Redirect all output to the temporary buffers so we can see how big it is
  // The comments need to go before this, so we save the output then check it
  // then emit the generated code.

  cg_main_output = &tmp_main;
  cg_declarations_output = &tmp_declarations;
  cg_header_output = &tmp_header;
  cg_scratch_vars_output = &tmp_scratch;

  // These are all the statements there are, we have to find it in this table
  // or else someone added a new statement and it isn't supported yet.
  Invariant(entry);
  ((void (*)(ast_node*))entry->val)(stmt);

  // safe to put it back now
  cg_main_output = main_saved;
  cg_header_output = header_saved;
  cg_declarations_output = declarations_saved;
  cg_scratch_vars_output = scratch_saved;

  // Emit a helpful comment for top level statements.
  if (stmt_nesting_level == 1) {
    charbuf *out = cg_main_output;
    if (is_ast_declare_vars_type(stmt) || is_proc(stmt) || is_ast_echo_stmt(stmt)) {
      out = cg_declarations_output;
    }

    bool_t skip_comment = false;

    // don't contaminate echo output with comments except in test, where we need it for verification
    skip_comment |= (!options.test && is_ast_echo_stmt(stmt));

    // If no code gen in the main buffer, don't add a comment, that will force a global proc
    // We used to have all kinds of special cases to detect the statements that don't generate code
    // and that was a bug farm.  So now instead we just look to see if it made code.  If it didn't make
    // code we will not force the global proc to exist because of the stupid comment...
    skip_comment |= (out == cg_main_output && tmp_main.used == 1);

    // put a line marker in the header file in case we want a test suite that verifies that
    if (options.test) {
      bprintf(cg_header_output, "\n// The statement ending at line %d\n", stmt->lineno);
    }

    // emit comments for most statements: we do not want to require the global proc block
    // just because there was a comment so this is suppressed for "no code" things
    if (!skip_comment) {
      if (options.test) {
        bprintf(out, "\n// The statement ending at line %d\n", stmt->lineno);
      } else {
        bprintf(cg_header_output, "\n// Generated from %s:%d\n", stmt->filename, stmt->lineno);
        bprintf(cg_declarations_output, "\n// Generated from %s:%d\n", stmt->filename, stmt->lineno);
      }
      // emit source comment
      bprintf(out, "\n/*\n");
      CHARBUF_OPEN(tmp);
      gen_stmt_level = 1;
      gen_set_output_buffer(&tmp);
      if (misc_attrs) {
        gen_misc_attrs(misc_attrs);
      }
      gen_one_stmt(stmt);
      cg_remove_slash_star_and_star_slash(&tmp); // internal "*/" is fatal. "/*" can also be under certain compilation flags
      bprintf(out, "%s", tmp.ptr);
      CHARBUF_CLOSE(tmp);
      bprintf(out, ";\n*/\n");
    }
  }

  // and finally write what we saved
  bprintf(cg_main_output, "%s", tmp_main.ptr);
  bprintf(cg_header_output, "%s", tmp_header.ptr);
  bprintf(cg_scratch_vars_output, "%s", tmp_scratch.ptr);
  bprintf(cg_declarations_output, "%s", tmp_declarations.ptr);

  CHARBUF_CLOSE(tmp_scratch);
  CHARBUF_CLOSE(tmp_main);
  CHARBUF_CLOSE(tmp_declarations);
  CHARBUF_CLOSE(tmp_header);
}