summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Hodge <tpg@ucc.asn.au>2018-12-15 14:47:08 +0800
committerJohn Hodge <tpg@ucc.asn.au>2018-12-15 14:47:08 +0800
commitf6209dce15ce863e15dc3063d78e43eeb0db25ee (patch)
tree9b041d4b32fc6907867412203db18d8c06fcf674
parent539ecb375c8b86bb0b3c2d64d73dfa6d5b56c2b9 (diff)
downloadmrust-f6209dce15ce863e15dc3063d78e43eeb0db25ee.tar.gz
Targets - Add alignment to the target specs, along with a saveback test.
-rw-r--r--Makefile9
-rw-r--r--samples/target_stress_test.toml22
-rw-r--r--src/main.cpp32
-rw-r--r--src/trans/codegen_c.cpp11
-rw-r--r--src/trans/target.cpp137
-rw-r--r--src/trans/target.hpp28
-rw-r--r--tools/common/toml.cpp85
-rw-r--r--tools/common/toml.h21
8 files changed, 252 insertions, 93 deletions
diff --git a/Makefile b/Makefile
index 1eda93dd..23c799d2 100644
--- a/Makefile
+++ b/Makefile
@@ -276,7 +276,14 @@ output/rust/test_run-pass_hello_out.txt: output/rust/test_run-pass_hello
#
# TEST: Rust standard library and the "hello, world" run-pass test
#
-test: output/libstd.hir output/rust/test_run-pass_hello_out.txt $(BIN)
+test: output/libstd.hir output/rust/test_run-pass_hello_out.txt $(BIN) TEST_targetsaveback
+
+.PHONY: TEST_targetsaveback
+TEST_targetsaveback:
+ $(BIN) --target ./samples/target_stress_test.toml --dump-target-spec TMP-dump-target_stress_test.toml
+ $(BIN) --target ./TMP-dump-target_stress_test.toml --dump-target-spec TMP-dump-target_stress_test-2.toml
+ diff ./samples/target_stress_test.toml TMP-dump-target_stress_test.toml
+ diff TMP-dump-target_stress_test.toml TMP-dump-target_stress_test-2.toml
#
# TEST: Attempt to compile rust_os (Tifflin) from ../rust_os
diff --git a/samples/target_stress_test.toml b/samples/target_stress_test.toml
new file mode 100644
index 00000000..c7630567
--- /dev/null
+++ b/samples/target_stress_test.toml
@@ -0,0 +1,22 @@
+[target]
+family = "fake"
+os-name = "fakest"
+env-name = "faker"
+
+[backend.c]
+variant = "msvc"
+target = "x86_64-linux-msvc"
+compiler-opts = ["/W:1234",]
+linker-opts = ["/K",]
+
+[arch]
+name = "fubar"
+pointer-bits = 128
+is-big-endian = true
+has-atomic-u8 = false
+has-atomic-u16 = false
+has-atomic-u32 = false
+has-atomic-u64 = false
+has-atomic-ptr = false
+alignments = { u16 = 1, u32 = 2, u64 = 4, u128 = 8, f32 = 3, f64 = 5, ptr = 16 }
+
diff --git a/src/main.cpp b/src/main.cpp
index 2dd05a05..a50fe095 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -36,6 +36,7 @@ bool g_debug_enabled = true;
void init_debug_list()
{
+ g_debug_disable_map.insert( "Target Load" );
g_debug_disable_map.insert( "Parse" );
g_debug_disable_map.insert( "LoadCrates" );
g_debug_disable_map.insert( "Expand" );
@@ -156,6 +157,9 @@ struct ProgramParams
bool test_harness = false;
+ // NOTE: If populated, nothing happens except for loading the target
+ ::std::string target_saveback;
+
::std::vector<const char*> lib_search_dirs;
::std::vector<const char*> libraries;
::std::map<::std::string, ::std::string> crate_overrides; // --extern name=path
@@ -214,8 +218,21 @@ int main(int argc, char *argv[])
Cfg_SetValueCb("feature", [&params](const ::std::string& s) {
return params.features.count(s) != 0;
});
- Target_SetCfg(params.target);
+ CompilePhaseV("Target Load", [&]() {
+ Target_SetCfg(params.target);
+ });
+ if( params.target_saveback != "")
+ {
+ Target_ExportCurSpec(params.target_saveback);
+ return 0;
+ }
+
+ if( params.infile == "" )
+ {
+ ::std::cerr << "No input file passed" << ::std::endl;
+ return 1;
+ }
if( params.test_harness )
{
@@ -1060,6 +1077,13 @@ ProgramParams::ProgramParams(int argc, char *argv[])
}
this->target = argv[++i];
}
+ else if( strcmp(arg, "--dump-target-spec") == 0 ) {
+ if (i == argc - 1) {
+ ::std::cerr << "Flag " << arg << " requires an argument" << ::std::endl;
+ exit(1);
+ }
+ this->target_saveback = argv[++i];
+ }
else if( strcmp(arg, "--test") == 0 ) {
this->test_harness = true;
}
@@ -1070,12 +1094,6 @@ ProgramParams::ProgramParams(int argc, char *argv[])
}
}
- if (this->infile == "")
- {
- ::std::cerr << "No input file passed" << ::std::endl;
- exit(1);
- }
-
if( const auto* a = getenv("MRUSTC_DUMP") )
{
while( a[0] )
diff --git a/src/trans/codegen_c.cpp b/src/trans/codegen_c.cpp
index 55b3ea1a..84a538d5 100644
--- a/src/trans/codegen_c.cpp
+++ b/src/trans/codegen_c.cpp
@@ -205,20 +205,23 @@ namespace {
m_outfile_path_c(outfile + ".c"),
m_of(m_outfile_path_c)
{
+ m_options.emulated_i128 = Target_GetCurSpec().m_backend_c.m_emulated_i128;
switch(Target_GetCurSpec().m_backend_c.m_codegen_mode)
{
case CodegenMode::Gnu11:
m_compiler = Compiler::Gcc;
- m_options.emulated_i128 = false;
- if( Target_GetCurSpec().m_arch.m_pointer_bits < 64 )
+ if( Target_GetCurSpec().m_arch.m_pointer_bits < 64 && !m_options.emulated_i128 )
{
- m_options.emulated_i128 = true;
+ WARNING(Span(), W0000, "Potentially misconfigured target, 32-bit targets require i128 emulation");
}
m_options.disallow_empty_structs = true;
break;
case CodegenMode::Msvc:
m_compiler = Compiler::Msvc;
- m_options.emulated_i128 = true;
+ if( !m_options.emulated_i128 )
+ {
+ WARNING(Span(), W0000, "Potentially misconfigured target, MSVC requires i128 emulation");
+ }
m_options.disallow_empty_structs = true;
break;
}
diff --git a/src/trans/target.cpp b/src/trans/target.cpp
index 64cf19c6..332a7e04 100644
--- a/src/trans/target.cpp
+++ b/src/trans/target.cpp
@@ -17,27 +17,32 @@
const TargetArch ARCH_X86_64 = {
"x86_64",
64, false,
- { /*atomic(u8)=*/true, false, true, true, true }
+ { /*atomic(u8)=*/true, false, true, true, true },
+ { 2, 4, 8, 16, 4, 8, 8 },
};
const TargetArch ARCH_X86 = {
"x86",
32, false,
- { /*atomic(u8)=*/true, false, true, false, true }
+ { /*atomic(u8)=*/true, false, true, false, true },
+ { 2, 4, /*u64*/4, /*u128*/4, 4, 4, /*ptr*/4 } // u128 has the same alignment as u64, which is u32's alignment. And f64 is 4 byte aligned
};
const TargetArch ARCH_ARM64 = {
"aarch64",
64, false,
- { /*atomic(u8)=*/true, true, true, true, true }
+ { /*atomic(u8)=*/true, true, true, true, true },
+ { 2, 4, 8, 16, 4, 8, 8 },
};
const TargetArch ARCH_ARM32 = {
"arm",
32, false,
- { /*atomic(u8)=*/true, false, true, false, true }
+ { /*atomic(u8)=*/true, false, true, false, true },
+ { 2, 4, 8, 16, 4, 8, 4 } // Note, all types are natively aligned (but i128 will be emulated)
};
const TargetArch ARCH_M68K = {
"m68k",
32, true,
- { /*atomic(u8)=*/true, false, true, false, true }
+ { /*atomic(u8)=*/true, false, true, false, true },
+ { 2, 4, 8, 16, 4, 8, 4 } // TODO: Does m68k have lower alignments?
};
TargetSpec g_target;
@@ -159,6 +164,11 @@ namespace
check_path_length(key_val, 3);
rv.m_backend_c.m_c_compiler = key_val.value.as_string();
}
+ else if( key_val.path[2] == "emulate-i128" )
+ {
+ check_path_length(key_val, 3);
+ rv.m_backend_c.m_emulated_i128 = key_val.value.as_bool();
+ }
else if( key_val.path[2] == "compiler-opts" )
{
check_path_length(key_val, 3);
@@ -233,6 +243,42 @@ namespace
check_path_length(key_val, 2);
rv.m_arch.m_atomics.ptr = key_val.value.as_bool();
}
+ else if( key_val.path[1] == "alignments" )
+ {
+ check_path_length(key_val, 3);
+ if( key_val.path[2] == "u16" )
+ {
+ rv.m_arch.m_alignments.u16 = key_val.value.as_int();
+ }
+ else if( key_val.path[2] == "u32" )
+ {
+ rv.m_arch.m_alignments.u32 = key_val.value.as_int();
+ }
+ else if( key_val.path[2] == "u64" )
+ {
+ rv.m_arch.m_alignments.u64 = key_val.value.as_int();
+ }
+ else if( key_val.path[2] == "u128" )
+ {
+ rv.m_arch.m_alignments.u128 = key_val.value.as_int();
+ }
+ else if( key_val.path[2] == "f32" )
+ {
+ rv.m_arch.m_alignments.f32 = key_val.value.as_int();
+ }
+ else if( key_val.path[2] == "f64" )
+ {
+ rv.m_arch.m_alignments.f64 = key_val.value.as_int();
+ }
+ else if( key_val.path[2] == "ptr" )
+ {
+ rv.m_arch.m_alignments.ptr = key_val.value.as_int();
+ }
+ else
+ {
+ ::std::cerr << "WARNING: Unknown field arch.alignments." << key_val.path[1] << " in " << filename << ::std::endl;
+ }
+ }
else
{
::std::cerr << "WARNING: Unknown field arch." << key_val.path[1] << " in " << filename << ::std::endl;
@@ -290,10 +336,10 @@ namespace
<< "[backend.c]\n"
<< "variant = \"" << H::c_variant_name(spec.m_backend_c.m_codegen_mode) << "\"\n"
<< "target = \"" << spec.m_backend_c.m_c_compiler << "\"\n"
- << "compiler-opts = [" << spec.m_backend_c.m_compiler_opts << "]\n"
- << "linker-opts = [" << spec.m_backend_c.m_linker_opts << "]\n"
+ << "compiler-opts = ["; for(const auto& s : spec.m_backend_c.m_compiler_opts) of << "\"" << s << "\","; of << "]\n"
+ << "linker-opts = ["; for(const auto& s : spec.m_backend_c.m_linker_opts) of << "\"" << s << "\","; of << "]\n"
<< "\n"
- << "[arch]"
+ << "[arch]\n"
<< "name = \"" << spec.m_arch.m_name << "\"\n"
<< "pointer-bits = " << spec.m_arch.m_pointer_bits << "\n"
<< "is-big-endian = " << H::tfstr(spec.m_arch.m_big_endian) << "\n"
@@ -302,6 +348,16 @@ namespace
<< "has-atomic-u32 = " << H::tfstr(spec.m_arch.m_atomics.u32) << "\n"
<< "has-atomic-u64 = " << H::tfstr(spec.m_arch.m_atomics.u64) << "\n"
<< "has-atomic-ptr = " << H::tfstr(spec.m_arch.m_atomics.ptr) << "\n"
+ << "alignments = {"
+ << " u16 = " << static_cast<int>(spec.m_arch.m_alignments.u16 ) << ","
+ << " u32 = " << static_cast<int>(spec.m_arch.m_alignments.u32 ) << ","
+ << " u64 = " << static_cast<int>(spec.m_arch.m_alignments.u64 ) << ","
+ << " u128 = " << static_cast<int>(spec.m_arch.m_alignments.u128) << ","
+ << " f32 = " << static_cast<int>(spec.m_arch.m_alignments.f32 ) << ","
+ << " f64 = " << static_cast<int>(spec.m_arch.m_alignments.f64 ) << ","
+ << " ptr = " << static_cast<int>(spec.m_arch.m_alignments.ptr )
+ << " }\n"
+ << "\n"
;
}
TargetSpec init_from_spec_name(const ::std::string& target_name)
@@ -316,49 +372,49 @@ namespace
else if(target_name == "i586-linux-gnu")
{
return TargetSpec {
- "unix", "linux", "gnu", {CodegenMode::Gnu11, "i586-linux-gnu", BACKEND_C_OPTS_GNU},
+ "unix", "linux", "gnu", {CodegenMode::Gnu11, true, "i586-linux-gnu", BACKEND_C_OPTS_GNU},
ARCH_X86
};
}
else if(target_name == "x86_64-linux-gnu")
{
return TargetSpec {
- "unix", "linux", "gnu", {CodegenMode::Gnu11, "x86_64-linux-gnu", BACKEND_C_OPTS_GNU},
+ "unix", "linux", "gnu", {CodegenMode::Gnu11, false, "x86_64-linux-gnu", BACKEND_C_OPTS_GNU},
ARCH_X86_64
};
}
else if(target_name == "arm-linux-gnu")
{
return TargetSpec {
- "unix", "linux", "gnu", {CodegenMode::Gnu11, "arm-elf-eabi", BACKEND_C_OPTS_GNU},
+ "unix", "linux", "gnu", {CodegenMode::Gnu11, true, "arm-elf-eabi", BACKEND_C_OPTS_GNU},
ARCH_ARM32
};
}
else if(target_name == "aarch64-linux-gnu")
{
return TargetSpec {
- "unix", "linux", "gnu", {CodegenMode::Gnu11, "aarch64-linux-gnu", BACKEND_C_OPTS_GNU},
+ "unix", "linux", "gnu", {CodegenMode::Gnu11, false, "aarch64-linux-gnu", BACKEND_C_OPTS_GNU},
ARCH_ARM64
};
}
else if(target_name == "m68k-linux-gnu")
{
return TargetSpec {
- "unix", "linux", "gnu", {CodegenMode::Gnu11, "m68k-linux-gnu", BACKEND_C_OPTS_GNU},
+ "unix", "linux", "gnu", {CodegenMode::Gnu11, true, "m68k-linux-gnu", BACKEND_C_OPTS_GNU},
ARCH_M68K
};
}
else if(target_name == "i586-windows-gnu")
{
return TargetSpec {
- "windows", "windows", "gnu", {CodegenMode::Gnu11, "mingw32", BACKEND_C_OPTS_GNU},
+ "windows", "windows", "gnu", {CodegenMode::Gnu11, true, "mingw32", BACKEND_C_OPTS_GNU},
ARCH_X86
};
}
else if(target_name == "x86_64-windows-gnu")
{
return TargetSpec {
- "windows", "windows", "gnu", {CodegenMode::Gnu11, "x86_64-w64-mingw32", BACKEND_C_OPTS_GNU},
+ "windows", "windows", "gnu", {CodegenMode::Gnu11, false, "x86_64-w64-mingw32", BACKEND_C_OPTS_GNU},
ARCH_X86_64
};
}
@@ -366,84 +422,84 @@ namespace
{
// TODO: Should this include the "kernel32.lib" inclusion?
return TargetSpec {
- "windows", "windows", "msvc", {CodegenMode::Msvc, "x86", {}, {}},
+ "windows", "windows", "msvc", {CodegenMode::Msvc, true, "x86", {}, {}},
ARCH_X86
};
}
else if (target_name == "x86_64-windows-msvc")
{
return TargetSpec {
- "windows", "windows", "msvc", {CodegenMode::Msvc, "amd64", {}, {}},
+ "windows", "windows", "msvc", {CodegenMode::Msvc, true, "amd64", {}, {}},
ARCH_X86_64
};
}
else if(target_name == "i686-unknown-freebsd")
{
return TargetSpec {
- "unix", "freebsd", "gnu", {CodegenMode::Gnu11, "i686-unknown-freebsd", BACKEND_C_OPTS_GNU},
+ "unix", "freebsd", "gnu", {CodegenMode::Gnu11, true, "i686-unknown-freebsd", BACKEND_C_OPTS_GNU},
ARCH_X86
};
}
else if(target_name == "x86_64-unknown-freebsd")
{
return TargetSpec {
- "unix", "freebsd", "gnu", {CodegenMode::Gnu11, "x86_64-unknown-freebsd", BACKEND_C_OPTS_GNU},
+ "unix", "freebsd", "gnu", {CodegenMode::Gnu11, false, "x86_64-unknown-freebsd", BACKEND_C_OPTS_GNU},
ARCH_X86_64
};
}
else if(target_name == "arm-unknown-freebsd")
{
return TargetSpec {
- "unix", "freebsd", "gnu", {CodegenMode::Gnu11, "arm-unknown-freebsd", BACKEND_C_OPTS_GNU},
+ "unix", "freebsd", "gnu", {CodegenMode::Gnu11, true, "arm-unknown-freebsd", BACKEND_C_OPTS_GNU},
ARCH_ARM32
};
}
else if(target_name == "aarch64-unknown-freebsd")
{
return TargetSpec {
- "unix", "freebsd", "gnu", {CodegenMode::Gnu11, "aarch64-unknown-freebsd", BACKEND_C_OPTS_GNU},
+ "unix", "freebsd", "gnu", {CodegenMode::Gnu11, false, "aarch64-unknown-freebsd", BACKEND_C_OPTS_GNU},
ARCH_ARM64
};
}
else if(target_name == "x86_64-unknown-netbsd")
{
return TargetSpec {
- "unix", "netbsd", "gnu", {CodegenMode::Gnu11, "x86_64-unknown-netbsd", BACKEND_C_OPTS_GNU},
+ "unix", "netbsd", "gnu", {CodegenMode::Gnu11, false, "x86_64-unknown-netbsd", BACKEND_C_OPTS_GNU},
ARCH_X86_64
};
}
else if(target_name == "i686-unknown-openbsd")
{
return TargetSpec {
- "unix", "openbsd", "gnu", {CodegenMode::Gnu11, "i686-unknown-openbsd", BACKEND_C_OPTS_GNU},
+ "unix", "openbsd", "gnu", {CodegenMode::Gnu11, true, "i686-unknown-openbsd", BACKEND_C_OPTS_GNU},
ARCH_X86
};
}
else if(target_name == "x86_64-unknown-openbsd")
{
return TargetSpec {
- "unix", "openbsd", "gnu", {CodegenMode::Gnu11, "x86_64-unknown-openbsd", BACKEND_C_OPTS_GNU},
+ "unix", "openbsd", "gnu", {CodegenMode::Gnu11, false, "x86_64-unknown-openbsd", BACKEND_C_OPTS_GNU},
ARCH_X86_64
};
}
else if(target_name == "arm-unknown-openbsd")
{
return TargetSpec {
- "unix", "openbsd", "gnu", {CodegenMode::Gnu11, "arm-unknown-openbsd", BACKEND_C_OPTS_GNU},
+ "unix", "openbsd", "gnu", {CodegenMode::Gnu11, true, "arm-unknown-openbsd", BACKEND_C_OPTS_GNU},
ARCH_ARM32
};
}
else if(target_name == "aarch64-unknown-openbsd")
{
return TargetSpec {
- "unix", "openbsd", "gnu", {CodegenMode::Gnu11, "aarch64-unknown-openbsd", BACKEND_C_OPTS_GNU},
+ "unix", "openbsd", "gnu", {CodegenMode::Gnu11, false, "aarch64-unknown-openbsd", BACKEND_C_OPTS_GNU},
ARCH_ARM64
};
}
else if(target_name == "x86_64-unknown-dragonfly")
{
return TargetSpec {
- "unix", "dragonfly", "gnu", {CodegenMode::Gnu11, "x86_64-unknown-dragonfly", BACKEND_C_OPTS_GNU},
+ "unix", "dragonfly", "gnu", {CodegenMode::Gnu11, false, "x86_64-unknown-dragonfly", BACKEND_C_OPTS_GNU},
ARCH_X86_64
};
}
@@ -451,7 +507,7 @@ namespace
{
// NOTE: OSX uses Mach-O binaries, which don't fully support the defaults used for GNU targets
return TargetSpec {
- "unix", "macos", "gnu", {CodegenMode::Gnu11, "x86_64-apple-darwin", {}, {}},
+ "unix", "macos", "gnu", {CodegenMode::Gnu11, false, "x86_64-apple-darwin", {}, {}},
ARCH_X86_64
};
}
@@ -684,48 +740,45 @@ bool Target_GetSizeAndAlignOf(const Span& sp, const StaticTraitResolve& resolve,
case ::HIR::CoreType::U8:
case ::HIR::CoreType::I8:
out_size = 1;
- out_align = 1;
+ out_align = 1; // u8 is always 1 aligned
return true;
case ::HIR::CoreType::U16:
case ::HIR::CoreType::I16:
out_size = 2;
- out_align = 2;
+ out_align = g_target.m_arch.m_alignments.u16;
return true;
case ::HIR::CoreType::U32:
case ::HIR::CoreType::I32:
case ::HIR::CoreType::Char:
out_size = 4;
- out_align = 4;
+ out_align = g_target.m_arch.m_alignments.u32;
return true;
case ::HIR::CoreType::U64:
case ::HIR::CoreType::I64:
out_size = 8;
- // TODO: on x86, u64/i64 has an alignment of 4, while x86_64 has 8. What do other platforms have?
- out_align = g_target.m_arch.m_name == "x86" ? 4 : 8;
+ out_align = g_target.m_arch.m_alignments.u64;
return true;
case ::HIR::CoreType::U128:
case ::HIR::CoreType::I128:
out_size = 16;
// TODO: If i128 is emulated, this can be 8 (as it is on x86, where it's actually 4 due to the above comment)
- if( g_target.m_arch.m_name == "x86" )
- out_align = 4;
- else if( /*g_target.m_arch.m_name == "x86_64" && */g_target.m_backend_c.m_codegen_mode == CodegenMode::Msvc )
- out_align = 8;
- else
- out_align = 16;
+ if( g_target.m_backend_c.m_emulated_i128 )
+ out_align = g_target.m_arch.m_alignments.u64;
+ else
+ out_align = g_target.m_arch.m_alignments.u128;
return true;
case ::HIR::CoreType::Usize:
case ::HIR::CoreType::Isize:
out_size = g_target.m_arch.m_pointer_bits / 8;
- out_align = g_target.m_arch.m_pointer_bits / 8;
+ out_align = g_target.m_arch.m_alignments.ptr;
return true;
case ::HIR::CoreType::F32:
out_size = 4;
- out_align = 4;
+ out_align = g_target.m_arch.m_alignments.f32;
return true;
case ::HIR::CoreType::F64:
out_size = 8;
- out_align = g_target.m_arch.m_name == "x86" ? 4 : 8;
+ out_align = g_target.m_arch.m_alignments.f64;
return true;
case ::HIR::CoreType::Str:
DEBUG("sizeof on a `str` - unsized");
diff --git a/src/trans/target.hpp b/src/trans/target.hpp
index b1ed9456..b6f04a42 100644
--- a/src/trans/target.hpp
+++ b/src/trans/target.hpp
@@ -17,23 +17,35 @@ enum class CodegenMode
Msvc,
};
+// NOTE: The default architecture is an unnamed 32-bit little-endian arch with all types natively aligned
struct TargetArch
{
- ::std::string m_name;
- unsigned m_pointer_bits;
- bool m_big_endian;
+ ::std::string m_name = "";
+ unsigned m_pointer_bits = 32;
+ bool m_big_endian = false;
struct {
- bool u8;
- bool u16;
- bool u32;
- bool u64;
- bool ptr;
+ bool u8 = true;
+ bool u16 = true;
+ bool u32 = true;
+ bool u64 = false;
+ bool ptr = true;
} m_atomics;
+
+ struct {
+ uint8_t u16 = 2;
+ uint8_t u32 = 4;
+ uint8_t u64 = 8;
+ uint8_t u128 = 16;
+ uint8_t f32 = 4;
+ uint8_t f64 = 8;
+ uint8_t ptr = 4;
+ } m_alignments;
};
struct BackendOptsC
{
CodegenMode m_codegen_mode;
+ bool m_emulated_i128; // Influences the chosen alignment for i128/u128
::std::string m_c_compiler; // MSVC arch / GNU triplet
::std::vector< ::std::string> m_compiler_opts;
::std::vector< ::std::string> m_linker_opts;
diff --git a/tools/common/toml.cpp b/tools/common/toml.cpp
index 489f32b6..285d22a4 100644
--- a/tools/common/toml.cpp
+++ b/tools/common/toml.cpp
@@ -80,11 +80,8 @@ struct Token
};
TomlFile::TomlFile(const ::std::string& filename):
- m_if(filename)
+ m_lexer(filename)
{
- if( !m_if.is_open() ) {
- throw ::std::runtime_error("Unable to open file '" + filename + "'");
- }
}
TomlFileIter TomlFile::begin()
{
@@ -99,12 +96,14 @@ TomlFileIter TomlFile::end()
TomlKeyValue TomlFile::get_next_value()
{
- auto t = Token::lex_from(m_if);
+ auto t = m_lexer.get_token();
if(m_current_composite.empty())
{
while( t.m_type == Token::Type::Newline )
- t = Token::lex_from(m_if);
+ {
+ t = m_lexer.get_token();
+ }
// Expect '[', a string, or an identifier
switch(t.m_type)
@@ -116,32 +115,32 @@ TomlKeyValue TomlFile::get_next_value()
m_current_block.clear();
do
{
- t = Token::lex_from(m_if);
+ t = m_lexer.get_token();
bool is_array = false;
if(t.m_type == Token::Type::SquareOpen)
{
is_array = true;
- t = Token::lex_from(m_if);
+ t = m_lexer.get_token();
}
assert(t.m_type == Token::Type::Ident || t.m_type == Token::Type::String);
m_current_block.push_back(t.as_string());
if(is_array)
{
m_current_block.push_back(::format(m_array_counts[t.as_string()]++));
- t = Token::lex_from(m_if);
+ t = m_lexer.get_token();
assert(t.m_type == Token::Type::SquareClose);
}
- t = Token::lex_from(m_if);
+ t = m_lexer.get_token();
} while(t.m_type == Token::Type::Dot);
if( t.m_type != Token::Type::SquareClose )
{
- throw ::std::runtime_error(::format("Unexpected token in block header - ", t));
+ throw ::std::runtime_error(::format(m_lexer, ": Unexpected token in block header - ", t));
}
- t = Token::lex_from(m_if);
+ t = m_lexer.get_token();
if (t.m_type != Token::Type::Newline)
{
- throw ::std::runtime_error(::format("Unexpected token after block block - ", t));
+ throw ::std::runtime_error(::format(m_lexer, ": Unexpected token after block block - ", t));
}
DEBUG("Start block " << m_current_block);
// Recurse!
@@ -156,7 +155,7 @@ TomlKeyValue TomlFile::get_next_value()
if( t.m_type == Token::Type::Eof )
{
// EOF isn't allowed here
- throw ::std::runtime_error(::format("Unexpected EOF in composite"));
+ throw ::std::runtime_error(::format(m_lexer, ": Unexpected EOF in composite"));
}
}
switch (t.m_type)
@@ -165,14 +164,14 @@ TomlKeyValue TomlFile::get_next_value()
case Token::Type::Ident:
break;
default:
- throw ::std::runtime_error(::format("Unexpected token for key - ", t));
+ throw ::std::runtime_error(::format(m_lexer, ": Unexpected token for key - ", t));
}
::std::string key_name = t.as_string();
- t = Token::lex_from(m_if);
+ t = m_lexer.get_token();
if(t.m_type != Token::Type::Assign)
- throw ::std::runtime_error(::format("Unexpected token after key - ", t));
- t = Token::lex_from(m_if);
+ throw ::std::runtime_error(::format(m_lexer, ": Unexpected token after key - ", t));
+ t = m_lexer.get_token();
// --- Value ---
TomlKeyValue rv;
@@ -193,10 +192,12 @@ TomlKeyValue TomlFile::get_next_value()
rv.path.push_back(key_name);
rv.value.m_type = TomlValue::Type::List;
- while( (t = Token::lex_from(m_if)).m_type != Token::Type::SquareClose )
+ while( (t = m_lexer.get_token()).m_type != Token::Type::SquareClose )
{
while( t.m_type == Token::Type::Newline )
- t = Token::lex_from(m_if);
+ {
+ t = m_lexer.get_token();
+ }
if( t.m_type == Token::Type::SquareClose )
break;
@@ -208,15 +209,15 @@ TomlKeyValue TomlFile::get_next_value()
rv.value.m_sub_values.push_back(TomlValue { t.as_string() });
break;
default:
- throw ::std::runtime_error(::format("Unexpected token in array value position - ", t));
+ throw ::std::runtime_error(::format(m_lexer, ": Unexpected token in array value position - ", t));
}
- t = Token::lex_from(m_if);
+ t = m_lexer.get_token();
if(t.m_type != Token::Type::Comma)
break;
}
if(t.m_type != Token::Type::SquareClose)
- throw ::std::runtime_error(::format("Unexpected token after array - ", t));
+ throw ::std::runtime_error(::format(m_lexer, ": Unexpected token after array - ", t));
break;
case Token::Type::BraceOpen:
m_current_composite.push_back(key_name);
@@ -228,7 +229,7 @@ TomlKeyValue TomlFile::get_next_value()
rv.path.insert(rv.path.end(), m_current_composite.begin(), m_current_composite.end());
rv.path.push_back(key_name);
rv.value = TomlValue { t.m_intval };
- return rv;
+ break;
case Token::Type::Ident:
if( t.m_data == "true" )
{
@@ -247,34 +248,58 @@ TomlKeyValue TomlFile::get_next_value()
}
else
{
- throw ::std::runtime_error(::format("Unexpected identifier in value position - ", t));
+ throw ::std::runtime_error(::format(m_lexer, ": Unexpected identifier in value position - ", t));
}
break;
default:
- throw ::std::runtime_error(::format("Unexpected token in value position - ", t));
+ throw ::std::runtime_error(::format(m_lexer, ": Unexpected token in value position - ", t));
}
- t = Token::lex_from(m_if);
+ t = m_lexer.get_token();
while (!m_current_composite.empty() && t.m_type == Token::Type::BraceClose)
{
DEBUG("Leave composite block " << m_current_block << ", " << m_current_composite);
m_current_composite.pop_back();
- t = Token::lex_from(m_if);
+ t = m_lexer.get_token();
}
if( m_current_composite.empty() )
{
// TODO: Allow EOF?
if(t.m_type != Token::Type::Newline)
- throw ::std::runtime_error(::format("Unexpected token in TOML file after entry - ", t));
+ throw ::std::runtime_error(::format(m_lexer, ": Unexpected token in TOML file after entry - ", t));
}
else
{
if( t.m_type != Token::Type::Comma )
- throw ::std::runtime_error(::format("Unexpected token in TOML file after composite entry - ", t));
+ throw ::std::runtime_error(::format(m_lexer, ": Unexpected token in TOML file after composite entry - ", t));
}
return rv;
}
+TomlLexer::TomlLexer(const ::std::string& filename)
+ :m_if(filename)
+ ,m_filename(filename)
+ ,m_line(1)
+{
+ if( !m_if.is_open() ) {
+ throw ::std::runtime_error("Unable to open file '" + filename + "'");
+ }
+}
+Token TomlLexer::get_token()
+{
+ auto rv = Token::lex_from(m_if);
+ if( rv.m_type == Token::Type::Newline )
+ {
+ m_line ++;
+ }
+ return rv;
+}
+::std::ostream& operator<<(::std::ostream& os, const TomlLexer& x)
+{
+ os << x.m_filename << ":" << x.m_line;
+ return os;
+}
+
Token Token::lex_from(::std::ifstream& is)
{
auto rv = Token::lex_from_inner(is);
diff --git a/tools/common/toml.h b/tools/common/toml.h
index 4c97e7f2..17e05142 100644
--- a/tools/common/toml.h
+++ b/tools/common/toml.h
@@ -15,11 +15,28 @@
class TomlFileIter;
struct TomlKeyValue;
-class TomlFile
+struct Token;
+class TomlLexer
{
+ friend class TomlFile;
/// Input file stream
::std::ifstream m_if;
+ ::std::string m_filename;
+ unsigned m_line;
+protected:
+ TomlLexer(const ::std::string& filename);
+ Token get_token();
+
+public:
+ friend ::std::ostream& operator<<(::std::ostream& os, const TomlLexer& x);
+};
+
+class TomlFile
+{
+ /// Input file stream
+ TomlLexer m_lexer;
+
/// Name of the current `[]` block
::std::vector<::std::string> m_current_block;
@@ -40,6 +57,8 @@ public:
// Obtain the next value in the file
TomlKeyValue get_next_value();
+
+ const TomlLexer& lexer() const;
};
struct TomlValue