Newer
Older
dub_jkp / source / dub / internal / sdlang / token.d
@WebFreak001 WebFreak001 on 4 Feb 2023 16 KB fix typo(s)
  1. // SDLang-D
  2. // Written in the D programming language.
  3.  
  4. module dub.internal.sdlang.token;
  5.  
  6. version (Have_sdlang_d) public import sdlang.token;
  7. else:
  8.  
  9. import std.array;
  10. import std.base64;
  11. import std.conv;
  12. import std.datetime;
  13. import std.range;
  14. import std.string;
  15. import std.typetuple;
  16.  
  17. import dub.internal.dyaml.stdsumtype;
  18.  
  19. import dub.internal.sdlang.symbol;
  20. import dub.internal.sdlang.util;
  21.  
  22. /// DateTime doesn't support milliseconds, but SDL's "Date Time" type does.
  23. /// So this is needed for any SDL "Date Time" that doesn't include a time zone.
  24. struct DateTimeFrac
  25. {
  26. this(DateTime dt, Duration fs) { this.dateTime = dt; this.fracSecs = fs; }
  27.  
  28. DateTime dateTime;
  29. Duration fracSecs;
  30. }
  31.  
  32. /++
  33. If a "Date Time" literal in the SDL file has a time zone that's not found in
  34. your system, you get one of these instead of a SysTime. (Because it's
  35. impossible to indicate "unknown time zone" with 'std.datetime.TimeZone'.)
  36.  
  37. The difference between this and 'DateTimeFrac' is that 'DateTimeFrac'
  38. indicates that no time zone was specified in the SDL at all, whereas
  39. 'DateTimeFracUnknownZone' indicates that a time zone was specified but
  40. data for it could not be found on your system.
  41. +/
  42. struct DateTimeFracUnknownZone
  43. {
  44. DateTime dateTime;
  45. Duration fracSecs;
  46. string timeZone;
  47.  
  48. bool opEquals(const DateTimeFracUnknownZone b) const
  49. {
  50. return opEquals(b);
  51. }
  52. bool opEquals(ref const DateTimeFracUnknownZone b) const
  53. {
  54. return
  55. this.dateTime == b.dateTime &&
  56. this.fracSecs == b.fracSecs &&
  57. this.timeZone == b.timeZone;
  58. }
  59. }
  60.  
  61. /++
  62. SDL's data-types map to D's datatypes as described below.
  63. Most are straightforward, but take special note of the date/time-related types.
  64.  
  65. Boolean: bool
  66. Null: typeof(null)
  67. Unicode Character: dchar
  68. Double-Quote Unicode String: string
  69. Raw Backtick Unicode String: string
  70. Integer (32 bits signed): int
  71. Long Integer (64 bits signed): long
  72. Float (32 bits signed): float
  73. Double Float (64 bits signed): double
  74. Decimal (128+ bits signed): real
  75. Binary (standard Base64): ubyte[]
  76. Time Span: Duration
  77.  
  78. Date (with no time at all): Date
  79. Date Time (no timezone): DateTimeFrac
  80. Date Time (with a known timezone): SysTime
  81. Date Time (with an unknown timezone): DateTimeFracUnknownZone
  82. +/
  83. alias TypeTuple!(
  84. typeof(null),
  85. bool,
  86. string, dchar,
  87. int, long,
  88. float, double, real,
  89. Date, DateTimeFrac, SysTime, DateTimeFracUnknownZone, Duration,
  90. ubyte[],
  91. ) ValueTypes;
  92.  
  93. alias SumType!ValueTypes Value; /// ditto
  94.  
  95. template isSDLSink(T)
  96. {
  97. enum isSink =
  98. isOutputRange!T &&
  99. is(ElementType!(T)[] == string);
  100. }
  101.  
  102. string toSDLString(T)(T value) if(
  103. is( T : Value ) ||
  104. is( T : bool ) ||
  105. is( T : string ) ||
  106. is( T : dchar ) ||
  107. is( T : int ) ||
  108. is( T : long ) ||
  109. is( T : float ) ||
  110. is( T : double ) ||
  111. is( T : real ) ||
  112. is( T : Date ) ||
  113. is( T : DateTimeFrac ) ||
  114. is( T : SysTime ) ||
  115. is( T : DateTimeFracUnknownZone ) ||
  116. is( T : Duration ) ||
  117. is( T : ubyte[] ) ||
  118. is( T : typeof(null) )
  119. )
  120. {
  121. Appender!string sink;
  122. toSDLString(value, sink);
  123. return sink.data;
  124. }
  125.  
  126. void toSDLString(Sink)(Value value, ref Sink sink) if(isOutputRange!(Sink,char))
  127. {
  128. value.match!(v => toSDLString(v, sink));
  129. }
  130.  
  131. void toSDLString(Sink)(typeof(null) value, ref Sink sink) if(isOutputRange!(Sink,char))
  132. {
  133. sink.put("null");
  134. }
  135.  
  136. void toSDLString(Sink)(bool value, ref Sink sink) if(isOutputRange!(Sink,char))
  137. {
  138. sink.put(value? "true" : "false");
  139. }
  140.  
  141. //TODO: Figure out how to properly handle strings/chars containing lineSep or paraSep
  142. void toSDLString(Sink)(string value, ref Sink sink) if(isOutputRange!(Sink,char))
  143. {
  144. sink.put('"');
  145.  
  146. // This loop is UTF-safe
  147. foreach(char ch; value)
  148. {
  149. if (ch == '\n') sink.put(`\n`);
  150. else if(ch == '\r') sink.put(`\r`);
  151. else if(ch == '\t') sink.put(`\t`);
  152. else if(ch == '\"') sink.put(`\"`);
  153. else if(ch == '\\') sink.put(`\\`);
  154. else
  155. sink.put(ch);
  156. }
  157.  
  158. sink.put('"');
  159. }
  160.  
  161. void toSDLString(Sink)(dchar value, ref Sink sink) if(isOutputRange!(Sink,char))
  162. {
  163. sink.put('\'');
  164.  
  165. if (value == '\n') sink.put(`\n`);
  166. else if(value == '\r') sink.put(`\r`);
  167. else if(value == '\t') sink.put(`\t`);
  168. else if(value == '\'') sink.put(`\'`);
  169. else if(value == '\\') sink.put(`\\`);
  170. else
  171. sink.put(value);
  172.  
  173. sink.put('\'');
  174. }
  175.  
  176. void toSDLString(Sink)(int value, ref Sink sink) if(isOutputRange!(Sink,char))
  177. {
  178. sink.put( "%s".format(value) );
  179. }
  180.  
  181. void toSDLString(Sink)(long value, ref Sink sink) if(isOutputRange!(Sink,char))
  182. {
  183. sink.put( "%sL".format(value) );
  184. }
  185.  
  186. void toSDLString(Sink)(float value, ref Sink sink) if(isOutputRange!(Sink,char))
  187. {
  188. sink.put( "%.10sF".format(value) );
  189. }
  190.  
  191. void toSDLString(Sink)(double value, ref Sink sink) if(isOutputRange!(Sink,char))
  192. {
  193. sink.put( "%.30sD".format(value) );
  194. }
  195.  
  196. void toSDLString(Sink)(real value, ref Sink sink) if(isOutputRange!(Sink,char))
  197. {
  198. sink.put( "%.30sBD".format(value) );
  199. }
  200.  
  201. void toSDLString(Sink)(Date value, ref Sink sink) if(isOutputRange!(Sink,char))
  202. {
  203. sink.put(to!string(value.year));
  204. sink.put('/');
  205. sink.put(to!string(cast(int)value.month));
  206. sink.put('/');
  207. sink.put(to!string(value.day));
  208. }
  209.  
  210. void toSDLString(Sink)(DateTimeFrac value, ref Sink sink) if(isOutputRange!(Sink,char))
  211. {
  212. toSDLString(value.dateTime.date, sink);
  213. sink.put(' ');
  214. sink.put("%.2s".format(value.dateTime.hour));
  215. sink.put(':');
  216. sink.put("%.2s".format(value.dateTime.minute));
  217.  
  218. if(value.dateTime.second != 0)
  219. {
  220. sink.put(':');
  221. sink.put("%.2s".format(value.dateTime.second));
  222. }
  223.  
  224. if(value.fracSecs.total!"msecs" != 0)
  225. {
  226. sink.put('.');
  227. sink.put("%.3s".format(value.fracSecs.total!"msecs"));
  228. }
  229. }
  230.  
  231. void toSDLString(Sink)(SysTime value, ref Sink sink) if(isOutputRange!(Sink,char))
  232. {
  233. auto dateTimeFrac = DateTimeFrac(cast(DateTime)value, value.fracSecs);
  234. toSDLString(dateTimeFrac, sink);
  235.  
  236. sink.put("-");
  237.  
  238. auto tzString = value.timezone.name;
  239.  
  240. // If name didn't exist, try abbreviation.
  241. // Note that according to std.datetime docs, on Windows the
  242. // stdName/dstName may not be properly abbreviated.
  243. version(Windows) {} else
  244. if(tzString == "")
  245. {
  246. auto tz = value.timezone;
  247. auto stdTime = value.stdTime;
  248.  
  249. if(tz.hasDST())
  250. tzString = tz.dstInEffect(stdTime)? tz.dstName : tz.stdName;
  251. else
  252. tzString = tz.stdName;
  253. }
  254.  
  255. if(tzString == "")
  256. {
  257. auto offset = value.timezone.utcOffsetAt(value.stdTime);
  258. sink.put("GMT");
  259.  
  260. if(offset < seconds(0))
  261. {
  262. sink.put("-");
  263. offset = -offset;
  264. }
  265. else
  266. sink.put("+");
  267.  
  268. long hours, minutes;
  269. offset.split!("hours", "minutes")(hours, minutes);
  270.  
  271. sink.put("%.2s".format(hours));
  272. sink.put(":");
  273. sink.put("%.2s".format(minutes));
  274. }
  275. else
  276. sink.put(tzString);
  277. }
  278.  
  279. void toSDLString(Sink)(DateTimeFracUnknownZone value, ref Sink sink) if(isOutputRange!(Sink,char))
  280. {
  281. auto dateTimeFrac = DateTimeFrac(value.dateTime, value.fracSecs);
  282. toSDLString(dateTimeFrac, sink);
  283.  
  284. sink.put("-");
  285. sink.put(value.timeZone);
  286. }
  287.  
  288. void toSDLString(Sink)(Duration value, ref Sink sink) if(isOutputRange!(Sink,char))
  289. {
  290. if(value < seconds(0))
  291. {
  292. sink.put("-");
  293. value = -value;
  294. }
  295.  
  296. auto days = value.total!"days"();
  297. if(days != 0)
  298. {
  299. sink.put("%s".format(days));
  300. sink.put("d:");
  301. }
  302.  
  303. long hours, minutes, seconds, msecs;
  304. value.split!("hours", "minutes", "seconds", "msecs")(hours, minutes, seconds, msecs);
  305.  
  306. sink.put("%.2s".format(hours));
  307. sink.put(':');
  308. sink.put("%.2s".format(minutes));
  309. sink.put(':');
  310. sink.put("%.2s".format(seconds));
  311.  
  312. if(msecs != 0)
  313. {
  314. sink.put('.');
  315. sink.put("%.3s".format(msecs));
  316. }
  317. }
  318.  
  319. void toSDLString(Sink)(ubyte[] value, ref Sink sink) if(isOutputRange!(Sink,char))
  320. {
  321. sink.put('[');
  322. sink.put( Base64.encode(value) );
  323. sink.put(']');
  324. }
  325.  
  326. /// This only represents terminals. Non-terminals aren't
  327. /// constructed since the AST is directly built during parsing.
  328. struct Token
  329. {
  330. Symbol symbol = dub.internal.sdlang.symbol.symbol!"Error"; /// The "type" of this token
  331. Location location;
  332. Value value; /// Only valid when 'symbol' is symbol!"Value", otherwise null
  333. string data; /// Original text from source
  334.  
  335. @disable this();
  336. this(Symbol symbol, Location location, Value value=Value(null), string data=null)
  337. {
  338. this.symbol = symbol;
  339. this.location = location;
  340. this.value = value;
  341. this.data = data;
  342. }
  343.  
  344. /// Tokens with differing symbols are always unequal.
  345. /// Tokens with differing values are always unequal.
  346. /// Tokens with differing Value types are always unequal.
  347. /// Member 'location' is always ignored for comparison.
  348. /// Member 'data' is ignored for comparison *EXCEPT* when the symbol is Ident.
  349. bool opEquals(Token b)
  350. {
  351. return opEquals(b);
  352. }
  353. bool opEquals(ref Token b) ///ditto
  354. {
  355. if(
  356. this.symbol != b.symbol ||
  357. this.value != b.value
  358. )
  359. return false;
  360.  
  361. if(this.symbol == .symbol!"Ident")
  362. return this.data == b.data;
  363.  
  364. return true;
  365. }
  366.  
  367. bool matches(string symbolName)()
  368. {
  369. return this.symbol == .symbol!symbolName;
  370. }
  371. }
  372.  
  373. version(sdlangUnittest)
  374. unittest
  375. {
  376. import std.stdio;
  377. writeln("Unittesting sdlang token...");
  378. stdout.flush();
  379.  
  380. auto loc = Location("", 0, 0, 0);
  381. auto loc2 = Location("a", 1, 1, 1);
  382.  
  383. assert(Token(symbol!"EOL",loc) == Token(symbol!"EOL",loc ));
  384. assert(Token(symbol!"EOL",loc) == Token(symbol!"EOL",loc2));
  385. assert(Token(symbol!":", loc) == Token(symbol!":", loc ));
  386. assert(Token(symbol!"EOL",loc) != Token(symbol!":", loc ));
  387. assert(Token(symbol!"EOL",loc,Value(null),"\n") == Token(symbol!"EOL",loc,Value(null),"\n"));
  388.  
  389. assert(Token(symbol!"EOL",loc,Value(null),"\n") == Token(symbol!"EOL",loc,Value(null),";" ));
  390. assert(Token(symbol!"EOL",loc,Value(null),"A" ) == Token(symbol!"EOL",loc,Value(null),"B" ));
  391. assert(Token(symbol!":", loc,Value(null),"A" ) == Token(symbol!":", loc,Value(null),"BB"));
  392. assert(Token(symbol!"EOL",loc,Value(null),"A" ) != Token(symbol!":", loc,Value(null),"A" ));
  393.  
  394. assert(Token(symbol!"Ident",loc,Value(null),"foo") == Token(symbol!"Ident",loc,Value(null),"foo"));
  395. assert(Token(symbol!"Ident",loc,Value(null),"foo") != Token(symbol!"Ident",loc,Value(null),"BAR"));
  396.  
  397. assert(Token(symbol!"Value",loc,Value(null),"foo") == Token(symbol!"Value",loc, Value(null),"foo"));
  398. assert(Token(symbol!"Value",loc,Value(null),"foo") == Token(symbol!"Value",loc2,Value(null),"foo"));
  399. assert(Token(symbol!"Value",loc,Value(null),"foo") == Token(symbol!"Value",loc, Value(null),"BAR"));
  400. assert(Token(symbol!"Value",loc,Value( 7),"foo") == Token(symbol!"Value",loc, Value( 7),"BAR"));
  401. assert(Token(symbol!"Value",loc,Value( 7),"foo") != Token(symbol!"Value",loc, Value( "A"),"foo"));
  402. assert(Token(symbol!"Value",loc,Value( 7),"foo") != Token(symbol!"Value",loc, Value( 2),"foo"));
  403. assert(Token(symbol!"Value",loc,Value(cast(int)7)) != Token(symbol!"Value",loc, Value(cast(long)7)));
  404. assert(Token(symbol!"Value",loc,Value(cast(float)1.2)) != Token(symbol!"Value",loc, Value(cast(double)1.2)));
  405. }
  406.  
  407. version(sdlangUnittest)
  408. unittest
  409. {
  410. import std.stdio;
  411. writeln("Unittesting sdlang Value.toSDLString()...");
  412. stdout.flush();
  413.  
  414. // Bool and null
  415. assert(Value(null ).toSDLString() == "null");
  416. assert(Value(true ).toSDLString() == "true");
  417. assert(Value(false).toSDLString() == "false");
  418.  
  419. // Base64 Binary
  420. assert(Value(cast(ubyte[])"hello world".dup).toSDLString() == "[aGVsbG8gd29ybGQ=]");
  421.  
  422. // Integer
  423. assert(Value(cast( int) 7).toSDLString() == "7");
  424. assert(Value(cast( int)-7).toSDLString() == "-7");
  425. assert(Value(cast( int) 0).toSDLString() == "0");
  426.  
  427. assert(Value(cast(long) 7).toSDLString() == "7L");
  428. assert(Value(cast(long)-7).toSDLString() == "-7L");
  429. assert(Value(cast(long) 0).toSDLString() == "0L");
  430.  
  431. // Floating point
  432. assert(Value(cast(float) 1.5).toSDLString() == "1.5F");
  433. assert(Value(cast(float)-1.5).toSDLString() == "-1.5F");
  434. assert(Value(cast(float) 0).toSDLString() == "0F");
  435.  
  436. assert(Value(cast(double) 1.5).toSDLString() == "1.5D");
  437. assert(Value(cast(double)-1.5).toSDLString() == "-1.5D");
  438. assert(Value(cast(double) 0).toSDLString() == "0D");
  439.  
  440. assert(Value(cast(real) 1.5).toSDLString() == "1.5BD");
  441. assert(Value(cast(real)-1.5).toSDLString() == "-1.5BD");
  442. assert(Value(cast(real) 0).toSDLString() == "0BD");
  443.  
  444. // String
  445. assert(Value("hello" ).toSDLString() == `"hello"`);
  446. assert(Value(" hello ").toSDLString() == `" hello "`);
  447. assert(Value("" ).toSDLString() == `""`);
  448. assert(Value("hello \r\n\t\"\\ world").toSDLString() == `"hello \r\n\t\"\\ world"`);
  449. assert(Value("日本語").toSDLString() == `"日本語"`);
  450.  
  451. // Chars
  452. assert(Value(cast(dchar) 'A').toSDLString() == `'A'`);
  453. assert(Value(cast(dchar)'\r').toSDLString() == `'\r'`);
  454. assert(Value(cast(dchar)'\n').toSDLString() == `'\n'`);
  455. assert(Value(cast(dchar)'\t').toSDLString() == `'\t'`);
  456. assert(Value(cast(dchar)'\'').toSDLString() == `'\''`);
  457. assert(Value(cast(dchar)'\\').toSDLString() == `'\\'`);
  458. assert(Value(cast(dchar) '月').toSDLString() == `'月'`);
  459.  
  460. // Date
  461. assert(Value(Date( 2004,10,31)).toSDLString() == "2004/10/31");
  462. assert(Value(Date(-2004,10,31)).toSDLString() == "-2004/10/31");
  463.  
  464. // DateTimeFrac w/o Frac
  465. assert(Value(DateTimeFrac(DateTime(2004,10,31, 14,30,15))).toSDLString() == "2004/10/31 14:30:15");
  466. assert(Value(DateTimeFrac(DateTime(2004,10,31, 1, 2, 3))).toSDLString() == "2004/10/31 01:02:03");
  467. assert(Value(DateTimeFrac(DateTime(-2004,10,31, 14,30,15))).toSDLString() == "-2004/10/31 14:30:15");
  468.  
  469. // DateTimeFrac w/ Frac
  470. assert(Value(DateTimeFrac(DateTime(2004,10,31, 14,30,15), 123.msecs)).toSDLString() == "2004/10/31 14:30:15.123");
  471. assert(Value(DateTimeFrac(DateTime(2004,10,31, 14,30,15), 120.msecs)).toSDLString() == "2004/10/31 14:30:15.120");
  472. assert(Value(DateTimeFrac(DateTime(2004,10,31, 14,30,15), 100.msecs)).toSDLString() == "2004/10/31 14:30:15.100");
  473. assert(Value(DateTimeFrac(DateTime(2004,10,31, 14,30,15), 12.msecs)).toSDLString() == "2004/10/31 14:30:15.012");
  474. assert(Value(DateTimeFrac(DateTime(2004,10,31, 14,30,15), 1.msecs)).toSDLString() == "2004/10/31 14:30:15.001");
  475. assert(Value(DateTimeFrac(DateTime(-2004,10,31, 14,30,15), 123.msecs)).toSDLString() == "-2004/10/31 14:30:15.123");
  476.  
  477. // DateTimeFracUnknownZone
  478. assert(Value(DateTimeFracUnknownZone(DateTime(2004,10,31, 14,30,15), 123.msecs, "Foo/Bar")).toSDLString() == "2004/10/31 14:30:15.123-Foo/Bar");
  479.  
  480. // SysTime
  481. assert(Value(SysTime(DateTime(2004,10,31, 14,30,15), new immutable SimpleTimeZone( hours(0) ))).toSDLString() == "2004/10/31 14:30:15-GMT+00:00");
  482. assert(Value(SysTime(DateTime(2004,10,31, 1, 2, 3), new immutable SimpleTimeZone( hours(0) ))).toSDLString() == "2004/10/31 01:02:03-GMT+00:00");
  483. assert(Value(SysTime(DateTime(2004,10,31, 14,30,15), new immutable SimpleTimeZone( hours(2)+minutes(10) ))).toSDLString() == "2004/10/31 14:30:15-GMT+02:10");
  484. assert(Value(SysTime(DateTime(2004,10,31, 14,30,15), new immutable SimpleTimeZone(-hours(5)-minutes(30) ))).toSDLString() == "2004/10/31 14:30:15-GMT-05:30");
  485. assert(Value(SysTime(DateTime(2004,10,31, 14,30,15), new immutable SimpleTimeZone( hours(2)+minutes( 3) ))).toSDLString() == "2004/10/31 14:30:15-GMT+02:03");
  486. assert(Value(SysTime(DateTime(2004,10,31, 14,30,15), 123.msecs, new immutable SimpleTimeZone( hours(0) ))).toSDLString() == "2004/10/31 14:30:15.123-GMT+00:00");
  487.  
  488. // Duration
  489. assert( "12:14:42" == Value( days( 0)+hours(12)+minutes(14)+seconds(42)+msecs( 0)).toSDLString());
  490. assert("-12:14:42" == Value(-days( 0)-hours(12)-minutes(14)-seconds(42)-msecs( 0)).toSDLString());
  491. assert( "00:09:12" == Value( days( 0)+hours( 0)+minutes( 9)+seconds(12)+msecs( 0)).toSDLString());
  492. assert( "00:00:01.023" == Value( days( 0)+hours( 0)+minutes( 0)+seconds( 1)+msecs( 23)).toSDLString());
  493. assert( "23d:05:21:23.532" == Value( days(23)+hours( 5)+minutes(21)+seconds(23)+msecs(532)).toSDLString());
  494. assert( "23d:05:21:23.530" == Value( days(23)+hours( 5)+minutes(21)+seconds(23)+msecs(530)).toSDLString());
  495. assert( "23d:05:21:23.500" == Value( days(23)+hours( 5)+minutes(21)+seconds(23)+msecs(500)).toSDLString());
  496. assert("-23d:05:21:23.532" == Value(-days(23)-hours( 5)-minutes(21)-seconds(23)-msecs(532)).toSDLString());
  497. assert("-23d:05:21:23.500" == Value(-days(23)-hours( 5)-minutes(21)-seconds(23)-msecs(500)).toSDLString());
  498. assert( "23d:05:21:23" == Value( days(23)+hours( 5)+minutes(21)+seconds(23)+msecs( 0)).toSDLString());
  499. }