//! @file goto.c
//! @author J. Marcel van der Veer
//
//! @section Copyright
//
// This file is part of VIF - vintage FORTRAN compiler.
// Copyright 2020-2025 J. Marcel van der Veer <algol68g@xs4all.nl>.
//
//! @section License
//
// This program is free software; you can redistribute it and/or modify it 
// under the terms of the GNU General Public License as published by the 
// Free Software Foundation; either version 3 of the License, or 
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but 
// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 
// more details. You should have received a copy of the GNU General Public 
// License along with this program. If not, see <http://www.gnu.org/licenses/>.

//! @section Synopsis
//!
//! Compile GOTO.

#include <vif.h>

static LBL *get_label (void) {
  LBL *L = find_label (curlex);
  if (L == NO_LABEL) {
    ERROR (2101, "no such label", curlex);
    return NO_LABEL;
  } else if (L->nonexe) {
    ERROR (2102, "label of non-executable", curlex);
    return NO_LABEL;
  }
  L->jumped++;
  return L;
}

void jump (void)
{
  int_4 rc = scan (EXPECT_LABEL);
  if (rc == LABEL) {
// GOTO label
    LBL *L = get_label ();
    if (L == NO_LABEL) {
      return;
    }
    NEW_RECORD (str);
    _srecordf (str, "goto _l%d;\n", L->num);
    code (nprocs, BODY, str);
    skip_card (FALSE);
  } else if (TOKEN ("(")) {
// GOTO (...), expr
    code (nprocs, BODY, "switch (");
    int_4 apatch = code (nprocs, BODY, NO_TEXT);
    code (nprocs, BODY, ") {\n");
    code (nprocs, BODY, "default:\n");
    rc = scan (EXPECT_LABEL);
    int_4 N = 1;
    while (rc == LABEL) {
      NEW_RECORD (str);
      LBL *L = get_label ();
      if (L == NO_LABEL) {
        return;
      }
      _srecordf (str, "case %d: goto _l%d;\n", N++, L->num);
      code (nprocs, BODY, str);
      rc = scan (EXPECT_NONE);
      if (TOKEN (",")) {
        rc = scan (EXPECT_LABEL);
      }
    };
    CHECKPOINT (2103, ")");
    rc = scan (EXPECT_NONE);
    if (TOKEN (",")) {
      rc = scan (EXPECT_NONE);
    }
    EXPR var;
    macro_depth = 0;
    express (&var, INTEGER, 4);
    patch (apatch, var.str);
    code (nprocs, BODY, "}\n");
    skip_card (FALSE);
  } else if (rc == WORD) {
// GOTO idf [, (...)]
    IDENT *idf = find_local (curlex, NO_MODE);
    if (idf == NO_IDENT ) {
      return;
    }
    if (idf->mode.type != INTEGER) {
      EXPECT (2104, "integer variable");
    }
    NEW_RECORD (str);
    EXPR var; MODE mode;
    var.str[0] = '\0';
    factor_variable (&var, idf, &mode, curlex);
    _srecordf (str, "switch (%s) {\n", var.str);
    code (nprocs, BODY, str);
    code (nprocs, BODY, "default:\n");
    rc = scan (EXPECT_NONE);
    if (TOKEN (",") || TOKEN ("(")) {
  // Emit indicated labels.
      if (TOKEN (",")) {
        rc = scan (EXPECT_NONE);
      }
      CHECKPOINT (2105, "(");
      rc = scan (EXPECT_LABEL);
      while (rc == LABEL) {
        LBL *L = get_label ();
        if (L == NO_LABEL) {
          return;
        }
        _srecordf (str, "case %d: goto _l%d;\n", L->index, L->num);
        code (nprocs, BODY, str);
        rc = scan (EXPECT_LABEL);
        if (TOKEN (",")) {
          rc = scan (EXPECT_LABEL);
        }
      }
      CHECKPOINT (2106, ")");
      code (nprocs, BODY, "}\n");
      skip_card (FALSE);
    } else {
  // Default, emit all labels.
      for (int_4 k = 0; k < nlabels; k++) {
        LBL *L = &labels[k];
        if (! L->nonexe) {
          L->jumped++;
          _srecordf (str, "case %d: goto _l%d;\n", L->index, L->num);
          code (nprocs, BODY, str);
        }
      }
      code (nprocs, BODY, "}\n");
      skip_card (FALSE);
    }
  }
}
