
/*
 * Copyright (c) 1998 David Stes.
 *
 * This library is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Library 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 Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 * $Id: assoc.m,v 1.17 1998/05/26 13:13:58 stes Exp $
 */

#include "config.h"
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <Object.h>
#include <ocstring.h>
#include <ordcltn.h>
#include <set.h>
#include <dictnary.h>
#include "node.h"
#include "decl.h"
#include "symbol.h"
#include "expr.h"
#include "identxpr.h"
#include "stmt.h"
#include "compstmt.h"
#include "def.h"
#include "datadef.h"
#include "classdef.h"
#include "trlunit.h"
#include "type.h"
#include "util.h"
#include "options.h"

id curcompound;
id curloopcompound;

@implementation CompoundStmt

- (BOOL)iscompstmt
{
  return YES;
}

- lbrace:lb
{
  lbrace = lb;
  return self;
}

- rbrace:rb
{
  rbrace = rb;
  return self;
}

- datadefs:defs
{
  datadefs = defs;
  return self;
}

- stmts:stmtlist
{
  stmts = stmtlist;
  return self;
}

- returnlabel
{
  return returnlabel;
}

- lookupparm:sym
{
  return nil;			/* no parms for compound (unlike BlockExpr) */
}

- synth
{
  int i, n;

  enclosing = curcompound;
  curcompound = self;
  if (o_refcnt)
    returnlabel = [trlunit returnlabel];
  if (!enclosing) {
    restype = [curdef restype];
    parmnames = [curdef parmnames];
    if (o_refcnt)
      for (i = 0, n = [parmnames size]; i < n; i++) {
	id x = [parmnames at:i];

	if ([[curdef lookupparm:x] isid]) {
	  [self addincref:x];
	  [self adddecref:x];
	}
      }
  }
  if (datadefs)
    [datadefs elementsPerform:_cmd];
  if (stmts)
    [stmts elementsPerform:_cmd];
  if (heapvars)
    [self removeheapvarsfromdatadefs];
  if (o_refcnt)
    for (i = 0, n = [locals size]; i < n; i++) {
      id x = [locals at:i];

      if ([[self lookuplocal:x] isid] && ![self isheapvar:x]) {
	[self adddecref:x];	/* works since all locals are nil'ed */
      }
    }
  curcompound = enclosing;
  return self;
}

- gen
{
  if (lbrace)
    [lbrace gen];
  else
    gc('{');
  if (heapvars || tmpvars || icaches || (returnlabel && enclosing == nil))
    gc('\n');
  if (returnlabel && enclosing == nil) {
    gs("int _returnflag = 0;\n");
    if (![restype isvoid]) {
      [restype gendef:s_returnval];
      gs(";\n");
    }
  }
  if (heapvars)
    [self genheapvarptr];
  if (tmpvars)
    gvarlist(tmpvars, "id", (o_refcnt) ? "=(id)0" : "");
  if (icaches)
    gvarlist(icaches, "static struct objcrt_inlineCache", "");
  if (datadefs)
    [datadefs elementsPerform:_cmd];
  if (increfs)
    [self genincrefs];
  if (initializers)
    [initializers elementsPerform:_cmd];
  if (stmts)
    [stmts elementsPerform:_cmd];
  if (returnlabel) {
    gc('\n');
    gs([returnlabel str]);
    gs(":\n");
    if (decrefs)
      [self gendecrefs];
    if (enclosing) {
      gf("if (_returnflag) goto %s;\n", [[enclosing returnlabel] str]);
    } else {
      /* avoid stupid warnings of unused returnflag or no return value */
      if ([restype isvoid])
	gs("if (_returnflag) return;\n");
      else
	gs("if (_returnflag) return _returnval;\n");
      if ([restype isvoid])
	gs("return;\n");
      else
	gs("return _returnval;");
    }
  }
  if (rbrace)
    [rbrace gen];
  else
    gc('}');
  return self;
}

#include "shared.m"

- addheapvarblock:c
{
  if (c == self) {
    return self;
  } else {
    if (enclosing)
      [enclosing addheapvarblock:c];
    return self;
  }
}

- st80
{
  gc('|');
  if (datadefs)
    [datadefs elementsPerform:_cmd];
  gc('|');
  gc('\n');
  if (datadefs)
    [datadefs elementsPerform:@selector(st80inits)];
  [stmts elementsPerform:_cmd];
  return self;
}

@end
 
