diff options
Diffstat (limited to 'tools')
| -rw-r--r-- | tools/minicargo/build.cpp | 47 | ||||
| -rw-r--r-- | tools/minicargo/helpers.h | 176 | ||||
| -rw-r--r-- | tools/minicargo/main.cpp | 39 | ||||
| -rw-r--r-- | tools/minicargo/manifest.cpp | 109 | ||||
| -rw-r--r-- | tools/minicargo/manifest.h | 39 | ||||
| -rw-r--r-- | tools/minicargo/repository.cpp | 70 | ||||
| -rw-r--r-- | tools/minicargo/repository.h | 29 | ||||
| -rw-r--r-- | tools/minicargo/toml.cpp | 13 | ||||
| -rw-r--r-- | tools/minicargo/toml.h | 19 | 
9 files changed, 499 insertions, 42 deletions
| diff --git a/tools/minicargo/build.cpp b/tools/minicargo/build.cpp index ace0dd13..352a4dcd 100644 --- a/tools/minicargo/build.cpp +++ b/tools/minicargo/build.cpp @@ -18,6 +18,7 @@ struct BuildList      };      ::std::vector<BuildEnt>  m_list; +    void add_dependencies(const PackageManifest& p, unsigned level);      void add_package(const PackageManifest& p, unsigned level);      void sort_list(); @@ -85,13 +86,16 @@ private:  void MiniCargo_Build(const PackageManifest& manifest)  {      BuildList   list; -    // Generate sorted dependency list -    for (const auto& dep : manifest.dependencies()) + +    list.add_dependencies(manifest, 0); + +    list.sort_list(); +    // dedup? +    for(const auto& p : list.iter())      { -        list.add_package(dep.get_package(), 1); +        DEBUG("WILL BUILD " << p.name() << " from " << p.manifest_path());      } -      // Build dependencies      Builder builder;      for(const auto& p : list.iter()) @@ -106,6 +110,17 @@ void MiniCargo_Build(const PackageManifest& manifest)      builder.build_library(manifest);  } +void BuildList::add_dependencies(const PackageManifest& p, unsigned level) +{ +    for (const auto& dep : p.dependencies()) +    { +        if( dep.is_optional() ) +        { +            continue ; +        } +        add_package(dep.get_package(), level+1); +    } +}  void BuildList::add_package(const PackageManifest& p, unsigned level)  {      for(auto& ent : m_list) @@ -125,17 +140,32 @@ void BuildList::add_package(const PackageManifest& p, unsigned level)  void BuildList::sort_list()  {      ::std::sort(m_list.begin(), m_list.end(), [](const auto& a, const auto& b){ return a.level < b.level; }); + +    for(auto it = m_list.begin(); it != m_list.end(); ) +    { +        auto it2 = ::std::find_if(m_list.begin(), it, [&](const auto& x){ return x.package == it->package; }); +        if( it2 != it ) +        { +            it = m_list.erase(it); +        } +        else +        { +            ++it; +        } +    }  }  bool Builder::build_target(const PackageManifest& manifest, const PackageTarget& target) const  { -    auto outfile = ::helpers::path("output") / ::format("lib", target.m_name, ".hir"); +    auto outdir = ::helpers::path("output"); +    auto outfile = outdir / ::format("lib", target.m_name, ".hir");      StringList  args;      args.push_back(::helpers::path(manifest.manifest_path()).parent() / ::helpers::path(target.m_path));      args.push_back("--crate-name"); args.push_back(target.m_name.c_str());      args.push_back("--crate-type"); args.push_back("rlib");      args.push_back("-o"); args.push_back(outfile); +    args.push_back("-L"); args.push_back(outdir);      return this->spawn_process(args, outfile + "_dbg.txt");  } @@ -157,6 +187,7 @@ bool Builder::spawn_process(const StringList& args, const ::helpers::path& logfi      STARTUPINFO si = { 0 };      si.cb = sizeof(si); +#if 1      si.dwFlags = STARTF_USESTDHANDLES;      si.hStdInput = NULL;      si.hStdError = GetStdHandle(STD_ERROR_HANDLE); @@ -169,8 +200,12 @@ bool Builder::spawn_process(const StringList& args, const ::helpers::path& logfi          WriteFile(si.hStdOutput, cmdline_str.data(), cmdline_str.size(), &tmp, NULL);          WriteFile(si.hStdOutput, "\n", 1, &tmp, NULL);      } +#endif      PROCESS_INFORMATION pi = { 0 }; -    CreateProcessA("x64\\Release\\mrustc.exe", (LPSTR)cmdline_str.c_str(), NULL, NULL, TRUE, 0, "MRUSTC_DEBUG=\0", NULL, &si, &pi); +    char env[] = +        "MRUSTC_DEBUG=""\0" +        ; +    CreateProcessA("x64\\Release\\mrustc.exe", (LPSTR)cmdline_str.c_str(), NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi);      CloseHandle(si.hStdOutput);      WaitForSingleObject(pi.hProcess, INFINITE);      DWORD status = 1; diff --git a/tools/minicargo/helpers.h b/tools/minicargo/helpers.h index d9fe7e3c..35e791f1 100644 --- a/tools/minicargo/helpers.h +++ b/tools/minicargo/helpers.h @@ -4,14 +4,37 @@  namespace helpers { +class string_view +{ +    const char* m_start; +    const size_t m_len; +public: +    string_view(const char* s, size_t n): +        m_start(s), m_len(n) +    { +    } + +    bool operator==(const ::std::string& s) const { +        return *this == s.c_str(); +    } +    bool operator==(const char* s) const { +        if(::std::strncmp(m_start, s, m_len) != 0) +            return false; +        return s[m_len] == '\0'; +    } +    friend ::std::string& operator+=(::std::string& x, const string_view& sv) { +        x.append(sv.m_start, sv.m_start+sv.m_len); +        return x; +    } +};  /// Path helper class (because I don't want to include boost)  class path  {  #ifdef _WIN32 -    const char SEP = '\\'; +    static const char SEP = '\\';  #else -    const char SEP = '/'; +    static const char SEP = '/';  #endif      ::std::string   m_str; @@ -96,6 +119,155 @@ public:          return m_str;      } +    class ComponentsIter +    { +        const path& p; +        size_t  pos; +        size_t  end; + +        friend class path; +        ComponentsIter(const path& p, size_t i): p(p), pos(i) { +            end = p.m_str.find(SEP, pos); +            if(end == ::std::string::npos) +                end = p.m_str.size(); +        } +    public: +        string_view operator*() const { +            return string_view(p.m_str.c_str() + pos, end - pos); +        } +        void operator++() { +            if(end == p.m_str.size()) +                pos = end; +            else +            { +                pos = end+1; +                end = p.m_str.find(SEP, pos); +                if(end == ::std::string::npos) +                    end = p.m_str.size(); +            } +        } +        bool operator!=(const ComponentsIter& x) const { +            return pos != x.pos; +        } +    }; +    ComponentsIter begin() const { +        return ComponentsIter(*this, 0); +    } +    ComponentsIter end() const { +        return ComponentsIter(*this, m_str.size()); +    } + +    path normalise() const +    { +        path rv; +        rv.m_str.reserve( m_str.size()+1 ); + +        for(auto comp : *this) +        { +            if( comp == "." ) { +                // Ignore. +            } +            else if( comp == ".." ) +            { +                // If the path is empty, OR the last element is a "..", push the element +                if( rv.m_str.empty() +                 || (rv.m_str.size() == 3 && rv.m_str[0] == '.' && rv.m_str[1] == '.' && rv.m_str[2] == SEP) +                 || (rv.m_str.size() > 4 && *(rv.m_str.end()-4) == SEP && *(rv.m_str.end()-3) == '.' && *(rv.m_str.end()-2) == '.' && *(rv.m_str.end()-1) == SEP ) +                    ) +                { +                    // Push +                    rv.m_str += comp; +                    rv.m_str += SEP; +                } +                else +                { +                    rv.m_str.pop_back(); +                    auto pos = rv.m_str.find_last_of(SEP); +                    if(pos == ::std::string::npos) +                    { +                        rv.m_str.resize(0); +                    } +                    else if( pos == 0 ) +                    { +                        // Keep. +                    } +                    else +                    { +                        rv.m_str.resize(pos+1); +                    } +                } +            } +            else { +                rv.m_str += comp; +                rv.m_str += SEP; +            } +        } +        rv.m_str.pop_back(); +        return rv; +    } +#if 0 +    void normalise_in_place() +    { +        size_t insert_point = 0; + +        for(size_t read_pos = 0; read_pos < m_str.size(); read_pos ++) +        { +            auto pos = m_str.find_first_of(SEP, read_pos); +            if(pos == ::std::string::npos) +                pos = m_str.size(); +            auto comp = string_view(m_str.c_str() + read_pos, pos - read_pos); + +            bool append; +            if(comp == ".") +            { +                // Advance read without touching insert +                append = false; +            } +            else if( comp == ".." ) +            { +                // Consume parent (if not a relative component already) +                // Move insertion point back to the previous separator +                auto pos = m_str.find_last_of(SEP, insert_point); +                if(pos == ::std::string::npos) +                { +                    // Only one component currently (or empty) +                    append = true; +                } +                else if(string_view(m_str.c_str() + pos+1, insert_point - pos-1) == "..") +                { +                    // Last component is ".." - keep adding +                    append = true; +                } +                else +                { +                    insert_point = pos; +                    append = false; +                } +            } +            else +            { +                append = true; +            } + +            if(append) +            { +                if( read_pos != insert_point ) +                { +                    //assert(read_pos > insert_point); +                    while(read_pos < pos) +                    { +                        m_str[insert_point++] = m_str[read_pos++]; +                    } +                } +            } +            else +            { +                read_pos = pos; +            } +        } +    } +#endif +      friend ::std::ostream& operator<<(::std::ostream& os, const path& p)      {          return os << p.m_str; diff --git a/tools/minicargo/main.cpp b/tools/minicargo/main.cpp index c2fe4c2e..236b9d77 100644 --- a/tools/minicargo/main.cpp +++ b/tools/minicargo/main.cpp @@ -6,9 +6,11 @@   */  #include <iostream>  #include <cstring>  // strcmp +#include <map>  #include "debug.h"  #include "manifest.h"  #include "helpers.h" +#include "repository.h"  extern void MiniCargo_Build(const PackageManifest& manifest); @@ -22,6 +24,8 @@ struct ProgramOptions      const char* output_directory = nullptr; +    const char* vendor_dir = nullptr; +      int parse(int argc, const char* argv[]);      void usage() const;  }; @@ -33,19 +37,34 @@ int main(int argc, const char* argv[])          return 1;      } -    // 1. Load the Cargo.toml file from the passed directory -    auto m = PackageManifest::load_from_toml( ::helpers::path(opts.directory ? opts.directory : ".") / "Cargo.toml" ); +    try +    { +        // Load package database +        Repository repo; +        // TODO: load repository from a local cache +        if( opts.vendor_dir ) +        { +            repo.load_vendored(opts.vendor_dir); +        } + +        // 1. Load the Cargo.toml file from the passed directory +        auto dir = ::helpers::path(opts.directory ? opts.directory : "."); +        auto m = PackageManifest::load_from_toml( dir / "Cargo.toml" ); + +        m.load_dependencies(repo); -    // 2. Recursively load dependency manifests -    for(const auto& dep : m.dependencies()) +        // 3. Build dependency tree +        MiniCargo_Build(m); +    } +    catch(const ::std::exception& e)      { -        throw "TODO: Deps"; +        ::std::cerr << "EXCEPTION: " << e.what() << ::std::endl; +        ::std::cout << "Press enter to exit..." << ::std::endl; +        ::std::cin.get(); +        return 1;      } -    // 3. Build dependency tree -    MiniCargo_Build(m); - -    ::std::cout << "Press any key to exit..." << ::std::endl; +    ::std::cout << "Press enter to exit..." << ::std::endl;      ::std::cin.get();      return 0;  } @@ -106,9 +125,9 @@ void ProgramOptions::usage() const  } -  void Debug_Print(::std::function<void(::std::ostream& os)> cb)  {      cb(::std::cout);      ::std::cout << ::std::endl;  } + diff --git a/tools/minicargo/manifest.cpp b/tools/minicargo/manifest.cpp index 90bb68a5..d068b7bf 100644 --- a/tools/minicargo/manifest.cpp +++ b/tools/minicargo/manifest.cpp @@ -6,10 +6,7 @@  #include "helpers.h"  #include <cassert>  #include <algorithm> -#include <sstream> -#ifdef _WIN32 -#include <Windows.h> -#endif +#include "repository.h"  static ::std::vector<::std::shared_ptr<PackageManifest>>    g_loaded_manifests; @@ -32,6 +29,7 @@ PackageManifest PackageManifest::load_from_toml(const ::std::string& path)      for(auto key_val : toml_file)      {          assert(key_val.path.size() > 0); +        DEBUG(key_val.path << " = " << key_val.value);          const auto& section = key_val.path[0];          if( section == "package" )          { @@ -60,6 +58,20 @@ PackageManifest PackageManifest::load_from_toml(const ::std::string& path)              {                  rv.m_version = PackageVersion::from_string(key_val.value.as_string());              } +            else if( key == "build" ) +            { +                if(rv.m_build_script != "" ) +                { +                    // TODO: Warn/error +                    throw ::std::runtime_error("Build script path set twice"); +                } +                rv.m_build_script = key_val.value.as_string(); +                if(rv.m_build_script == "") +                { +                    // TODO: Error +                    throw ::std::runtime_error("Build script path cannot be empty"); +                } +            }              else              {                  // Unknown value in `package` @@ -145,22 +157,28 @@ PackageManifest PackageManifest::load_from_toml(const ::std::string& path)                      // Set path specification of the named depenency                      ref.m_path = key_val.value.as_string();                  } -                else if (attr == "git") +                else if( attr == "git" )                  {                      // Load from git repo.                      TODO("Support git dependencies");                  } -                else if (attr == "branch") +                else if( attr == "branch" )                  {                      // Specify git branch                      TODO("Support git dependencies (branch)");                  } -                else if( attr == "version") +                else if( attr == "version" )                  {                      assert(key_val.path.size() == 3);                      // Parse version specifier                      ref.m_version = PackageVersionSpec::from_string(key_val.value.as_string());                  } +                else if( attr == "optional" ) +                { +                    assert(key_val.path.size() == 3); +                    ref.m_optional = key_val.value.as_bool(); +                    // TODO: Add a feature with the same name as the dependency. +                }                  else                  {                      // TODO: Error @@ -168,11 +186,23 @@ PackageManifest PackageManifest::load_from_toml(const ::std::string& path)                  }              }          } +        else if( section == "build-dependencies" ) +        { +            // TODO: Build deps +        }          else if( section == "patch" )          {              //const auto& repo = key_val.path[1];              TODO("Support repository patches");          } +        else if( section == "target" ) +        { +            // TODO: Target opts? +        } +        else if( section == "features" ) +        { +            // TODO: Features +        }          else          {              // Unknown manifest section @@ -203,36 +233,40 @@ namespace              assert(kv.path.size() == base_idx + 1);              target.m_enable_test = kv.value.as_bool();          } -        else if (key == "doctest") +        else if( key == "doctest" )          {              assert(kv.path.size() == base_idx + 1);              target.m_enable_doctest = kv.value.as_bool();          } -        else if (key == "bench") +        else if( key == "bench" )          {              assert(kv.path.size() == base_idx + 1);              target.m_enable_bench = kv.value.as_bool();          } -        else if (key == "doc") +        else if( key == "doc" )          {              assert(kv.path.size() == base_idx + 1);              target.m_enable_doc = kv.value.as_bool();          } -        else if (key == "plugin") +        else if( key == "plugin" )          {              assert(kv.path.size() == base_idx + 1);              target.m_is_plugin = kv.value.as_bool();          } -        else if (key == "proc-macro") +        else if( key == "proc-macro" )          {              assert(kv.path.size() == base_idx + 1);              target.m_is_proc_macro = kv.value.as_bool();          } -        else if (key == "harness") +        else if( key == "harness" )          {              assert(kv.path.size() == base_idx + 1);              target.m_is_own_harness = kv.value.as_bool();          } +        else if( key == "crate-type" ) +        { +            // TODO: Support crate types +        }          else          {              throw ::std::runtime_error( ::format("TODO: Handle target option `", key, "`") ); @@ -250,10 +284,49 @@ const PackageTarget& PackageManifest::get_library() const      return *it;  } -const PackageManifest& PackageRef::get_package() const +void PackageManifest::load_dependencies(Repository& repo)  { -    DEBUG("TODO: PackageRef::get_package()"); -    throw ""; +    DEBUG("Loading depencencies for " << m_name); +    auto base_path = ::helpers::path(m_manifest_path).parent(); + +    // 2. Recursively load dependency manifests +    for(auto& dep : m_dependencies) +    { +        if( dep.m_optional ) +        { +            // TODO: Check for feature that enables this (option to a feature with no '/') +            continue ; +        } +        dep.load_manifest(repo, base_path); +    } +} + +void PackageRef::load_manifest(Repository& repo, const ::helpers::path& base_path) +{ +    // If the path isn't set, check for: +    // - Git (checkout and use) +    // - Version and repository (check vendored, check cache, download into cache) +    if( ! this->has_path() ) +    { +        if( this->has_git() ) +        { +            DEBUG("Load dependency " << this->name() << " from git"); +            throw "TODO: Git"; +        } +        else +        { +            DEBUG("Load dependency " << this->name() << " from repo"); +            m_manifest = repo.find(this->name(), this->get_version()); +        } +    } +    else +    { +        DEBUG("Load dependency " << m_name << " from path " << m_path); +        // Search for a copy of this already loaded +        m_manifest = repo.from_path(base_path / ::helpers::path(m_path) / "Cargo.toml"); +    } + +    m_manifest->load_dependencies(repo);  }  PackageVersion PackageVersion::from_string(const ::std::string& s) @@ -275,4 +348,8 @@ PackageVersionSpec PackageVersionSpec::from_string(const ::std::string& s)      PackageVersionSpec  rv;      throw "";      return rv; +} +bool PackageVersionSpec::accepts(const PackageVersion& v) const +{ +    throw "";  }
\ No newline at end of file diff --git a/tools/minicargo/manifest.h b/tools/minicargo/manifest.h index 054347fb..0e6c2d81 100644 --- a/tools/minicargo/manifest.h +++ b/tools/minicargo/manifest.h @@ -3,8 +3,10 @@  #include <string>  #include <vector>  #include <memory> +#include "helpers.h"  class PackageManifest; +class Repository;  struct PackageVersion  { @@ -13,6 +15,15 @@ struct PackageVersion      unsigned patch;      static PackageVersion from_string(const ::std::string& s); +    bool operator<(const PackageVersion& x) const { +        if( major < x.major )   return true; +        if( major > x.major )   return false; +        if( minor < x.minor )   return true; +        if( minor > x.minor )   return false; +        if( minor < x.patch )   return true; +        if( patch > x.patch )   return false; +        return false; +    }  };  struct PackageVersionSpec  { @@ -28,10 +39,14 @@ struct PackageVersionSpec          Type    ty;          PackageVersion  ver;      }; +    // TODO: Just upper and lower?      ::std::vector<Bound>   m_bounds; -    // TODO: Just upper and lower? +    // Construct from a string      static PackageVersionSpec from_string(const ::std::string& s); + +    /// Check if this spec accepts the passed version +    bool accepts(const PackageVersion& v) const;  };  class PackageRef @@ -40,6 +55,7 @@ class PackageRef      ::std::string   m_name;      PackageVersionSpec  m_version; +    bool m_optional = false;      ::std::string   m_path;      ::std::shared_ptr<PackageManifest> m_manifest; @@ -49,7 +65,22 @@ class PackageRef      }  public: -    const PackageManifest& get_package() const; +    const ::std::string& name() const { return m_name; } +    //const ::std::string& get_repo_name() const  { return m_repo; } +    const PackageVersionSpec& get_version() const { return m_version; } + +    bool is_optional() const { return m_optional; } + +    const bool has_path() const { return m_path != ""; } +    const ::std::string& path() const { return m_path; } +    const bool has_git() const { return false; } + +    const PackageManifest& get_package() const { +        if(!m_manifest) throw ::std::runtime_error("Manifest not loaded for package " + m_name); +        return *m_manifest; +    } + +    void load_manifest(Repository& repo, const ::helpers::path& base_path);  };  struct PackageTarget @@ -98,6 +129,8 @@ class PackageManifest      ::std::string   m_name;      PackageVersion  m_version; +    ::std::string   m_build_script; +      ::std::vector<PackageRef>   m_dependencies;      ::std::vector<PackageTarget>    m_targets; @@ -122,4 +155,6 @@ public:      const ::std::vector<PackageRef>& dependencies() const {          return m_dependencies;      } +     +    void load_dependencies(Repository& repo);  }; diff --git a/tools/minicargo/repository.cpp b/tools/minicargo/repository.cpp new file mode 100644 index 00000000..0a097f66 --- /dev/null +++ b/tools/minicargo/repository.cpp @@ -0,0 +1,70 @@ +/* + */ +#include "repository.h" +#include "debug.h" + +void Repository::load_cache(const ::helpers::path& path) +{ +    throw ""; +} +void Repository::load_vendored(const ::helpers::path& path) +{ +    // Enumerate folders in this folder, try to open Cargo.toml files +    // Extract package name and version from each manifest +} + +::std::shared_ptr<PackageManifest> Repository::from_path(::helpers::path path) +{ +    DEBUG("Repository::from_path(" << path << ")"); +    // 1. Normalise path +    path = path.normalise(); +    DEBUG("path = " << path); + +    auto it = m_path_cache.find(path); +    if(it == m_path_cache.end()) +    { +        ::std::shared_ptr<PackageManifest> rv ( new PackageManifest(PackageManifest::load_from_toml(path)) ); + +        m_path_cache.insert( ::std::make_pair(::std::move(path), rv) ); + +        return rv; +    } +    else +    { +        return it->second; +    } +} +::std::shared_ptr<PackageManifest> Repository::find(const ::std::string& name, const PackageVersionSpec& version) +{ +    auto itp = m_cache.equal_range(name); + +    Entry* best = nullptr; +    for(auto i = itp.first; i != itp.second; ++i) +    { +        if( version.accepts(i->second.version) ) +        { +            if( !best || best->version < i->second.version ) +            { +                best = &i->second; +            } +        } +    } + +    if( best ) +    { +        if( !best->loaded_manifest ) +        { +            if( best->manifest_path == "" ) +            { +                throw "TODO: Download package"; +            } +            best->loaded_manifest = ::std::shared_ptr<PackageManifest>( new PackageManifest(PackageManifest::load_from_toml(best->manifest_path)) ); +        } + +        return best->loaded_manifest; +    } +    else +    { +        return {}; +    } +} diff --git a/tools/minicargo/repository.h b/tools/minicargo/repository.h new file mode 100644 index 00000000..0b186077 --- /dev/null +++ b/tools/minicargo/repository.h @@ -0,0 +1,29 @@ +#pragma once + +#include <string> +#include <map> +#include "helpers.h" +#include "manifest.h" + +class Repository +{ +    struct Entry +    { +        /// Path to the Cargo.toml file in the package root +        ::std::string   manifest_path; +        /// Package version +        PackageVersion  version; +        /// (Cached) loaded manifest +        ::std::shared_ptr<PackageManifest>  loaded_manifest; +    }; + +    ::std::multimap<::std::string, Entry>    m_cache; +    // path => manifest +    ::std::map<::std::string, ::std::shared_ptr<PackageManifest>>   m_path_cache; +public: +    void load_cache(const ::helpers::path& path); +    void load_vendored(const ::helpers::path& path); + +    ::std::shared_ptr<PackageManifest> from_path(::helpers::path path); +    ::std::shared_ptr<PackageManifest> find(const ::std::string& name, const PackageVersionSpec& version); +}; diff --git a/tools/minicargo/toml.cpp b/tools/minicargo/toml.cpp index 7d4b0685..fe81fa3c 100644 --- a/tools/minicargo/toml.cpp +++ b/tools/minicargo/toml.cpp @@ -158,14 +158,14 @@ TomlKeyValue TomlFile::get_next_value()      {      case Token::Type::String:          rv.path = m_current_block; -        rv.path.insert(rv.path.begin(), m_current_composite.begin(), m_current_composite.end()); +        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_data };          break;      case Token::Type::SquareOpen:          rv.path = m_current_block; -        rv.path.insert(rv.path.begin(), m_current_composite.begin(), m_current_composite.end()); +        rv.path.insert(rv.path.end(), m_current_composite.begin(), m_current_composite.end());          rv.path.push_back(key_name);          rv.value.m_type = TomlValue::Type::List; @@ -197,14 +197,14 @@ TomlKeyValue TomlFile::get_next_value()          if( t.m_data == "true" )          {              rv.path = m_current_block; -            rv.path.insert(rv.path.begin(), m_current_composite.begin(), m_current_composite.end()); +            rv.path.insert(rv.path.end(), m_current_composite.begin(), m_current_composite.end());              rv.path.push_back(key_name);              rv.value = TomlValue { true };          }          else if( t.m_data == "false" )          {              rv.path = m_current_block; -            rv.path.insert(rv.path.begin(), m_current_composite.begin(), m_current_composite.end()); +            rv.path.insert(rv.path.end(), m_current_composite.begin(), m_current_composite.end());              rv.path.push_back(key_name);              rv.value = TomlValue { false }; @@ -242,7 +242,7 @@ TomlKeyValue TomlFile::get_next_value()  Token Token::lex_from(::std::ifstream& is)  {      auto rv = Token::lex_from_inner(is); -    DEBUG("lex_from: " << rv); +    //DEBUG("lex_from: " << rv);      return rv;  }  Token Token::lex_from_inner(::std::ifstream& is) @@ -307,7 +307,7 @@ Token Token::lex_from_inner(::std::ifstream& is)          if(isalpha(c))          {              // Identifier -            while(isalnum(c) || c == '-') +            while(isalnum(c) || c == '-' || c == '_')              {                  str += (char)c;                  c = is.get(); @@ -317,6 +317,7 @@ Token Token::lex_from_inner(::std::ifstream& is)          }          else          { +            throw ::std::runtime_error(::format("Unexpected chracter '", (char)c, "' in file"));              throw "";          }      } diff --git a/tools/minicargo/toml.h b/tools/minicargo/toml.h index 1c8f90d5..17517ca3 100644 --- a/tools/minicargo/toml.h +++ b/tools/minicargo/toml.h @@ -2,6 +2,7 @@  #include <fstream>  #include <vector> +#include <string>  #include <unordered_map>  class TomlFileIter; @@ -91,6 +92,24 @@ struct TomlValue          }          return m_int_value != 0;      } + +    friend ::std::ostream& operator<<(::std::ostream& os, const TomlValue& x) { +        switch(x.m_type) +        { +        case Type::Boolean: os << (x.m_int_value != 0 ? "true" : "false");  break; +        case Type::Integer: os << x.m_int_value; break; +        case Type::List: +            os << "["; +            for(auto& e : x.m_sub_values) +                os << e << ","; +            os << "]"; +            break; +        case Type::String: +            os << "\"" << x.m_str_value << "\""; +            break; +        } +        return os; +    }  };  struct TomlKeyValue | 
