1 /** 2 This module contains a example grammar rules to parse different kind of numbers literals. 3 */ 4 module pegged.examples.numbers; 5 6 import pegged.grammar; 7 8 /// Numbers 9 mixin(grammar(` 10 Numbers: 11 Scientific <~ Floating ( ('e' / 'E' ) Integer )? 12 Floating <~ Integer ('.' Unsigned )? 13 Unsigned <~ [0-9]+ 14 Integer <~ Sign? Unsigned 15 Hexa <~ [0-9a-fA-F]+ 16 Binary <~ "0b" [01] [01_]* 17 Sign <- '-' / '+' 18 `)); 19 20 unittest 21 { 22 string[] testNumbers = 23 [ 24 "0", "0.0", "0.01", 25 "-0", "+0", "-0.0", "+0.0", 26 "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", 27 "0123456789", 28 "123", "123.0", "123.01", "-123", "-123.0", "-123.01", 29 "-123e+12", "-123e-12", "+123e+12", "+123e-12", "-123E+12", "-123E-12", "+123E+12", "+123E-12", 30 "123.456e+00", "123.456E+00", "123.456e-00", "123.456E-00", 31 "-123.456e+00", "-123.456E+00", "-123.456e-00", "-123.456E-00", 32 "+123.456e+00", "+123.456E+00", "+123.456e-00", "+123.456E-00" 33 ]; 34 35 foreach(number; testNumbers) 36 { 37 const parseTree = Numbers(number); 38 auto match = parseTree.matches; 39 assert(parseTree.successful, "Expected to parse successfully number " ~ number); 40 assert(match == [number], "Expected " ~ number ~ " but was " ~ match[0]); // Shall parse 41 } 42 43 // Failures 44 testNumbers = 45 [ 46 ".", ".0", "0.", "123..456", 47 "", "abc", "+", "-", "+.", "-.", 48 "--1", "++1", "+-1", "-+1", 49 "1e", "1e+", "1e-","1ee" 50 ]; 51 52 foreach(number; testNumbers) 53 { 54 assert(Numbers(number).matches != [number], "Number \"" ~ number ~ "\" musn't be parsed"); // None shall parse 55 } 56 57 // Hexadecimal numbers 58 testNumbers = 59 [ 60 "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", 61 "A", "B", "C", "D", "E", "F", 62 "a", "b", "c", "d", "e", "f", 63 "0123456789ABCDEF", 64 "0123456789abcdef", 65 "DEADBEEF", "0123BEEF", "DEAD0123", 66 "deadbeef", "0123beef", "dead0123", 67 "123E", "123e" 68 ]; 69 70 foreach(number; testNumbers) 71 { 72 const parseTree = Numbers.decimateTree(Numbers.Hexa(number)); 73 auto match = parseTree.matches; 74 assert(parseTree.successful, "Expected to parse successfully number " ~ number); 75 assert(match == [number], "Expected " ~ number ~ " but was " ~ match[0]); // Shall parse 76 } 77 78 // Hexadecimal failures 79 testNumbers = 80 [ 81 "", "G", "g", "-1", "123.456", "123e+100" 82 ]; 83 84 foreach(number; testNumbers) 85 { 86 assert(Numbers.decimateTree(Numbers.Hexa(number)).matches != [number], 87 "Number \"" ~ number ~ "\" musn't be parsed"); // None shall parse 88 } 89 90 // Binary numbers 91 testNumbers = 92 [ 93 "0b0", "0b1", "0b0000", "0b0001", "0b11110000", "0b0000_1111", "0b1010_00_11" 94 ]; 95 96 foreach(number; testNumbers) 97 { 98 const parseTree = Numbers.decimateTree(Numbers.Binary(number)); 99 auto match = parseTree.matches; 100 assert(parseTree.successful, "Expected to parse successfully number " ~ number); 101 assert(match == [number], "Expected " ~ number ~ " but was " ~ match[0]); // Shall parse 102 } 103 104 // Hexadecimal failures 105 testNumbers = 106 [ 107 "", "G", "g", "-1", "123.456", "123e+100", "0b", "01010", "0b3456" 108 ]; 109 110 foreach(number; testNumbers) 111 { 112 assert(Numbers.decimateTree(Numbers.Binary(number)).matches != [number], 113 "Number \"" ~ number ~ "\" musn't be parsed"); // None shall parse 114 } 115 }