/*
 * GNOME Basic Statements
 *
 * Authors:
 *    Jody Goldberg (jgoldberg@home.com)
 *    Ravi Pratap (ravi_pratap@email.com)
 *
 * Copyright 1999,2000, Helix Code, Inc.
 */

#ifndef GB_STATEMENT_H
#define GB_STATEMENT_H

#include "gb.h"
#include "gb-expr.h"
#include "gb-eval.h"

typedef enum
{
    /* specificly use non sequential numbers to allow help
     * track using invalid pointers */
    GBS_ASSIGN = 10, GBS_CALL = 20, GBS_WITH = 30,
    GBS_FOR = 40, GBS_FOREACH = 50,
    GBS_WHILE = 60, GBS_DO = 70,
    GBS_IF = 80, GBS_SELECT = 90,
    GBS_RANDOMIZE = 110, GBS_LOAD = 120, GBS_UNLOAD = 130,
    GBS_OPEN = 140, GBS_INPUT = 150, GBS_LINE_INPUT = 160,
    GBS_CLOSE = 170, GBS_ON_ERROR = 180, GBS_GOTO = 190, GBS_LABEL = 200,
    GBS_GET = 210, GBS_PUT = 220, GBS_SEEK = 230, GBS_PRINT = 240,
    GBS_SET = 250, GBS_REDIM = 280, GBS_EXIT = 290, GBS_ERASE = 300
} GBStatementType;

typedef enum { GB_OPEN_INPUT, GB_OPEN_OUTPUT, GB_OPEN_APPEND, 
	       GB_OPEN_BINARY, GB_OPEN_RANDOM } GBSOpenMode; 

typedef enum { GBS_EXIT_DO, GBS_EXIT_FOR, GBS_EXIT_FUNCTION,
	       GBS_EXIT_PROPERTY, GBS_EXIT_SUB } GBSExitNesting;
 
struct _GBStatement {
	GBStatementType type;
	int             line;
	union
	{
		struct {
			const GBExpr *dest;
			const GBExpr *val;
		} assignment;
		struct {
			const GBExpr *call;
		} func;
		struct {
			const GBExpr *base_obj;
			GSList       *body;
			int           depth;
		} with;
		struct {
			char   const *var;
			const GBExpr *from;
			const GBExpr *to;
			const GBExpr *step;
			GSList       *body;
		} forloop;
		struct {
			const char   *var;
			const GBExpr *collection;
			GSList       *body;
		} foreach;
		struct {
			const GBExpr *expr;
			GSList       *body;
		} do_while;
		struct {
			const GBExpr *condition;
			GSList       *body;
			GSList       *else_body;
		} if_stmt;
		struct {
			const GBExpr *test_expr;
			GSList       *cases;
		} select;
		
		struct {
			const GBExpr *var;
			gboolean      new;
			const GBExpr *objref;
		} set;

		const GBExpr         *randomize;
		const GBExpr         *load;
		const GBExpr         *unload;
		
		/* File handling statements */
		struct {
			const GBExpr *filename;
			GBSOpenMode   mode;
			const GBExpr *handle;
			const GBExpr *recordlen;
		} open;
		struct {
			const GBExpr *handle;
			GBExprList   *objrefs;
		} input;
		struct {
			const GBExpr *handle;
			GBExprList   *items;
		} print;
		struct { 
			const GBExpr *handle;
			const GBExpr *objref;
		} line_input;
		struct {
			GBExprList   *handles;
		} close;
		GBOnError             on_error;
		const char           *label;
		struct {
			const GBExpr *handle;
			const GBExpr *recordnum;
			const GBExpr *objref;
		} get;
		struct {
			const GBExpr *handle;
			const GBExpr *recordnum;
			const GBExpr *objref;
		} put;
		struct {
			const GBExpr *handle;
			const GBExpr *pos;
		} seek;
		struct {
			const char   *var_name;
			GSList       *indices;
			gboolean      preserve;
		} redim;
		GBSExitNesting        exit;
		struct {
			const char   *var_name;
		} erase;
	} parm;
};

const GBStatement *gb_stmt_new_assignment (GBParseData *module,
					   const GBExpr *dest,
					   const GBExpr *val);

const GBStatement *gb_stmt_new_call	  (GBParseData *module,
					   const GBExpr *expr);
					

const GBStatement *gb_stmt_new_with	  (GBParseData *module,
					   const GBExpr *base_obj,
					   GSList *statements);

const GBStatement *gb_stmt_new_forloop	  (GBParseData *module,
					   const char *name,
					   const GBExpr *from,
					   const GBExpr *to,
					   const GBExpr *step,
					   GSList *body);

const GBStatement *gb_stmt_new_foreach	  (GBParseData *module,
					   const char *name,
					   const GBExpr *collection,
					   GSList *body);

const GBStatement *gb_stmt_new_do_while   (GBParseData  *module,
					   const GBExpr *while_expr,
					   const GBExpr *until_expr,
					   GSList *body);

const GBStatement *gb_stmt_new_if         (GBParseData *module,
					   GSList *body,
					   GSList *else_body);

const GBStatement *gb_stmt_new_select     (GBParseData  *module,
					   const GBExpr *expr,
					   GSList       *case_stmts);

const GBStatement *gb_stmt_new_set        (GBParseData  *module,
					   const GBExpr *var,
					   gboolean      new,
					   const GBExpr *objref);

const GBStatement *gb_stmt_new_randomize  (GBParseData    *module,
					   const GBExpr   *expr);

const GBStatement *gb_stmt_new_load       (GBParseData    *module, 
					   const GBExpr   *expr);

const GBStatement *gb_stmt_new_unload     (GBParseData    *module,
					   const GBExpr   *expr);

const GBStatement *gb_stmt_new_redim      (GBParseData    *module,
					   const char     *var_name,
					   GSList         *indices,
					   gboolean        preserve);

const GBStatement *gb_stmt_new_erase      (GBParseData    *module,
					   const char     *var_name);

const GBStatement *gb_stmt_new_exit       (GBParseData    *module,
					   GBSExitNesting  exit);

GSList            *gb_stmt_accumulate     (GSList *list,
					   const GBStatement *next);

const GBStatement *gb_stmt_if_set_cond    (const GBStatement *stmt,
					   const GBExpr *condition);

void               gb_stmt_destroy        (GBStatement *stmt);
void               gb_stmts_destroy       (GSList      *stmts);

/* Quick HACK.  Replace this with the various translators */
void gb_stmt_print  (FILE *sink, const GBStatement *stmt);
void gb_stmts_print (FILE *sink,
		     GSList const *stmts, gboolean nest);

/* Select ... Case statement */

struct _GBSelectCase {
	GSList *case_exprs;
	GSList *statements;
};

struct _GBCaseExpr {
	enum { GB_CASE_EXPR, GB_CASE_EXPR_TO_EXPR,
	       GB_CASE_COMPARISON, 
	       GB_CASE_CSV, GB_CASE_ELSE } type;
	union {
		const GBExpr         *expr;
		struct {
			const GBExpr *from;
			const GBExpr *to;
		} expr_to_expr;
		struct {
			GBExprType    op;
			const GBExpr *to;
		} comparison;
		const GBExprList     *exprs;
	} u;
};

GBCaseExpr *gb_select_case_new_expr         (const GBExpr *expr);
					 
GBCaseExpr *gb_select_case_new_expr_to_expr (const GBExpr *from,
					     const GBExpr *to);
					 
GBCaseExpr *gb_select_case_new_comparison   (GBExprType    op,
					     const GBExpr *to);

GBSelectCase *gb_select_case_new            (GSList       *case_exprs,
					     GSList       *statements);

GBSelectCase *gb_select_case_new_else       (GSList       *statements);

/* File handling */

const GBStatement *gb_stmt_new_open           (GBParseData  *module, 
					       const GBExpr *filename,
					       GBSOpenMode   mode,
					       const GBExpr *handle,
					       const GBExpr *recordlen);

const GBStatement *gb_stmt_new_input          (GBParseData  *module,
					       const GBExpr *handle,
					       GBExprList   *objrefs);

const GBStatement *gb_stmt_new_line_input     (GBParseData  *module,
					       const GBExpr *handle,
					       const GBExpr *objref);

const GBStatement *gb_stmt_new_close          (GBParseData  *module,
					       GBExprList   *handles);

const GBStatement *gb_stmt_new_on_error_next  (GBParseData  *module);
const GBStatement *gb_stmt_new_on_error_goto  (GBParseData  *module,
					       const char   *label);

const GBStatement *gb_stmt_new_goto           (GBParseData  *module,
					       const char   *label);

const GBStatement *gb_stmt_new_label          (GBParseData  *module,
					       const char   *label);

const GBStatement *gb_stmt_new_get            (GBParseData  *module, 
					       const GBExpr *handle,
					       const GBExpr *recordnum,
					       const GBExpr *objref);

const GBStatement *gb_stmt_new_put            (GBParseData  *module,
					       const GBExpr *handle,
					       const GBExpr *recordnum,
					       const GBExpr *objref);

const GBStatement *gb_stmt_new_seek           (GBParseData  *module,
					       const GBExpr *handle,
					       const GBExpr *pos);


const GBStatement *gb_stmt_new_print          (GBParseData  *module,
					       const GBExpr *handle,
					       GBExprList   *objrefs);

const char        *gb_stmt_type               (const GBStatement *stmt);

#endif /* GB_STATEMENT_H */
