How to create compile-time container?
Steven Schveighoffer
schveiguy at gmail.com
Wed Sep 2 14:38:30 UTC 2020
On 9/2/20 5:56 AM, Andrey Zherikov wrote:
> ==============
> Everything works well until I have included scripts in subdirectories:
> ├── dir1
> │ ├── dir2
> │ │ └── script
> │ └── script
> └── script
> Content:
> ============== script
> msg hello
> include dir1/script
> ============== dir1/script
> msg hello from dir1
> include dir2/script
> ============== dir1/dir2/script
> msg hello from dir1/dir2
> ==============
>
> Compilation fails with "Error: file `"dir2/script"` cannot be found or
> not in a path specified with `-J`" (I used simple dmd -J. -run parser.d)
> which is expected because parse* functions do not track the directory
> where the script is located.
>
> In this simple example the issue can be fixed by passing path to script
> as a parameter to parseScript function. But this doesn't seem to be
> flexible and extendable solution because there can be other commands
> that might call parseFile indirectly (they can even be in other modules).
>
> Theoretically this can be solved by doing something like this but it
> doesn't work because "static variable `paths` cannot be read at compile
> time":
> ==============
> string[] paths;
> void parseFile(string file)()
> {
> enum path = paths.length > 0 ? buildPath(paths[$-1],
> file.dirName()) : file.dirName();
>
> paths ~= path;
> scope(exit) paths = paths[0..$-1];
>
> enum script = import(buildPath(path, file));
> mixin(parseScript(script));
> }
> ==============
> Note that the whole point is to do this parsing at compile time.
OK, NOW I see where your code is coming from. The issue is that you need
the directory of the script imported to be the "local directory". Your
solution will not work -- you can't mixin code that is not available at
compile time.
Here is what I would do instead:
string parseScript(string filename, string script)
{
string code;
string base = dirName(filename);
if(base[$-1] != '/') base ~= '/';
foreach(line; script.lineSplitter())
{
auto idx = line.indexOf(' ');
switch(line[0..idx])
{
case "msg":
code ~= "writeln(\"" ~ line[idx+1..$] ~ "\");";
break;
case "include":
{
code ~= `parseFile!"`;
string importfile = line[idx+1 .. $];
if(!importfile.startsWith('/')) // relative path
code ~= base;
code ~= importfile ~ `";`;
break;
}
default: break;
}
}
return code;
}
And pass the filename to this function in addition to the script source.
-Steve
More information about the Digitalmars-d-learn
mailing list