# HG changeset patch # User Anders Halager # Date 1210103962 -7200 # Node ID 857f0d530789e1e66ee498e8fc964050ea51ae3e # Parent 7f9240d4ddc1799380954198803a94b8a2c7c3ba 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; diff -r 7f9240d4ddc1 -r 857f0d530789 ast/Decl.d --- 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) diff -r 7f9240d4ddc1 -r 857f0d530789 basic/Messages.d --- 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") ]; } + diff -r 7f9240d4ddc1 -r 857f0d530789 lexer/Lexer.d --- 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; diff -r 7f9240d4ddc1 -r 857f0d530789 parser/Action.d --- 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)` diff -r 7f9240d4ddc1 -r 857f0d530789 parser/Parser.d --- 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; } + diff -r 7f9240d4ddc1 -r 857f0d530789 sema/AstAction.d --- 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; diff -r 7f9240d4ddc1 -r 857f0d530789 sema/Scope.d --- 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) diff -r 7f9240d4ddc1 -r 857f0d530789 sema/ScopeBuilder.d --- 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); diff -r 7f9240d4ddc1 -r 857f0d530789 sema/ScopeCheck.d --- 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); diff -r 7f9240d4ddc1 -r 857f0d530789 sema/Visitor.d --- 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); diff -r 7f9240d4ddc1 -r 857f0d530789 tests/code/array_1.d --- 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;