changeset 99:857f0d530789 new_gen

Imports and improved module statement Allow "module a.b.c" Supports most forms of D's import. import A, B; import A, B = C; import A, B : a = b, c;
author Anders Halager <halager@gmail.com>
date Tue, 06 May 2008 21:59:22 +0200
parents 7f9240d4ddc1
children 5f258eaf9517
files ast/Decl.d basic/Messages.d lexer/Lexer.d parser/Action.d parser/Parser.d sema/AstAction.d sema/Scope.d sema/ScopeBuilder.d sema/ScopeCheck.d sema/Visitor.d tests/code/array_1.d
diffstat 11 files changed, 283 insertions(+), 48 deletions(-) [+]
line wrap: on
line diff
--- a/ast/Decl.d	Tue May 06 21:55:29 2008 +0200
+++ b/ast/Decl.d	Tue May 06 21:59:22 2008 +0200
@@ -14,6 +14,7 @@
 enum DeclType
 {
     VarDecl,
+    ImportDecl,
     FuncDecl,
     StructDecl,
 }
@@ -59,6 +60,22 @@
     Exp init;
 }
 
+class ImportDecl : Decl
+{
+    this()
+    {
+        super(DeclType.ImportDecl);
+    }
+
+    bool isStatic = false;
+
+    Identifier[] packages;
+    Identifier name;
+    Identifier aliasedName;
+
+    Identifier[2][] explicitSymbols;
+}
+
 class FuncDecl : Decl
 {
     this(Identifier type, Identifier identifier)
--- a/basic/Messages.d	Tue May 06 21:55:29 2008 +0200
+++ b/basic/Messages.d	Tue May 06 21:59:22 2008 +0200
@@ -2,11 +2,14 @@
 
 enum : uint
 {
+    // Lex
     InvalidSymbol,
     InvalidIlligaleType,
     UnexpectedEOFBlock,
     OnlyOneDotFloating,
     OnlyOneEFloating,
+
+    // Parse
     UnexpectedTokMulti,
     UnexpectedTokSingle,
     UnexpectedTok,
@@ -18,6 +21,9 @@
     ExpectedCastType,
     InvalidDeclType,
     InvalidType,
+    //   - imports/module
+    ExpectedIdAfterPackage,
+    RenameMustBeSingleIdent,
 }
 
 enum MessageType
@@ -33,24 +39,30 @@
     MessageType type;
     char[] message;
 }
-
+    
+private alias MessageType.Error Err;
+private alias MessageType.Warning War;
+private alias MessageEntry E;
 static this()
 {
     Messages = [
-        UnexpectedEOFBlock  : MessageEntry(MessageType.Error, "Unexpected end of file. Unclosed comment block"),
-        InvalidSymbol       : MessageEntry(MessageType.Error, "Read invalid symbol: '%0'"),
-        OnlyOneDotFloating  : MessageEntry(MessageType.Error, "Only one '.' is allowed in an floating number"),
-        OnlyOneEFloating    : MessageEntry(MessageType.Error, "Only one E is allowed in an floating number"),
-        UnexpectedTokMulti  : MessageEntry(MessageType.Error, "Unexpected token, got %0 expected one of %1"),
-        UnexpectedTokSingle : MessageEntry(MessageType.Error, "Unexpected token, got %0 expected %1"),
-        UnexpectedTok       : MessageEntry(MessageType.Error, "Unexpected token %0"),
-        CaseValueMustBeInt  : MessageEntry(MessageType.Error, "Cases can only be integer literals"),
-        UnexpectedBeginStmt : MessageEntry(MessageType.Error, "Unexpected begining of statement."),
-        UnexpectedTokType   : MessageEntry(MessageType.Error, "Unexpected token in Type parsing. Got %0"),
-        ExpectedIdAfterDot  : MessageEntry(MessageType.Error, "Expected identifier after '.'"),
-        ExpectedExp         : MessageEntry(MessageType.Error, "Expected expression"),
-        ExpectedCastType    : MessageEntry(MessageType.Error, "Expected cast type"),
-        InvalidDeclType     : MessageEntry(MessageType.Error, "Invalid declaration type"),
-        InvalidType         : MessageEntry(MessageType.Error, "Invalid type")
+        UnexpectedEOFBlock  : E(Err, "Unexpected end of file. Unclosed comment block"),
+        InvalidSymbol       : E(Err, "Read invalid symbol: '%0'"),
+        OnlyOneDotFloating  : E(Err, "Only one '.' is allowed in an floating number"),
+        OnlyOneEFloating    : E(Err, "Only one E is allowed in an floating number"),
+
+        UnexpectedTokMulti  : E(Err, "Unexpected token, got %0 expected one of %1"),
+        UnexpectedTokSingle : E(Err, "Unexpected token, got %0 expected %1"),
+        UnexpectedTok       : E(Err, "Unexpected token %0"),
+        CaseValueMustBeInt  : E(Err, "Cases can only be integer literals"),
+        UnexpectedBeginStmt : E(Err, "Unexpected begining of statement."),
+        UnexpectedTokType   : E(Err, "Unexpected token in Type parsing. Got %0"),
+        ExpectedIdAfterDot  : E(Err, "Expected identifier after '.'"),
+        ExpectedExp         : E(Err, "Expected expression"),
+        ExpectedCastType    : E(Err, "Expected cast type"),
+        InvalidDeclType     : E(Err, "Invalid declaration type"),
+        InvalidType         : E(Err, "Invalid type"),
+        ExpectedIdAfterPackage : E(Err, "Identifier expected following package")
     ];
 }
+
--- a/lexer/Lexer.d	Tue May 06 21:55:29 2008 +0200
+++ b/lexer/Lexer.d	Tue May 06 21:59:22 2008 +0200
@@ -21,8 +21,6 @@
     /**
       Create a new Lexer.
     */
-
-
     this(SourceLocation start, SourceManager src_mgr, MessageHandler messages)
     {
         this.messages = messages;
--- a/parser/Action.d	Tue May 06 21:55:29 2008 +0200
+++ b/parser/Action.d	Tue May 06 21:59:22 2008 +0200
@@ -60,6 +60,25 @@
 }
 
 /**
+  Represents a fully qualified name, with some packages and a final identifier.
+  The identifier should always be set, but packages may have length 0.
+ **/
+struct ModuleName
+{
+    Id id;
+    Id[] packages;
+
+    /// Get the full ranged spanned by packages and identifier
+    SourceRange asRange()
+    {
+        SourceRange r = id.tok.asRange();
+        foreach (identifier; packages)
+            r = r + identifier.tok.asRange();
+        return r;
+    }
+}
+
+/**
   All methods are optional.
 
 Warning: Interface is not stable yet. Use the `override` keyword in all classes
@@ -82,7 +101,18 @@
 
     // -- Modules --
 
-    ModuleT actOnModule(char[] name)
+    ModuleT actOnModule(ref Token _module, char[] name)
+    {
+        return null;
+    }
+
+    /**
+      This action is called when a file does not start with a module
+      declaration - in which case there is no Token available.
+
+      Instead a SLoc to the start of the file is given.
+     */
+    ModuleT actOnImplicitModule(SourceLocation fileStart, char[] name)
     {
         return null;
     }
@@ -94,6 +124,23 @@
     // -- Declarations --
 
     /**
+      Called for an import statement, that may be renamed. Id name is null,
+      there is no rename.
+
+      If there are selective imports, its handled in add 
+     */
+    DeclT actOnImport(ref Token _import, ref ModuleName target, Id* name)
+    {
+        return null;
+    }
+
+    /**
+     */
+    void addSelectiveImport(DeclT _import, ref Id target, Id* name)
+    {
+    }
+
+    /**
       Either we should have one case that handles a lot of things, or we should
       have a lot of separate cases.
       As an example, this method could handle the params in `int f(int, int)`
--- a/parser/Parser.d	Tue May 06 21:55:29 2008 +0200
+++ b/parser/Parser.d	Tue May 06 21:59:22 2008 +0200
@@ -22,8 +22,6 @@
     alias Object Decl;
     alias Object Module;
 
-public:
-
     this(MessageHandler messages)
     {
         this.messages = messages;
@@ -35,31 +33,35 @@
         this.lexer = lexer;
         this.action = act;
 
-        auto m = parseModule();
+        Module m;
+        if (lexer.peek.type == Tok.Module)
+        {
+            Token _module = lexer.next;
+            ModuleName name = parseModuleName();
+            m = action.actOnModule(_module, sm.getText(name.asRange()));
+            require(Tok.Seperator);
+        }
+        else
+        {
+            SLoc loc = lexer.peek.location;
+            m = action.actOnImplicitModule(loc, sm.getFile(loc));
+        }
 
-        while(lexer.peek.type != Tok.EOF)
-            action.actOnModuleDecl(m, parseDecl());
+        while (lexer.peek.type != Tok.EOF)
+            foreach (d; parseDeclDef())
+                action.actOnModuleDecl(m, d);
 
         return m;
     }
 
-    Module parseModule()
+private:
+    Decl[] parseDeclDef()
     {
-        if(lexer.peek.type == Tok.Module)
-        {
-            lexer.next;
-            if(lexer.peek.type != Tok.Identifier)
-                messages.report(UnexpectedTok, lexer.peek.location)
-                    .arg(lexer.peek.type)
-                    .arg(Tok.Identifier)
-                    .fatal(ExitLevel.Parser);
-    
-            auto m = action.actOnModule(sm.getText(lexer.next.asRange));
-            require(Tok.Seperator);
-            return m;
-        }
-
-        return action.actOnModule(sm.getFile(lexer.peek.location));
+        Token t = lexer.peek;
+        if (t.type == Tok.Import)
+            return parseImports();
+        else
+            return [parseDecl()];
     }
 
     Decl parseDecl()
@@ -118,6 +120,83 @@
     }
 
     /**
+      Parse a series of imports belonging to a single import token.
+     */
+    Decl[] parseImports()
+    {
+        Token _import = require(Tok.Import);
+        SmallArray!(Decl) res;
+        void addToRes(Decl d) { res ~= d; }
+
+        bool done = false;
+        while (!done && !on_a(Tok.Seperator))
+        {
+            ModuleName mod = parseModuleName();
+            Token tok = lexer.peek;
+            switch (tok.type)
+            {
+                case Tok.Comma:
+                    // import A, B.C;
+                    // parse another module-name
+                    lexer.next();
+                    res ~= action.actOnImport(_import, mod, null);
+                    break;
+                case Tok.Assign:
+                    // import B = A.A;
+                    //        ^- must be a single identifier
+                    // renamed import
+                    if (mod.packages.length != 0)
+                    {
+                        SLoc loc = mod.packages[0].tok.location;
+                        messages.report(RenameMustBeSingleIdent, loc);
+                    }
+                    //if (isStatic)
+                    //    error("Static imports cannot be renamed");
+                    lexer.next();
+                    Id name = mod.id;
+                    mod = parseModuleName();
+                    // create from mod and rename to `name`
+                    res ~= action.actOnImport(_import, mod, &name);
+                    break;
+                case Tok.Colon:
+                    // import A : a;
+                    // selective imports, potentially import A : print = a
+                    lexer.next();
+                    Decl d = action.actOnImport(_import, mod, null);
+                    // do-while on a comma:
+                    //   add explicit symbol
+                    do
+                    {
+                        Id sym = parseIdentifier();
+                        Id dummy;
+                        Id* name = null;
+                        if (skip(Tok.Assign))
+                        {
+                            dummy = sym;
+                            name = &dummy;
+                            sym = parseIdentifier();
+                        }
+                        action.addSelectiveImport(d, sym, name);
+
+                    } while (skip(Tok.Comma));
+                    require(Tok.Seperator);
+                    res ~= d;
+                    return res.safe();
+                default:
+                    goto Lerror;
+            }
+            res ~= action.actOnImport(_import, mod, null);
+        }
+
+        require(Tok.Seperator);
+        return res.safe();
+Lerror:
+        while (!on_a (Tok.Seperator))
+            lexer.next();
+        return res.safe();
+    }
+
+    /**
       Parse struct
      */
     Decl parseStruct(Id type, Id iden)
@@ -152,6 +231,7 @@
         
         return decl;
     }
+
     /**
       Parse statements.
 
@@ -237,14 +317,13 @@
                         return action.actOnExprStmt(exp);
                     }
                         
-                    if ( n.isIdentifier())
+                    if (n.isIdentifier())
                         return action.actOnDeclStmt(parseVarDecl());
 
                     // Expression: a.b, a = b, a(b) etc.
                     Exp exp = parseExpression();
                     require(Tok.Seperator);
                     return action.actOnExprStmt(exp);
-                    break;
                 }
 
             case Tok.Switch:
@@ -261,6 +340,7 @@
                     return action.actOnExprStmt(exp);
                 }
                 messages.report(UnexpectedBeginStmt, lexer.peek.location).arg(lexer.next.getType);
+                return null;
         }
         messages.report(UnexpectedTok, t.location);
         return null;
@@ -332,8 +412,10 @@
             return parseCompoundStatement();
         return parseStatement();
     }
+
     /**
-      Parses a function-body or similar, expects { to be current token.
+      Parses a function-body or similar, expects an opening brace to be the
+      current token.
       
       Will consume both the starting { and ending }
      */
@@ -359,6 +441,28 @@
             .arg(Tok.Identifier);
     }
 
+    ModuleName parseModuleName()
+    {
+        auto id = parseIdentifier();
+        ModuleName mod;
+        while (skip(Tok.Dot))
+        {
+            mod.packages ~= id;
+            if (lexer.peek.type != Tok.Identifier) {
+                messages.report(ExpectedIdAfterPackage, lexer.peek.location);
+                goto Lerror;
+            }
+            id = parseIdentifier();
+        }
+        mod.id = id;
+        return mod;
+Lerror:
+        while (!skip(Tok.Seperator))
+            lexer.next();
+        return mod;
+    }
+
+
     /**
       Parse a type - this includes pointer and array(at some point) types.
      */
@@ -609,6 +713,12 @@
         return true;
     }
 
+    bool on_a(Tok t)
+    {
+        return lexer.peek.type == t;
+    }
+
     Lexer lexer;
     SourceManager sm;
 }
+
--- a/sema/AstAction.d	Tue May 06 21:55:29 2008 +0200
+++ b/sema/AstAction.d	Tue May 06 21:59:22 2008 +0200
@@ -42,7 +42,12 @@
         return new Identifier(t.location, sm.getText(t.asRange));
     }
 
-    override ModuleT actOnModule(char[] name)
+    override ModuleT actOnModule(ref Token _module, char[] name)
+    {
+        return new Module(name);
+    }
+
+    override ModuleT actOnImplicitModule(SLoc startLoc, char[] name)
     {
         return new Module(name);
     }
@@ -53,6 +58,30 @@
     }
 
     // -- Declarations --
+    override DeclT actOnImport(ref Token _, ref ModuleName target, Id* name)
+    {
+        auto res = new ImportDecl;
+        Identifier[] packages = new Identifier[target.packages.length];
+        foreach (i, v; target.packages)
+            packages[i] = identifierFromTok(v.tok);
+        res.packages = packages;
+
+        res.name = identifierFromTok(target.id.tok);
+        if (name !is null)
+            res.aliasedName = identifierFromTok(name.tok);
+        return res;
+    }
+
+    override void addSelectiveImport(DeclT _import, ref Id target, Id* name)
+    {
+        auto d = cast(ImportDecl)_import;
+        Identifier t = identifierFromTok(target.tok);
+        Identifier n = t;
+        if (name !is null)
+            n = identifierFromTok(name.tok);
+        d.explicitSymbols ~= [t, n];
+    }
+
     override DeclT actOnDeclarator(ref Id type, ref Id id, ExprT init)
     {
         Exp exp = cast(Exp)init;
--- a/sema/Scope.d	Tue May 06 21:55:29 2008 +0200
+++ b/sema/Scope.d	Tue May 06 21:59:22 2008 +0200
@@ -3,6 +3,7 @@
 import tango.io.Stdout;
 
 import lexer.Token,
+       ast.Module,
        ast.Decl,
        ast.Exp;
 
@@ -16,16 +17,15 @@
     {
         this.enclosing = enclosing;
         this.func = enclosing.func;
+        this.inModule = enclosing.inModule;
     }
 
     Scope enclosing;
+    Module inModule;
 
     void add(Identifier id)
     {
-//        auto s = new Symbol;
-//        s.id = id;
         symbols[id] = id;
-//        return s;
     }
 
     Identifier find(Identifier id)
--- a/sema/ScopeBuilder.d	Tue May 06 21:55:29 2008 +0200
+++ b/sema/ScopeBuilder.d	Tue May 06 21:59:22 2008 +0200
@@ -74,6 +74,7 @@
 
     override void visit(Module m)
     {
+        current().inModule = m;
         visitModule(m);
         auto fr = new ForwardReference();
         fr.visit(m);
--- a/sema/ScopeCheck.d	Tue May 06 21:55:29 2008 +0200
+++ b/sema/ScopeCheck.d	Tue May 06 21:59:22 2008 +0200
@@ -46,6 +46,8 @@
             visitStmt(stmt);
     }
 
+    override void visitImportDecl(ImportDecl) { }
+
     override void visitCastExp(CastExp exp)
     {
         visitExp(exp.exp);
--- a/sema/Visitor.d	Tue May 06 21:55:29 2008 +0200
+++ b/sema/Visitor.d	Tue May 06 21:59:22 2008 +0200
@@ -40,6 +40,8 @@
                 return visitFuncDecl(cast(FuncDecl)decl);
             case DeclType.VarDecl:
                 return visitVarDecl(cast(VarDecl)decl);
+            case DeclType.ImportDecl:
+                return visitImportDecl(cast(ImportDecl)decl);
             case DeclType.StructDecl:
                 return visitStructDecl(cast(StructDecl)decl);
             default:
@@ -118,6 +120,24 @@
             return DeclT.init;
     }
 
+    DeclT visitImportDecl(ImportDecl d)
+    {
+        visitIdentifier(d.name);
+        visitIdentifier(d.aliasedName);
+        foreach (id; d.packages)
+            visitIdentifier(id);
+        foreach (ids; d.explicitSymbols)
+        {
+            visitIdentifier(ids[0]);
+            visitIdentifier(ids[1]);
+        }
+
+        static if (is(DeclT == void))
+            return;
+        else
+            return DeclT.init;
+    }
+
     DeclT visitFuncDecl(FuncDecl f)
     {
         visitExp(f.returnType);
--- a/tests/code/array_1.d	Tue May 06 21:55:29 2008 +0200
+++ b/tests/code/array_1.d	Tue May 06 21:59:22 2008 +0200
@@ -1,4 +1,3 @@
-
 struct Array
 {
     int[] data;