view trunk/src/dil/semantic/Pass1.d @ 680:6b3e397229c5

Renamed Statements, Declarations and EnumMember. Statements -> CompoundStatement. Declarations -> CompoundDeclaration. EnumMember -> EnumMemberDeclaration.
author Aziz K?ksal <aziz.koeksal@gmail.com>
date Fri, 18 Jan 2008 23:59:41 +0100
parents ff6971637f88
children 1ae72234db26
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.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 common;

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

  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;
    visitN(modul.root);
  }

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

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

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

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

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

  Declaration visit(EmptyDeclaration ed)
  { return ed; }

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

  Declaration 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;
  }

  Declaration 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;
  }

  Declaration visit(EnumDeclaration ed)
  {
    /+
    // Create the symbol.
    symbol = new Enum(name, this);
    // Type semantics.
    Type type = Types.Int; // Default to integer.
    if (baseType)
      type = baseType.semantic(scop);
    auto enumType = new EnumType(symbol, type);
    // Set the base type of the enum symbol.
    symbol.setType(enumType);
    if (name)
    { // Insert named enum into scope.
      scop.insert(symbol, symbol.ident);
      // Create new scope.
      scop = scop.push(symbol);
    }
    // Semantic on members.
    foreach (member; members)
    {
      auto value = member.value;
      if (value)
      {
        // value = value.semantic(scop);
        // value = value.evaluate();
      }
      auto variable = new Variable(StorageClass.Const, LinkageType.None, type, member.name, member);
      scop.insert(variable, variable.ident);
    }
    if (name)
      scop.pop();
    +/
    return ed;
  }

  Declaration visit(EnumMemberDeclaration)
  { return null; }

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

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

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

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

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

  Declaration visit(VariablesDeclaration vd)
  {
    Type type = Types.Undefined;

    if (vd.typeNode)
      // Get type from typeNode.
      type = visitT(vd.typeNode).type;
    else
    { // Infer type from first initializer.
      auto firstInit = vd.values[0];
      firstInit = visitE(firstInit);
      type = firstInit.type;
    }
    //assert(type !is null);

    // Check if we are in an interface.
    if (scop.isInterface)
      return error(vd.begin, MSG.InterfaceCantHaveVariables), vd;

    // Iterate over variable identifiers in this declaration.
    foreach (i, ident; vd.idents)
    {
      // Perform semantic analysis on value.
      if (vd.values[i])
        vd.values[i] = visitE(vd.values[i]);
      // Create a new variable symbol.
      // TODO: pass 'prot' to constructor.
      auto variable = new Variable(vd.stc, vd.linkageType, type, ident, vd);
      vd.variables ~= variable;
      // Add to scope.
      scop.insert(variable);
    }
    return vd;
  }

  Declaration visit(InvariantDeclaration)
  { return null; }
  Declaration visit(UnittestDeclaration)
  { return null; }
  Declaration visit(DebugDeclaration)
  { return null; }
  Declaration visit(VersionDeclaration)
  { return null; }
  Declaration visit(StaticIfDeclaration)
  { return null; }
  Declaration visit(StaticAssertDeclaration)
  { return null; }
  Declaration visit(TemplateDeclaration)
  { return null; }
  Declaration visit(NewDeclaration)
  { return null; }
  Declaration visit(DeleteDeclaration)
  { return null; }

  Declaration visit(ProtectionDeclaration d)
  { visitD(d.decls); return d; }
  Declaration visit(StorageClassDeclaration d)
  { visitD(d.decls); return d; }
  Declaration visit(LinkageDeclaration d)
  { visitD(d.decls); return d; }
  Declaration visit(AlignDeclaration d)
  { visitD(d.decls); return d; }

  Declaration 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;
  }

  Declaration visit(MixinDeclaration)
  { return null; }

  Expression visit(ParenExpression e)
  {
    if (!e.type)
    {
      e.next = visitE(e.next);
      e.type = e.next.type;
    }
    return e;
  }

  Expression visit(CommaExpression e)
  {
    if (!e.type)
    {
      e.left = visitE(e.left);
      e.right = visitE(e.right);
      e.type = e.right.type;
    }
    return e;
  }

  Expression visit(OrOrExpression)
  { return null; }

  Expression visit(AndAndExpression)
  { return null; }

  Expression visit(SpecialTokenExpression e)
  {
    if (e.type)
      return e.value;
    switch (e.specialToken.kind)
    {
    case TOK.LINE, TOK.VERSION:
      e.value = new IntExpression(e.specialToken.uint_, Types.Uint);
      break;
    case TOK.FILE, TOK.DATE, TOK.TIME, TOK.TIMESTAMP, TOK.VENDOR:
      e.value = new StringExpression(e.specialToken.str);
      break;
    default:
      assert(0);
    }
    e.type = e.value.type;
    return e.value;
  }

  Expression visit(DollarExpression e)
  {
    if (e.type)
      return e;
    e.type = Types.Size_t;
    // if (!inArraySubscript)
    //   error("$ can only be in an array subscript.");
    return e;
  }

  Expression visit(NullExpression e)
  {
    if (!e.type)
      e.type = Types.Void_ptr;
    return e;
  }

  Expression visit(BoolExpression e)
  {
    if (e.type)
      return e;
    e.value = new IntExpression(e.toBool(), Types.Bool);
    e.type = Types.Bool;
    return e;
  }

  Expression visit(IntExpression e)
  {
    if (e.type)
      return e;

    if (e.number & 0x8000_0000_0000_0000)
      e.type = Types.Ulong; // 0xFFFF_FFFF_FFFF_FFFF
    else if (e.number & 0xFFFF_FFFF_0000_0000)
      e.type = Types.Long; // 0x7FFF_FFFF_FFFF_FFFF
    else if (e.number & 0x8000_0000)
      e.type = Types.Uint; // 0xFFFF_FFFF
    else
      e.type = Types.Int; // 0x7FFF_FFFF
    return e;
  }

  Expression visit(RealExpression e)
  {
    if (e.type)
      e.type = Types.Double;
    return e;
  }

  Expression visit(ComplexExpression e)
  {
    if (!e.type)
      e.type = Types.Cdouble;
    return e;
  }

  Expression visit(CharExpression e)
  {
    if (e.type)
      return e;
    if (e.character <= 0xFF)
      e.type = Types.Char;
    else if (e.character <= 0xFFFF)
      e.type = Types.Wchar;
    else
      e.type = Types.Dchar;
    return e;
  }

  Expression visit(StringExpression e)
  {
    return e;
  }

  Expression visit(MixinExpression me)
  {
    /+
    if (type)
      return this.expr;
    // TODO:
    auto expr = this.expr.semantic(scop);
    expr = expr.evaluate();
    if (expr is null)
      return this;
    auto strExpr = TryCast!(StringExpression)(expr);
    if (strExpr is null)
     error(scop, MSG.MixinArgumentMustBeString);
    else
    {
      auto loc = this.begin.getErrorLocation();
      auto filePath = loc.filePath;
      auto parser = new_ExpressionParser(strExpr.getString(), filePath, scop.infoMan);
      expr = parser.parse();
      expr = expr.semantic(scop);
    }
    this.expr = expr;
    this.type = expr.type;
    return expr;
    +/
    return null;
  }
} // override
}