view trunk/src/dil/semantic/Pass1.d @ 683:1ae72234db26

Implemented some methods in SemanticPass1. Renamed Symbol.ident to name. Added a constructor to Symbol. Adapted constructors of classes that inherit from Symbol. Added Alias and OverloadSet Symbol classes. Renamed idents and values to names and inits in VariablesDeclaration.
author Aziz K?ksal <aziz.koeksal@gmail.com>
date Mon, 21 Jan 2008 17:10:12 +0100
parents 6b3e397229c5
children e8c09d13f2a5
line wrap: on
line source

/++
  Author: Aziz Köksal
  License: GPL3
+/
module dil.semantic.Pass1;

import dil.ast.Visitor;
import dil.ast.Node,
       dil.ast.Declarations,
       dil.ast.Expressions,
       dil.ast.Statements,
       dil.ast.Types,
       dil.ast.Parameters;
import dil.lexer.Identifier;
import dil.semantic.Symbol,
       dil.semantic.Symbols,
       dil.semantic.Types,
       dil.semantic.Scope,
       dil.semantic.Module,
       dil.semantic.Analysis;
import dil.Location;
import dil.Information;
import dil.Messages;
import dil.Enums;
import dil.CompilerInfo;
import common;

class SemanticPass1 : Visitor
{
  Scope scop; /// The current scope.
  Module modul; /// The module to be semantically checked.

  // Attributes:
  LinkageType linkageType;
  Protection protection;
  StorageClass storageClass;
  uint alignSize = DEFAULT_ALIGN_SIZE;

  this(Module modul)
  {
    this.modul = modul;
  }

  /// Start semantic analysis.
  void start()
  {
    assert(modul.root !is null);
    // Create module scope.
    scop = new Scope();
    scop.symbol = modul; // Set this module as the scope's symbol.
    scop.infoMan = modul.infoMan;
    visit(modul.root);
  }

  void enterScope(ScopeSymbol s)
  {
    scop = scop.enter(s);
  }

  void exitScope()
  {
    scop = scop.exit();
  }

  /// Insert a symbol into the current scope.
  void insert(Symbol sym, Identifier* ident)
  {
    auto sym2 = scop.symbol.lookup(ident);
    if (sym2)
      reportSymbolConflict(sym, sym2, ident);
    else
      scop.symbol.insert(sym, ident);
    // Set the current scope symbol as the parent.
    sym.parent = scop.symbol;
  }

  /// Insert a symbol, overloading on the name, into the current scope.
  void insertOverload(Symbol sym, Identifier* ident)
  {
    auto sym2 = scop.symbol.lookup(ident);
    if (sym2)
    {
      if (sym2.isOverloadSet)
        (cast(OverloadSet)cast(void*)sym2).add(sym);
      else
        reportSymbolConflict(sym, sym2, ident);
    }
    else
      // Create a new overload set.
      scop.symbol.insert(new OverloadSet(ident, sym.node), ident);
    // Set the current scope symbol as the parent.
    sym.parent = scop.symbol;
  }

  /// Report error: new symbol s1 conflicts with existing symbol s2.
  void reportSymbolConflict(Symbol s1, Symbol s2, Identifier* ident)
  {
    auto loc = s2.node.begin.getErrorLocation();
    auto locString = Format("{}({},{})", loc.filePath, loc.lineNum, loc.colNum);
    error(s1.node.begin, MSG.DeclConflictsWithDecl, ident.str, locString);
  }

  void error(Token* token, char[] formatMsg, ...)
  {
    auto location = token.getErrorLocation();
    auto msg = Format(_arguments, _argptr, formatMsg);
    modul.infoMan ~= new SemanticError(location, msg);
  }

  private alias Declaration D;

override
{
  D visit(CompoundDeclaration d)
  {
    foreach (node; d.children)
    {
      assert(node.category == NodeCategory.Declaration, Format("{}", node));
      visitD(cast(Declaration)cast(void*)node);
    }
    return d;
  }

  D visit(IllegalDeclaration)
  { assert(0, "semantic pass on invalid AST"); return null; }

  D visit(EmptyDeclaration ed)
  { return ed; }

  D visit(ModuleDeclaration)
  { return null; }
  D visit(ImportDeclaration)
  { return null; }

  D visit(AliasDeclaration ad)
  {
    /+
    decl.semantic(scop); // call semantic() or do SA in if statements?
    if (auto fd = TryCast!(FunctionDeclaration)(decl))
    {
      // TODO: do SA here?
    }
    else if (auto vd = TryCast!(VariableDeclaration)(decl))
    {
      // TODO: do SA here?
    }
    +/
    return ad;
  }

  D visit(TypedefDeclaration td)
  {
    /+
    decl.semantic(scop); // call semantic() or do SA in if statements?
    if (auto fd = TryCast!(FunctionDeclaration)(decl))
    {
      // TODO: do SA here?
    }
    else if (auto vd = TryCast!(VariableDeclaration)(decl))
    {
      // TODO: do SA here?
    }
    +/
    return td;
  }

  D visit(EnumDeclaration d)
  {
    // Create the symbol.
    d.symbol = new Enum(d.name, d);
    if (d.name)
    { // Declare named enum.
      insert(d.symbol, d.name);
      enterScope(d.symbol);
    }
    // Declare members.
    foreach (member; d.members)
    {
      auto variable = new Variable(member.name, protection, storageClass, linkageType, member);
      insert(variable, variable.name);
    }
    if (d.name)
      exitScope();
    return d;
  }

  D visit(EnumMemberDeclaration)
  { return null; }

  D visit(ClassDeclaration d)
  {
    if (d.symbol)
      return d;
    d.symbol = new Class(d.name, d);
    // Insert into current scope.
    if (d.tparams)
      insertOverload(d.symbol, d.name);
    else
      insert(d.symbol, d.name);
    enterScope(d.symbol);
    // Continue semantic analysis.
    d.decls && visitD(d.decls);
    exitScope();
    return d;
  }

  D visit(InterfaceDeclaration d)
  {
    if (d.symbol)
      return d;
    d.symbol = new dil.semantic.Symbols.Interface(d.name, d);
    // Insert into current scope.
    if (d.tparams)
      insertOverload(d.symbol, d.name);
    else
      insert(d.symbol, d.name);
    enterScope(d.symbol);
    // Continue semantic analysis.
    d.decls && visitD(d.decls);
    exitScope();
    return d;
  }

  D visit(StructDeclaration d)
  {
    if (d.symbol)
      return d;
    d.symbol = new Struct(d.name, d);
    // Insert into current scope.
    if (d.name)
    {
      if (d.tparams)
        insertOverload(d.symbol, d.name);
      else
        insert(d.symbol, d.name);
    }
    enterScope(d.symbol);
    // Continue semantic analysis.
    d.decls && visitD(d.decls);
    exitScope();
    return d;
  }

  D visit(UnionDeclaration d)
  {
    if (d.symbol)
      return d;
    d.symbol = new Union(d.name, d);
    // Insert into current scope.
    if (d.name)
    {
      if (d.tparams)
        insertOverload(d.symbol, d.name);
      else
        insert(d.symbol, d.name);
    }
    enterScope(d.symbol);
    // Continue semantic analysis.
    d.decls && visitD(d.decls);
    exitScope();
    return d;
  }

  D visit(ConstructorDeclaration)
  { return null; }
  D visit(StaticConstructorDeclaration)
  { return null; }
  D visit(DestructorDeclaration)
  { return null; }
  D visit(StaticDestructorDeclaration)
  { return null; }
  D visit(FunctionDeclaration)
  { return null; }

  D visit(VariablesDeclaration vd)
  {
    // Error if we are in an interface.
    if (scop.isInterface)
      return error(vd.begin, MSG.InterfaceCantHaveVariables), vd;

    // Insert variable symbols in this declaration into the symbol table.
    foreach (name; vd.names)
    {
      auto variable = new Variable(name, protection, storageClass, linkageType, vd);
      vd.variables ~= variable;
      insert(variable, name);
    }
    return vd;
  }

  D visit(InvariantDeclaration)
  { return null; }
  D visit(UnittestDeclaration)
  { return null; }
  D visit(DebugDeclaration)
  { return null; }
  D visit(VersionDeclaration)
  { return null; }

  D visit(StaticIfDeclaration d)
  {
    visitE(d.condition);
    visitD(d.ifDecls);
    d.elseDecls && visitD(d.elseDecls);
    return null;
  }

  D visit(StaticAssertDeclaration d)
  { return d; } // SP2

  D visit(TemplateDeclaration d)
  {
    if (d.symbol)
      return d;
    d.symbol = new Template(d.name, d);
    // Insert into current scope.
    insertOverload(d.symbol, d.name);
    enterScope(d.symbol);
    // Continue semantic analysis.
    visitD(d.decls);
    exitScope();
    return d;
  }

  D visit(NewDeclaration)
  { /*add id to env*/return null; }
  D visit(DeleteDeclaration)
  { /*add id to env*/return null; }

  D visit(ProtectionDeclaration d)
  {
    auto saved = protection; // Save.
    protection = d.prot; // Set.
    visitD(d.decls);
    protection = saved; // Restore.
    return d;
  }

  D visit(StorageClassDeclaration d)
  {
    auto saved = storageClass; // Save.
    storageClass = d.storageClass; // Set.
    visitD(d.decls);
    storageClass = saved; // Restore.
    return d;
  }

  D visit(LinkageDeclaration d)
  {
    auto saved = linkageType; // Save.
    linkageType = d.linkageType; // Set.
    visitD(d.decls);
    linkageType = saved; // Restore.
    return d;
  }

  D visit(AlignDeclaration d)
  {
    auto saved = alignSize; // Save.
    alignSize = d.size; // Set.
    visitD(d.decls);
    alignSize = saved; // Restore.
    return d;
  }

  D visit(PragmaDeclaration d)
  {
    pragmaSemantic(scop, d.begin, d.ident, d.args);
    visitD(d.decls);
    return d;
  }

  Statement visit(PragmaStatement s)
  {
    pragmaSemantic(scop, s.begin, s.ident, s.args);
    visitS(s.pragmaBody);
    return s;
  }

  D visit(MixinDeclaration md)
  {
    // Add md to vector of (Scope, MixinDeclaration)
    // and evaluate them in 2nd pass?
    // TODO: store all attributes in md; they have to be applied
    // to the content that is mixed in.
    return md;
  }
} // override
}