/* $Id: rt_expr.c,v 1.1.1.1 2008/10/28 13:28:21 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 "object.h"
#include "message.h"
#include "ctalk.h"

/*
 *  Simple or complex expression that should be evaled at run time.
 */
char *fmt_rt_expr (MESSAGE_STACK messages, int start_idx, int *end_idx) {
  static char buf[MAXMSG];
  char *exprbuf, exprbuf_esc[MAXMSG];

  exprbuf = collect_expression (messages, start_idx, end_idx, 
				get_stack_top (messages));
  strcpy (exprbuf_esc, escape_str_quotes (exprbuf));
  free (exprbuf);
  sprintf (buf, "%s(\"%s\")", EVAL_EXPR_FN, exprbuf_esc);
  return buf;
}

char *rt_expr (MESSAGE_STACK messages, int start_idx, int *end_idx) {

  char *exprbuf;
  int i;

  exprbuf = fmt_rt_expr (messages, start_idx, end_idx);
  for (i = start_idx; i >= *end_idx; i--) {
    if (M_TOK(messages[i]) == LABEL) {
      CVAR *__c;
      if (((__c = get_local_var (M_NAME(messages[i]))) != NULL) ||
	  ((__c = get_global_var (M_NAME(messages[i]))) != NULL)) {
	generate_register_c_method_arg_call (__c, M_NAME(messages[i]),
					     LOCAL_VAR,
					     start_idx);
      }

    }
  }
  fileout (exprbuf, 0, start_idx);
  for (i = start_idx; i >= *end_idx; i--) {
    ++messages[i] -> evaled;
    ++messages[i] -> output;
  }
  return exprbuf;
}

static void comma_op_buf (char *s) {
  char *p;
  while ((p = index (s, ';')) != NULL) *p = ',';
  while ((p = index (s, '\n')) != NULL) *p = ' ';
}

/*
 *  Format a run-time expression, for example, a for loop termination
 *  predicate, with CVAR registration function calls if necessary.
 */
char *fmt_libc_fn_rt_expr (MESSAGE_STACK messages, int start_idx, int end_idx) {

  static char buf[MAXMSG];
  char *exprbuf, *c99name,
    fn_call_buf[MAXMSG],
    *cfn_buf;
  int i;
  MESSAGE *m;
  CVAR *cvar;
  CFUNC *fn;

  for (i = start_idx, *buf = 0; i >= end_idx; i--) {

    m = messages[i];

    if (m && M_ISSPACE(m)) continue;

    if (M_TOK(m) == LABEL) {
      if (((cvar = get_local_var (M_NAME(m))) != NULL) ||
	  ((cvar = get_global_var (M_NAME(m))) != NULL)) {
	if ((cvar -> attrs & CVAR_ATTR_FN_DECL) ||
	    (cvar -> attrs & CVAR_ATTR_FN_PTR_DECL) ||
	    (cvar -> attrs & CVAR_ATTR_FN_PROTOTYPE)) {
	  /*
	   *  First check if we have a template for the function.
	   *  If so, insert the template in the output, and if 
	   *  necessary, register the template in the initialization
	   *  (though now the function registration by clib_fn_expr ()
	   *  is handled earlier in ctrlblk_pred_rt_expr ()).
	   *  If there's no template, issue a warning.
	   *
	   *  The function should be able to simply do a token 
	   *  replacement here, but later, it might be necessary
	   *  to set the value object, if we need to rescan the
	   *  message.
	   */
	  if ((c99name = c99_name (M_NAME(m), FALSE)) != NULL) {
	    if ((cfn_buf = clib_fn_rt_expr (messages, i)) != NULL) {
	      free (m -> name);
	      m -> name = strdup (cfn_buf);
	    }
	  }
	} else {
	  sprintf (fn_call_buf, "%s ", 
	   fmt_register_c_method_arg_call (cvar, cvar -> name, LOCAL_VAR));
	  comma_op_buf (fn_call_buf);
	  strcat (buf, fn_call_buf);
	}
      } else {
	if ((fn = get_function (M_NAME(m))) != NULL) {
	  if ((c99name = c99_name (M_NAME(m), FALSE)) != NULL) {
	    if ((cfn_buf = clib_fn_rt_expr (messages, i)) != NULL) {
	      free (m -> name);
	      m -> name = strdup (cfn_buf);
	    }
	  }
	}
      }
    }
  }

  exprbuf = collect_tokens (messages, start_idx, end_idx);
  de_newline_buf (exprbuf);
  sprintf (fn_call_buf, "__ctalkToCInteger (%s, %d)",
 	   fmt_eval_expr (exprbuf), FALSE);
  free (exprbuf);
  strcat (buf, fn_call_buf);

  return buf;
}

/*
 *  This is much simpler than fmt_libc_fn_rt_expr, because user functions
 *  get a template for each occurrence (in fn_tmpl.c), so we don't 
 *  have to worry about registering arguments.  
 */
char *fmt_user_fn_rt_expr (MESSAGE_STACK messages, 
			   int start_idx, int end_idx, char *expr) {
  static char fn_call_buf[MAXMSG];
  char buf[MAXMSG];
  strcpy (buf, expr);
  de_newline_buf (buf);
  sprintf (fn_call_buf, "__ctalkToCInteger (%s, %d)", 
	   fmt_eval_expr (buf), FALSE);
  return fn_call_buf;
}


