1 module bamboo.util;
2 
3 import bamboo.types;
4 
5 /// Generates a hashmap of builtin types.
6 Type[string] genbuiltins()
7 {
8     import std.algorithm : map;
9     import std.conv : to;
10     import std.traits : EnumMembers;
11     import std.typecons : tuple;
12 
13     Type[string] types;
14 
15     enum arr = [EnumMembers!Type].map!(x => tuple(x, x.to!string));
16 
17     foreach (item; arr)
18     {
19         types[item[1]] = item[0];
20     }
21 
22     return types;
23 }
24 
25 /++
26 Interpolated string (ie, variable expansion).
27 Any D expression can be placed inside ${ and }. Everything between the curly
28 braces will be evaluated inside your current scope, and passed as a parameter
29 (or parameters) to std.conv.text.
30 The curly braces do NOT nest, so variable expansion will end at the first
31 closing brace. If the closing brace is missing, an Exception will be thrown
32 at compile-time.
33 Author: https://github.com/Abscissa
34 License: zlib/libpng
35 Example:
36 ------------
37 // Output: The number 21 doubled is 42!
38 int num = 21;
39 writeln( mixin(interp!"The number ${num} doubled is ${num * 2}!") );
40 // Output: Empty braces output nothing.
41 writeln( mixin(interp!"Empty ${}braces ${}output nothing.") );
42 // Output: Multiple params: John Doe.
43 auto first = "John", last = "Doe";
44 writeln( mixin(interp!`Multiple params: ${first, " ", last}.`) );
45 ------------
46 +/
47 string interp(string str)()
48 {
49 	enum State
50 	{
51 		normal,
52 		dollar,
53 		code,
54 	}
55 
56 	auto state = State.normal;
57 
58 	string buf;
59 	buf ~= '`';
60 
61 	foreach(char c; str)
62 	final switch(state)
63 	{
64 	case State.normal:
65 		if(c == '$')
66 			// Delay copying the $ until we find out whether it's
67 			// the start of an escape sequence.
68 			state = State.dollar;
69 		else if(c == '`')
70 			buf ~= "`~\"`\"~`";
71 		else
72 			buf ~= c;
73 		break;
74 
75 	case State.dollar:
76 		if(c == '{')
77 		{
78 			state = State.code;
79 			buf ~= "`~_interp_text(";
80 		}
81 		else if(c == '$')
82 			buf ~= '$'; // Copy the previous $
83 		else
84 		{
85 			buf ~= '$'; // Copy the previous $
86 			buf ~= c;
87 			state = State.normal;
88 		}
89 		break;
90 
91 	case State.code:
92 		if(c == '}')
93 		{
94 			buf ~= ")~`";
95 			state = State.normal;
96 		}
97 		else
98 			buf ~= c;
99 		break;
100 	}
101 	
102 	// Finish up
103 	final switch(state)
104 	{
105 	case State.normal:
106 		buf ~= '`';
107 		break;
108 
109 	case State.dollar:
110 		buf ~= "$`"; // Copy the previous $
111 		break;
112 
113 	case State.code:
114 		throw new Exception(
115 			"Interpolated string contains an unterminated expansion. "~
116 			"You're missing a closing curly brace."
117 		);
118 	}
119 
120 	return buf;
121 }
122 string _interp_text(T...)(T args)
123 {
124     static import std.conv;
125 	static if(T.length == 0)
126 		return null;
127 	else
128 		return std.conv.text(args);
129 }