mirror of
https://github.com/dlang/dmd.git
synced 2025-04-26 13:10:12 +03:00
397 lines
9.5 KiB
D
397 lines
9.5 KiB
D
// See ../README.md for information about DMD unit tests.
|
|
|
|
module frontend;
|
|
|
|
import support : afterEach, defaultImportPaths;
|
|
|
|
@afterEach deinitializeFrontend()
|
|
{
|
|
import dmd.frontend : deinitializeDMD;
|
|
deinitializeDMD();
|
|
}
|
|
|
|
@("parseModule - custom AST family")
|
|
unittest
|
|
{
|
|
import std.algorithm : each;
|
|
|
|
import dmd.astcodegen : ASTCodegen;
|
|
import dmd.dclass : ClassDeclaration;
|
|
import dmd.frontend;
|
|
import dmd.visitor : SemanticTimeTransitiveVisitor;
|
|
|
|
static struct AST
|
|
{
|
|
ASTCodegen ast;
|
|
alias ast this;
|
|
|
|
extern (C++) static final class InterfaceDeclaration : ClassDeclaration
|
|
{
|
|
import dmd.arraytypes : BaseClasses;
|
|
import dmd.identifier : Identifier;
|
|
import dmd.location;
|
|
|
|
bool created = false;
|
|
|
|
extern (D) this(Loc loc, Identifier id, BaseClasses* baseclasses)
|
|
{
|
|
super(loc, id, baseclasses, null, false);
|
|
created = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
extern (C++) static class Visitor : SemanticTimeTransitiveVisitor
|
|
{
|
|
alias visit = typeof(super).visit;
|
|
|
|
bool created = false;
|
|
|
|
override void visit(ClassDeclaration cdecl)
|
|
{
|
|
created = (cast(AST.InterfaceDeclaration) cdecl).created;
|
|
}
|
|
}
|
|
|
|
initDMD();
|
|
defaultImportPaths.each!addImport;
|
|
|
|
auto t = parseModule!AST("frontendcustomASTfamily.d", q{
|
|
interface Foo {}
|
|
});
|
|
|
|
assert(!t.diagnostics.hasErrors);
|
|
assert(!t.diagnostics.hasWarnings);
|
|
|
|
scope visitor = new Visitor;
|
|
t.module_.accept(visitor);
|
|
|
|
assert(visitor.created);
|
|
}
|
|
|
|
@("parseModule - invalid module name")
|
|
unittest
|
|
{
|
|
import dmd.frontend;
|
|
|
|
initDMD();
|
|
|
|
auto t = parseModule("foo/bar.d", "");
|
|
|
|
assert(!t.diagnostics.hasErrors);
|
|
assert(!t.diagnostics.hasWarnings);
|
|
|
|
const actual = t.module_.ident.toString;
|
|
assert(actual == "bar", actual);
|
|
}
|
|
|
|
@("parseModule - missing package")
|
|
unittest
|
|
{
|
|
import dmd.frontend;
|
|
|
|
initDMD();
|
|
|
|
auto t = parseModule("foo/bar.d", q{
|
|
module foo.bar;
|
|
});
|
|
|
|
assert(!t.diagnostics.hasErrors);
|
|
assert(!t.diagnostics.hasWarnings);
|
|
|
|
assert(t.module_.parent !is null);
|
|
}
|
|
|
|
@("parseModule - invalid module")
|
|
unittest
|
|
{
|
|
import std.conv : to;
|
|
import dmd.frontend;
|
|
|
|
import dmd.common.outbuffer;
|
|
import dmd.console : Color;
|
|
import dmd.location;
|
|
import core.stdc.stdarg : va_list;
|
|
|
|
string[] diagnosticMessages;
|
|
|
|
nothrow bool diagnosticHandler(const ref SourceLoc loc, Color headerColor, const(char)* header,
|
|
const(char)* format, va_list ap, const(char)* p1, const(char)* p2)
|
|
{
|
|
OutBuffer tmp;
|
|
tmp.vprintf(format, ap);
|
|
diagnosticMessages ~= to!string(tmp.peekChars());
|
|
return true;
|
|
}
|
|
initDMD(&diagnosticHandler);
|
|
|
|
auto bom = parseModule("foo/bar.d", [0x84, 0xC3]);
|
|
assert(bom.diagnostics.hasErrors);
|
|
assert(bom.module_ is null);
|
|
|
|
auto odd16 = parseModule("foo/bar.d", [0xFE, 0xFF, 0x84, 0x00]);
|
|
assert(odd16.diagnostics.hasErrors);
|
|
assert(odd16.module_ is null);
|
|
|
|
auto odd32 = parseModule("foo/bar.d", [0x00, 0x00, 0xFE, 0xFF, 0x84, 0x81]);
|
|
assert(odd32.diagnostics.hasErrors);
|
|
assert(odd32.module_ is null);
|
|
|
|
auto utf32gt = parseModule("foo/bar.d", [0x00, 0x00, 0xFE, 0xFF, 0x84, 0x81, 0x00]);
|
|
assert(utf32gt.diagnostics.hasErrors);
|
|
assert(utf32gt.module_ is null);
|
|
|
|
auto ill16 = parseModule("foo/bar.d", [0xFE, 0xFF, 0xFF, 0xFF, 0x00]);
|
|
assert(ill16.diagnostics.hasErrors);
|
|
assert(ill16.module_ is null);
|
|
|
|
auto unp16 = parseModule("foo/bar.d", [0xFE, 0xFF, 0xDC, 0x00, 0x00]);
|
|
assert(unp16.diagnostics.hasErrors);
|
|
assert(unp16.module_ is null);
|
|
|
|
auto sur16 = parseModule("foo/bar.d", [0xFE, 0xFF, 0xD8, 0x00, 0xE0, 0x00, 0x00]);
|
|
assert(sur16.diagnostics.hasErrors);
|
|
assert(sur16.module_ is null);
|
|
|
|
assert(diagnosticMessages.length == 7);
|
|
assert(endsWith(diagnosticMessages[0], "source file must start with BOM or ASCII character, not \\x84"));
|
|
assert(endsWith(diagnosticMessages[1], "odd length of UTF-16 char source 3"));
|
|
assert(endsWith(diagnosticMessages[2], "odd length of UTF-32 char source 3"));
|
|
assert(endsWith(diagnosticMessages[3], "UTF-32 value 84810000 greater than 0x10FFFF"));
|
|
assert(endsWith(diagnosticMessages[4], "illegal UTF-16 value ffff"));
|
|
assert(endsWith(diagnosticMessages[5], "unpaired surrogate UTF-16 value dc00"));
|
|
assert(endsWith(diagnosticMessages[6], "surrogate UTF-16 low value e000 out of range"));
|
|
}
|
|
|
|
@("initDMD - contract checking")
|
|
unittest
|
|
{
|
|
import std.algorithm : each;
|
|
|
|
import dmd.frontend;
|
|
import dmd.globals : global;
|
|
|
|
initDMD();
|
|
defaultImportPaths.each!addImport;
|
|
|
|
auto t = parseModule("frontendcontractchecking.d", q{
|
|
int foo(int a)
|
|
in(a == 3)
|
|
out(result; result == 0)
|
|
{
|
|
if (a == 1)
|
|
assert(false);
|
|
|
|
int[] array;
|
|
array[0] = 3;
|
|
|
|
final switch (3)
|
|
{
|
|
case 4: break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
class Foo
|
|
{
|
|
int a;
|
|
invariant(a > 0);
|
|
}
|
|
});
|
|
|
|
assert(!t.diagnostics.hasErrors);
|
|
assert(!t.diagnostics.hasWarnings);
|
|
|
|
t.module_.fullSemantic();
|
|
|
|
assert(global.errors == 0);
|
|
}
|
|
|
|
@("initDMD - version identifiers")
|
|
unittest
|
|
{
|
|
import std.algorithm : each;
|
|
|
|
import dmd.frontend;
|
|
import dmd.globals : global;
|
|
|
|
initDMD(null, null, ["Foo"]);
|
|
defaultImportPaths.each!addImport;
|
|
|
|
auto t = parseModule("frontendversionidentifiers.d", q{
|
|
version (Foo)
|
|
enum a = 1;
|
|
else
|
|
enum a = 2;
|
|
|
|
static assert(a == 1);
|
|
});
|
|
|
|
assert(!t.diagnostics.hasErrors);
|
|
assert(!t.diagnostics.hasWarnings);
|
|
|
|
t.module_.fullSemantic();
|
|
|
|
assert(global.errors == 0);
|
|
}
|
|
|
|
@("initDMD - custom diagnostic handling")
|
|
unittest
|
|
{
|
|
import std.conv;
|
|
import std.algorithm : each;
|
|
|
|
import core.stdc.stdarg : va_list;
|
|
|
|
import dmd.frontend;
|
|
import dmd.common.outbuffer;
|
|
import dmd.console : Color;
|
|
import dmd.location;
|
|
|
|
string[] diagnosticMessages;
|
|
|
|
nothrow bool diagnosticHandler(const ref SourceLoc loc, Color headerColor, const(char)* header,
|
|
const(char)* format, va_list ap, const(char)* p1, const(char)* p2)
|
|
{
|
|
OutBuffer tmp;
|
|
tmp.vprintf(format, ap);
|
|
diagnosticMessages ~= to!string(tmp.peekChars());
|
|
return true;
|
|
}
|
|
|
|
initDMD(&diagnosticHandler);
|
|
defaultImportPaths.each!addImport;
|
|
|
|
parseModule("frontendcustomdiagnostichandling.d", q{
|
|
void foo(){
|
|
auto temp == 7.8;
|
|
foreach(i; 0..5){
|
|
}
|
|
}
|
|
});
|
|
|
|
assert(endsWith(diagnosticMessages[0], "variable name expected after type `temp`, not `==`"));
|
|
assert(endsWith(diagnosticMessages[1], "found `==` instead of statement"));
|
|
}
|
|
|
|
@("addStringImport") unittest
|
|
{
|
|
import std.algorithm : each;
|
|
import std.path : dirName, buildPath;
|
|
|
|
import dmd.frontend;
|
|
import dmd.globals : global;
|
|
|
|
initDMD();
|
|
defaultImportPaths.each!addImport;
|
|
addStringImport(__FILE_FULL_PATH__.dirName.buildPath("support", "data"));
|
|
|
|
auto t = parseModule("frontendaddStringImport.d", q{
|
|
enum a = import("foo.txt");
|
|
});
|
|
|
|
assert(!t.diagnostics.hasErrors);
|
|
assert(!t.diagnostics.hasWarnings);
|
|
|
|
t.module_.fullSemantic();
|
|
|
|
assert(global.errors == 0);
|
|
}
|
|
|
|
@("initDMD - floating-point")
|
|
unittest
|
|
{
|
|
import std.algorithm : each;
|
|
|
|
import dmd.frontend;
|
|
import dmd.globals : global;
|
|
|
|
initDMD();
|
|
defaultImportPaths.each!addImport;
|
|
|
|
auto t = parseModule("frontendfloatingpoint.d", q{
|
|
static assert((2.0i).re == 0);
|
|
});
|
|
|
|
assert(!t.diagnostics.hasErrors);
|
|
assert(!t.diagnostics.hasWarnings);
|
|
|
|
t.module_.fullSemantic();
|
|
|
|
assert(global.errors == 0);
|
|
}
|
|
|
|
@("inline assembly")
|
|
unittest
|
|
{
|
|
import std.algorithm : each;
|
|
|
|
import dmd.frontend;
|
|
import dmd.globals : global;
|
|
|
|
initDMD();
|
|
defaultImportPaths.each!addImport;
|
|
|
|
auto t = parseModule("frontendinlineassembly.d", q{
|
|
void foo()
|
|
{
|
|
asm
|
|
{
|
|
call foo;
|
|
}
|
|
}
|
|
});
|
|
|
|
assert(!t.diagnostics.hasErrors);
|
|
assert(!t.diagnostics.hasWarnings);
|
|
|
|
t.module_.fullSemantic();
|
|
|
|
assert(global.errors == 0);
|
|
}
|
|
|
|
// Issue https://issues.dlang.org/show_bug.cgi?id=22906
|
|
@("semantics on non regular module")
|
|
unittest
|
|
{
|
|
import std.algorithm : each;
|
|
import std.conv : to;
|
|
|
|
import core.stdc.stdarg : va_list;
|
|
|
|
import dmd.frontend;
|
|
import dmd.globals : global;
|
|
import dmd.common.outbuffer;
|
|
import dmd.console : Color;
|
|
import dmd.location;
|
|
|
|
string[] diagnosticMessages;
|
|
|
|
nothrow bool diagnosticHandler(const ref SourceLoc loc, Color headerColor, const(char)* header,
|
|
const(char)* format, va_list ap, const(char)* p1, const(char)* p2)
|
|
{
|
|
OutBuffer tmp;
|
|
tmp.vprintf(format, ap);
|
|
diagnosticMessages ~= to!string(tmp.peekChars());
|
|
return true;
|
|
}
|
|
|
|
initDMD(&diagnosticHandler);
|
|
defaultImportPaths.each!addImport;
|
|
|
|
auto t = parseModule("frontendddoc.dd", q{Ddoc});
|
|
|
|
assert(!t.diagnostics.hasErrors);
|
|
assert(!t.diagnostics.hasWarnings);
|
|
|
|
t.module_.fullSemantic();
|
|
|
|
assert(global.errors == 1);
|
|
assert(endsWith(diagnosticMessages[0], "is a Ddoc file, cannot import it"));
|
|
}
|
|
|
|
bool endsWith(string diag, string msg)
|
|
{
|
|
return diag.length >= msg.length && diag[$ - msg.length .. $] == msg;
|
|
}
|