<commit_before>package c99.parser;

import java.util.Collection;

import c99.*;
import c99.Types.*;
import c99.parser.tree.*;

import static c99.parser.Trees.*;

public class DeclActions extends ExprActions
{
private Scope m_topScope;

protected void init ( CompEnv compEnv, SymTable symTab )
{
  super.init( compEnv, symTab );
}

public final Object FIXME ( String msg )
{
  assert false;
  return null;
}

public final Object FIXME ()
{
  assert false;
  return null;
}

public Scope topScope ()
{
  return m_topScope;
}

public Scope popScope ( Scope scope )
{
  assert m_topScope == scope;
  m_topScope.pop();
  m_topScope = m_topScope.getParent();
  return scope;
}

public Scope pushScope ( Scope.Kind kind )
{
  return m_topScope = new Scope( kind, m_topScope );
}

public final String stringLiteralString ( CParser.Location loc, TStringLiteral lit )
{
  return Utils.asciiString(lit.value);
}

public final TExtAttr extAttr (
  CParser.Location locAll, CParser.Location locName, String name, TreeList params
)
{
  ExtAttrDef def;
  if ((def = m_plat.findExtAttr(name)) == null)
  {
    error( locName, "unknown attribute '%s'", name );
    return null;
  }
  SourceRange rngAll = BisonLexer.fromLocation(locAll);
  ExtAttr extAttr = m_plat.parseExtAttr(
    rngAll, BisonLexer.fromLocation(locName), def, params
  );
  if (extAttr == null)
    return null;
  return new TExtAttr(rngAll, extAttr);
}

public final TExtAttrList extAttrList ( CParser.Location loc, TExtAttrList list, TExtAttr attr )
{
  if (attr != null)
  {
    if (list == null)
      list = new TExtAttrList();
    list.add( attr );
  }
  return list;
}

public final TSpecNode specExtAttr ( CParser.Location loc, TExtAttrList attrList )
{
  if (attrList != null && attrList.size() > 0)
    return BisonLexer.setLocation(new TSpecAttrNode(null, attrList), loc);
  else
    return null;
}

public final TSpecNode spec ( CParser.Location loc, Code code )
{
  return BisonLexer.setLocation(new TSpecNode( null, code ), loc);
}

public final TSpecNode specTypename ( CParser.Location loc, Decl decl )
{
  return BisonLexer.setLocation( new TSpecDeclNode( null, Code.TYPENAME, decl ), loc );
}

private final Spec referenceAgg ( TSpecAggNode node )
{
  final Decl tagDecl;
  final TypeSpec tagSpec = node.code == Code.STRUCT ? TypeSpec.STRUCT : TypeSpec.UNION;
  boolean fwdDecl = false;

  assert node.identTree != null;
  final Symbol ident = node.identTree.ident;
  if (ident.topTag != null)
  {
    if (ident.topTag.type.spec.type == tagSpec)
    {
      tagDecl = ident.topTag; // Return the existing tag
    }
    else
    {
      error( node.identTree, "'%s %s' previously defined as a different kind of tag here: %s",
             node.code.str, ident.name, SourceRange.formatRange( ident.topTag ) );

      // Error recovery: return an anonymous tag
      Spec spec = new StructUnionSpec( tagSpec, null );
      tagDecl = new Decl( node, Decl.Kind.TAG, m_topScope, SClass.NONE, Linkage.NONE,
                          null, new Qual( spec ), false, true );
      fwdDecl = true;
    }
  }
  else
  {
    // Forward declaration of tag
    fwdDecl = true;
    Spec spec = new StructUnionSpec( tagSpec, ident );
    tagDecl = new Decl( node.identTree, Decl.Kind.TAG, m_topScope, SClass.NONE, Linkage.NONE,
                        ident, new Qual( spec ), false, false );
    m_topScope.pushTag( tagDecl );
    if (m_topScope.kind == Scope.Kind.PARAM)
      warning( tagDecl, "declaration of '%s' will not be visible outside of the function", spec.readableType() );
  }

  if (fwdDecl)
    m_compEnv.visitor.visitRecordDecl( node, tagDecl, false );
  return tagDecl.type.spec;
}

private final Spec declareAgg ( TSpecAggNode node )
{
  if (node.memberScope == null)
    return referenceAgg( node );

  final TypeSpec tagSpec = node.code == Code.STRUCT ? TypeSpec.STRUCT : TypeSpec.UNION;

  Decl tagDecl = null;
  Symbol ident = node.identTree.ident;
  boolean haveErr = node.memberScope.error;

  // Check for redefinition: it must have been defined in the current scope
  if (ident != null && ident.topTag != null && ident.topTag.scope == m_topScope)
  {
    if (ident.topTag.type.spec.type == tagSpec)
    {
      final StructUnionSpec prevSpec = (StructUnionSpec)ident.topTag.type.spec;

      if (prevSpec.isComplete()) // Already defined?
      {
        error( node.identTree, "redefinition of '%s %s'. originally defined here: %s",
               node.code.str, ident.name, SourceRange.formatRange( ident.topTag ) );

        // Error recovery: make the aggregate anonymous
        ident = null;
        haveErr = true;
      }
      else
        tagDecl = ident.topTag; // We will complete the existing forward declaration
    }
    else
    {
      error( node.identTree, "'%s %s' previously defined as a different kind of tag here: %s",
             node.code.str, ident.name, SourceRange.formatRange( ident.topTag ) );

      // Error recovery: make the aggregate anonymous
      ident = null;
      haveErr = true;
    }
  }

  final SourceRange rng = node.identTree != null ? node.identTree : node;

  if (tagDecl == null) // If not completing a previous forward declaration
  {
    Spec spec = new StructUnionSpec( tagSpec, ident );
    tagDecl = new Decl( node, Decl.Kind.TAG, m_topScope, SClass.NONE, Linkage.NONE, ident,
                        new Qual( spec ), true, haveErr );
    m_topScope.pushTag( tagDecl );
    if (m_topScope.kind == Scope.Kind.PARAM)
      warning( rng, "declaration of '%s' will not be visible outside of the function", spec.readableType() );
  }

  tagDecl.defined = true;

  // Update the location to this one in all cases
  tagDecl.setRange( rng );

  final StructUnionSpec spec = (StructUnionSpec)tagDecl.type.spec;
  final Collection<Decl> decls = node.memberScope.decls();

  assert !spec.isComplete();
  Member[] fields = new Member[decls.size()];

  int i = 0;
  for ( Decl d : decls )
  {
    fields[i++] = new Member( d, d.symbol, d.type );
    haveErr |= d.error;
  }

  spec.orError( haveErr );
  spec.setFields( fields );
  calcAggSize( spec );

  m_compEnv.visitor.visitRecordDecl( node, tagDecl, true );<commit_msg>DeclActions: fix declaration scope of nested structs<commit_after>package c99.parser;

import java.util.Collection;

import c99.*;
import c99.Types.*;
import c99.parser.tree.*;

import static c99.parser.Trees.*;

public class DeclActions extends ExprActions
{
private Scope m_topScope;

protected void init ( CompEnv compEnv, SymTable symTab )
{
  super.init( compEnv, symTab );
}

public final Object FIXME ( String msg )
{
  assert false;
  return null;
}

public final Object FIXME ()
{
  assert false;
  return null;
}

public Scope topScope ()
{
  return m_topScope;
}

public Scope popScope ( Scope scope )
{
  assert m_topScope == scope;
  m_topScope.pop();
  m_topScope = m_topScope.getParent();
  return scope;
}

public Scope pushScope ( Scope.Kind kind )
{
  return m_topScope = new Scope( kind, m_topScope );
}

private final Scope topNonStructScope ()
{
  Scope res = m_topScope;
  while (res.kind == Scope.Kind.AGGREGATE)
    res = res.getParent();
  return res;
}

public final String stringLiteralString ( CParser.Location loc, TStringLiteral lit )
{
  return Utils.asciiString(lit.value);
}

public final TExtAttr extAttr (
  CParser.Location locAll, CParser.Location locName, String name, TreeList params
)
{
  ExtAttrDef def;
  if ((def = m_plat.findExtAttr(name)) == null)
  {
    error( locName, "unknown attribute '%s'", name );
    return null;
  }
  SourceRange rngAll = BisonLexer.fromLocation(locAll);
  ExtAttr extAttr = m_plat.parseExtAttr(
    rngAll, BisonLexer.fromLocation(locName), def, params
  );
  if (extAttr == null)
    return null;
  return new TExtAttr(rngAll, extAttr);
}

public final TExtAttrList extAttrList ( CParser.Location loc, TExtAttrList list, TExtAttr attr )
{
  if (attr != null)
  {
    if (list == null)
      list = new TExtAttrList();
    list.add( attr );
  }
  return list;
}

public final TSpecNode specExtAttr ( CParser.Location loc, TExtAttrList attrList )
{
  if (attrList != null && attrList.size() > 0)
    return BisonLexer.setLocation(new TSpecAttrNode(null, attrList), loc);
  else
    return null;
}

public final TSpecNode spec ( CParser.Location loc, Code code )
{
  return BisonLexer.setLocation(new TSpecNode( null, code ), loc);
}

public final TSpecNode specTypename ( CParser.Location loc, Decl decl )
{
  return BisonLexer.setLocation( new TSpecDeclNode( null, Code.TYPENAME, decl ), loc );
}

private final Spec referenceAgg ( TSpecAggNode node )
{
  final Decl tagDecl;
  final TypeSpec tagSpec = node.code == Code.STRUCT ? TypeSpec.STRUCT : TypeSpec.UNION;
  boolean fwdDecl = false;
  final Scope declScope = topNonStructScope(); // a forward decl would go in this scope

  assert node.identTree != null;
  final Symbol ident = node.identTree.ident;
  if (ident.topTag != null)
  {
    if (ident.topTag.type.spec.type == tagSpec)
    {
      tagDecl = ident.topTag; // Return the existing tag
    }
    else
    {
      error( node.identTree, "'%s %s' previously defined as a different kind of tag here: %s",
             node.code.str, ident.name, SourceRange.formatRange( ident.topTag ) );

      // Error recovery: return an anonymous tag
      Spec spec = new StructUnionSpec( tagSpec, null );
      tagDecl = new Decl( node, Decl.Kind.TAG, declScope, SClass.NONE, Linkage.NONE,
                          null, new Qual( spec ), false, true );
      fwdDecl = true;
    }
  }
  else
  {
    // Forward declaration of tag
    fwdDecl = true;
    Spec spec = new StructUnionSpec( tagSpec, ident );
    tagDecl = new Decl( node.identTree, Decl.Kind.TAG, declScope, SClass.NONE, Linkage.NONE,
                        ident, new Qual( spec ), false, false );
    declScope.pushTag( tagDecl );
    if (declScope.kind == Scope.Kind.PARAM)
      warning( tagDecl, "declaration of '%s' will not be visible outside of the function", spec.readableType() );
  }

  if (fwdDecl)
    m_compEnv.visitor.visitRecordDecl( node, tagDecl, false );
  return tagDecl.type.spec;
}

private final Spec declareAgg ( TSpecAggNode node )
{
  if (node.memberScope == null)
    return referenceAgg( node );

  final TypeSpec tagSpec = node.code == Code.STRUCT ? TypeSpec.STRUCT : TypeSpec.UNION;
  final Scope declScope = topNonStructScope(); // a forward decl would go in this scope

  Decl tagDecl = null;
  Symbol ident = node.identTree.ident;
  boolean haveErr = node.memberScope.error;

  // Check for redefinition: it must have been defined in the current scope
  if (ident != null && ident.topTag != null && ident.topTag.scope == declScope)
  {
    if (ident.topTag.type.spec.type == tagSpec)
    {
      final StructUnionSpec prevSpec = (StructUnionSpec)ident.topTag.type.spec;

      if (prevSpec.isComplete()) // Already defined?
      {
        error( node.identTree, "redefinition of '%s %s'. originally defined here: %s",
               node.code.str, ident.name, SourceRange.formatRange( ident.topTag ) );

        // Error recovery: make the aggregate anonymous
        ident = null;
        haveErr = true;
      }
      else
        tagDecl = ident.topTag; // We will complete the existing forward declaration
    }
    else
    {
      error( node.identTree, "'%s %s' previously defined as a different kind of tag here: %s",
             node.code.str, ident.name, SourceRange.formatRange( ident.topTag ) );

      // Error recovery: make the aggregate anonymous
      ident = null;
      haveErr = true;
    }
  }

  final SourceRange rng = node.identTree != null ? node.identTree : node;

  if (tagDecl == null) // If not completing a previous forward declaration
  {
    Spec spec = new StructUnionSpec( tagSpec, ident );
    tagDecl = new Decl( node, Decl.Kind.TAG, declScope, SClass.NONE, Linkage.NONE, ident,
                        new Qual( spec ), true, haveErr );
    declScope.pushTag( tagDecl );
    if (declScope.kind == Scope.Kind.PARAM)
      warning( rng, "declaration of '%s' will not be visible outside of the function", spec.readableType() );
  }

  tagDecl.defined = true;

  // Update the location to this one in all cases
  tagDecl.setRange( rng );

  final StructUnionSpec spec = (StructUnionSpec)tagDecl.type.spec;
  final Collection<Decl> decls = node.memberScope.decls();

  assert !spec.isComplete();
  Member[] fields = new Member[decls.size()];

  int i = 0;
  for ( Decl d : decls )
  {
    fields[i++] = new Member( d, d.symbol, d.type );
    haveErr |= d.error;
  }

  spec.orError( haveErr );
  spec.setFields( fields );
  calcAggSize( spec );

  m_compEnv.visitor.visitRecordDecl( node, tagDecl, true );
{'fraction_non_alphanumeric': 0.11055831951354339, 'fraction_numerical': 0.0018952854773750297, 'mean_word_length': 3.1277705345501956, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '920422', 'n_tokens_mistral': 4076, 'n_tokens_neox': 4000, 'n_words': 1194}