/* $Id: error.c,v 1.3 2008/11/03 22:57:08 kiesling Exp $ */

/*
  This file is part of ctalk.
  Copyright © 2005-2008 Robert Kiesling, ctalk@ctalklang.org.
  Permission is granted to copy this software provided that this copyright
  notice is included in all source code modules.

  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 2 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, write to the Free Software Foundation, 
  Inc., 51 Franklin St., Fifth Floor, Boston, MA 02110-1301 USA.
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <errno.h>
#include "object.h"
#include "message.h"
#include "ctalk.h"

extern char appname[];                 /* Declared in main.c.         */
extern char input_source_file[];
extern I_PASS interpreter_pass;
extern int error_line, error_column;   /* Declared in errorloc.c.     */

extern int library_input;              /* Declared in class.c.        */

/* Library prototypes. */
extern char *_format_str (char *, char *, va_list);
extern void _error (char *,...);
extern void _error_out (char *);
extern void _warning (char *,...);

/*
 *  Return the name of the source file depending on which
 *  pass the interpreter is in.
 */

char *source_filename (void) {

  static char fn[FILENAME_MAX];

  switch (interpreter_pass)
    {
    case preprocessing_pass:
      strcpy (fn, __source_filename ());
      break;
    case var_pass:
    case parsing_pass:
    case c_fn_pass:
    case expr_check:
      strcpy (fn, __source_filename ());
      break;
    case library_pass:
    case method_pass:
      if (library_input)
	strcpy (fn, library_pathname ());
      else
	strcpy (fn, __source_filename ());
      break;
    case run_time_pass:
      break;
    default:
      break;
    }

  return fn;
}

/*
 *  Exit with an error.  The _error () function doesn't return, so
 *  perform file cleanup first.
 */

void error (MESSAGE *orig, char *fmt,...) {
  va_list ap;
  char fmtbuf[MAXMSG];

  cleanup (TRUE);

  va_start (ap, fmt);
  _error ("%s:%d. %s\n", source_filename (), orig -> error_line, 
	  _format_str (fmtbuf, fmt, ap));
}

void warning (MESSAGE *orig, char *fmt,...) {
  va_list ap;
  char fmtbuf[MAXMSG];

  va_start (ap, fmt);
  _warning ("%s:%d: Warning: %s\n", source_filename (),
	    orig -> error_line, _format_str (fmtbuf, fmt, ap));
}

#ifdef DEBUG_CODE
void debug (char *fmt,...) {
  va_list ap;
  char fmtbuf[MAXMSG];
  va_start (ap, fmt);
  _warning ("%s\n", _format_str (fmtbuf, fmt, ap));
}
#endif

void fn_check_expr (MESSAGE_STACK messages, int fn_idx, int stack_start,
		    int main_stack_idx) {
  int prev_tok_idx, prev_tok;
  MESSAGE *m_orig;
  if ((prev_tok_idx = prevlangmsg (messages, fn_idx)) != ERROR) {
    if (prev_tok_idx >= stack_start)
      return;
    prev_tok = M_TOK(messages[prev_tok_idx]);
    m_orig = message_stack_at (main_stack_idx);
    if (!IS_C_BINARY_MATH_OP(prev_tok) &&
	(prev_tok != OPENPAREN) &&
	(prev_tok != ARGSEPARATOR) &&
	(prev_tok != SEMICOLON)) {
      if (m_orig) {
	warning (message_stack_at (main_stack_idx), 
		 "Function, \"%s,\" in expression is preceded by an invalid token.", 
		 M_NAME(messages[fn_idx]));
      } else {
	_warning 
	  (
   "fn_check_expr: Function, \"%s,\" in expression is preceded by an invalid token.\n", 
		 M_NAME(messages[fn_idx]));
      }
    }
  }
}

