yum-mirror/slang
Making it easier to work with shaders
git clone https://git.yummers.dev/yum-mirror/slang
7b570feed
master
1 2#include "../../source/compiler-core/slang-json-lexer.h" 3#include "../../source/compiler-core/slang-json-parser.h" 4#include "../../source/compiler-core/slang-json-value.h" 5#include "../../source/core/slang-string-escape-util.h" 6#include "unit-test/slang-unit-test.h" 7 8using namespace Slang ; 9 10namespace 11{// anonymous 12 13struct Element 14{ 15JSONTokenType type ; 16const char * value ; 17}; 18 19}// namespace 20 21static SlangResult _lex (const char * in ,DiagnosticSink * sink ,List < JSONToken >& toks ) 22{ 23SourceManager * sourceManager = sink -> getSourceManager (); 24 25String contents (in ); 26SourceFile * sourceFile = 27sourceManager -> createSourceFileWithString (PathInfo ::makeUnknown (),contents ); 28SourceView * sourceView = sourceManager -> createSourceView (sourceFile ,nullptr ,SourceLoc ()); 29 30JSONLexer lexer ; 31 32lexer .init (sourceView ,sink ); 33 34while (lexer .peekType ()!= JSONTokenType ::EndOfFile ) 35 { 36if (lexer .peekType ()== JSONTokenType ::Invalid ) 37 { 38toks .add (lexer .peekToken ()); 39return SLANG_FAIL ; 40 } 41 42toks .add (lexer .peekToken ()); 43lexer .advance (); 44 } 45 46toks .add (lexer .peekToken ()); 47 48// If we advance from end of file we should still be at EndOfFile 49SLANG_ASSERT (lexer .advance ()== JSONTokenType ::EndOfFile ); 50 51return SLANG_OK ; 52} 53 54static SlangResult _parse (const char * in ,DiagnosticSink * sink ,JSONListener * listener ) 55{ 56SourceManager * sourceManager = sink -> getSourceManager (); 57 58String contents (in ); 59SourceFile * sourceFile = 60sourceManager -> createSourceFileWithString (PathInfo ::makeUnknown (),contents ); 61SourceView * sourceView = sourceManager -> createSourceView (sourceFile ,nullptr ,SourceLoc ()); 62 63JSONLexer lexer ; 64lexer .init (sourceView ,sink ); 65 66JSONParser parser ; 67SLANG_RETURN_ON_FAIL (parser .parse (& lexer ,sourceView ,listener ,sink )); 68return SLANG_OK ; 69} 70 71static bool _areEqual ( 72SourceManager * sourceManager , 73const List < JSONToken >& toks , 74const Element * eles , 75Index elesCount ) 76{ 77if (toks .getCount ()!= elesCount ) 78 { 79return false; 80 } 81 82SourceView * sourceView = toks .getCount () ?sourceManager -> findSourceView (toks [0 ].loc ) :nullptr ; 83const char * const content = sourceView ?sourceView -> getContent ().begin () :nullptr ; 84 85for (Index i = 0 ;i < toks .getCount ();++ i ) 86 { 87const JSONToken & tok = toks [i ]; 88const auto & ele = eles [i ]; 89 90if (tok .type != ele .type ) 91 { 92return false; 93 } 94 95SLANG_ASSERT (sourceView -> getRange ().contains (tok .loc )); 96 97const char * start = content + sourceView -> getRange ().getOffset (tok .loc ); 98 99UnownedStringSlice lexeme (start ,tok .length ); 100 101if (lexeme != ele .value ) 102 { 103return false; 104 } 105 } 106 107return true; 108} 109 110SLANG_UNIT_TEST (json ) 111{ 112SourceManager sourceManager ; 113sourceManager .initialize (nullptr ,nullptr ); 114DiagnosticSink sink (& sourceManager ,nullptr ); 115 116 { 117const char text []= 118" { \"Hello\" : [ \"World\", 1, 2.0, -3.0, -435.5345435, 45e-10, 421.00e+20, 17e1] }" ; 119 120const Element eles []= { 121 {JSONTokenType ::LBrace ,"{" }, 122 {JSONTokenType ::StringLiteral ,"\"Hello\"" }, 123 {JSONTokenType ::Colon ,":" }, 124 {JSONTokenType ::LBracket ,"[" }, 125 {JSONTokenType ::StringLiteral ,"\"World\"" }, 126 {JSONTokenType ::Comma ,"," }, 127 {JSONTokenType ::IntegerLiteral ,"1" }, 128 {JSONTokenType ::Comma ,"," }, 129 {JSONTokenType ::FloatLiteral ,"2.0" }, 130 {JSONTokenType ::Comma ,"," }, 131 {JSONTokenType ::FloatLiteral ,"-3.0" }, 132 {JSONTokenType ::Comma ,"," }, 133 {JSONTokenType ::FloatLiteral ,"-435.5345435" }, 134 {JSONTokenType ::Comma ,"," }, 135 {JSONTokenType ::FloatLiteral ,"45e-10" }, 136 {JSONTokenType ::Comma ,"," }, 137 {JSONTokenType ::FloatLiteral ,"421.00e+20" }, 138 {JSONTokenType ::Comma ,"," }, 139 {JSONTokenType ::FloatLiteral ,"17e1" }, 140 {JSONTokenType ::RBracket ,"]" }, 141 {JSONTokenType ::RBrace ,"}" }, 142 {JSONTokenType ::EndOfFile ,"" }, 143 }; 144 145List < JSONToken > toks ; 146SLANG_CHECK (SLANG_SUCCEEDED (_lex (text ,& sink ,toks ))); 147 148SLANG_CHECK (_areEqual (& sourceManager ,toks ,eles ,SLANG_COUNT_OF (eles ))); 149 } 150 151 { 152StringEscapeHandler * handler = StringEscapeUtil ::getHandler (StringEscapeUtil ::Style ::JSON ); 153 154 155 { 156const auto slice = UnownedStringSlice ::fromLiteral ("\n\r\b\f\t \"\\/ Some text..." ); 157 158SLANG_CHECK (handler -> isEscapingNeeded (slice )); 159SLANG_CHECK (!handler -> isEscapingNeeded (UnownedStringSlice ::fromLiteral ("Hello!" ))); 160 161StringBuilder escaped ; 162handler -> appendEscaped (slice ,escaped ); 163 164StringBuilder unescaped ; 165handler -> appendUnescaped (escaped .getUnownedSlice (),unescaped ); 166 167SLANG_CHECK (unescaped == slice ); 168 } 169 170 { 171uint32_t v = 0x7f ; 172 173StringBuilder buf ; 174while (v < 0x10000 ) 175 { 176char work [10 ]= "\\u" ; 177 178for (Int i = 0 ;i < 4 ;++ i ) 179 { 180const uint32_t digitValue = (v >> ((3 - i )* 4 ))& 0xf ; 181 182char digitC = 183 (digitValue > 9 ) ?char (digitValue - 10 + 'a' ) :char (digitValue + '0' ); 184work [i + 2 ]= digitC ; 185 } 186 187buf <<UnownedStringSlice (work ,6 ); 188 189v += v ; 190 } 191 192// Decode it 193StringBuilder unescaped ; 194handler -> appendUnescaped (buf .getUnownedSlice (),unescaped ); 195 196// Encode it 197StringBuilder escaped ; 198handler -> appendEscaped (unescaped .getUnownedSlice (),escaped ); 199 200SLANG_CHECK (escaped == buf ); 201 } 202 } 203 204 { 205const char in []= "{ \"Hello\" : \"Json\", \"!\" : 10, \"array\" : [1, 2, 3.0] }" ; 206 207 { 208auto style = JSONWriter ::IndentationStyle ::Allman ; 209 210JSONWriter writer (style ); 211_parse (in ,& sink ,& writer ); 212 213JSONWriter writerCheck (style ); 214_parse (writer .getBuilder ().getBuffer (),& sink ,& writerCheck ); 215 216SLANG_CHECK (writerCheck .getBuilder ()== writer .getBuilder ()); 217 } 218 219 { 220auto style = JSONWriter ::IndentationStyle ::KNR ; 221 222JSONWriter writer (style ,80 ); 223_parse (in ,& sink ,& writer ); 224 225JSONWriter writerCheck (style ); 226_parse (writer .getBuilder ().getBuffer (),& sink ,& writerCheck ); 227 228SLANG_CHECK (writerCheck .getBuilder ()== writer .getBuilder ()); 229 } 230 231 { 232// Let's parse into a Value 233RefPtr < JSONContainer > container = new JSONContainer (& sourceManager ); 234 235JSONValue value ; 236 { 237JSONBuilder builder (container ); 238 239SLANG_CHECK (SLANG_SUCCEEDED (_parse (in ,& sink ,& builder ))); 240value = builder .getRootValue (); 241 } 242// Let's recreate 243JSONValue copy ; 244 { 245JSONBuilder builder (container ); 246container -> traverseRecursively (value ,& builder ); 247copy = builder .getRootValue (); 248 } 249 250SLANG_CHECK (container -> areEqual (value ,copy )); 251 } 252 } 253 254 { 255// Only need a SourceManager if we are going to store lexemes 256RefPtr < JSONContainer > container = new JSONContainer (nullptr ); 257 258 { 259List < JSONValue > values ; 260 261for (Int i = 0 ;i < 100 ;++ i ) 262 { 263 264values .add (JSONValue ::makeInt (i )); 265values .add (JSONValue ::makeFloat (- double (i ))); 266 } 267 268JSONValue array = container -> createArray (values .getBuffer (),values .getCount ()); 269 270auto arrayView = container -> getArray (array ); 271 272SLANG_CHECK (arrayView .getCount ()== values .getCount ()); 273 274// Check the values are the same 275SLANG_CHECK (container -> areEqual ( 276arrayView .getBuffer (), 277values .getBuffer (), 278arrayView .getCount ())); 279 280 { 281JSONWriter writer (JSONWriter ::IndentationStyle ::KNR ,80 ); 282 283container -> traverseRecursively (array ,& writer ); 284 } 285 } 286 { 287JSONValue obj = JSONValue ::makeEmptyObject (); 288 289JSONKey key = container -> getKey (UnownedStringSlice ::fromLiteral ("Hello" )); 290 291container -> setKeyValue (obj ,key ,JSONValue ::makeNull ()); 292container -> setKeyValue (obj ,key ,JSONValue ::makeInt (10 )); 293 294auto objView = container -> getObject (obj ); 295 296SLANG_CHECK (objView .getCount ()== 1 ); 297 298SLANG_CHECK (objView [0 ].value .asInteger ()== 10 ); 299 } 300 } 301 302// Check repeated keys works out 303// Check out comparison works with different key orders 304 { 305RefPtr < JSONContainer > container = new JSONContainer (& sourceManager ); 306const char aText []= "{ \"a\" : 10, \"b\" : 20.0, \"a\" : \"Hello\" }" ; 307 308 309JSONBuilder builder (container ); 310SLANG_CHECK (SLANG_SUCCEEDED (_parse (aText ,& sink ,& builder ))); 311const JSONValue a = builder .getRootValue (); 312 313builder .reset (); 314 315const char bText []= "{ \"b\" : 20.0, \"a\" : \"Hello\"}" ; 316SLANG_CHECK (SLANG_SUCCEEDED (_parse (bText ,& sink ,& builder ))); 317const JSONValue b = builder .getRootValue (); 318 319SLANG_CHECK (container -> areEqual (a ,b )); 320 321JSONBuilder convertBuilder (container ,JSONBuilder ::Flag ::ConvertLexemes ); 322 323SLANG_CHECK (SLANG_SUCCEEDED (_parse (aText ,& sink ,& convertBuilder ))); 324const JSONValue c = builder .getRootValue (); 325 326SLANG_CHECK (container -> areEqual (a ,c )); 327 } 328 329 { 330RefPtr < JSONContainer > container = new JSONContainer (& sourceManager ); 331const char aText []= "{ \"a\" : \"Hi!\", \"b\" : 20.0, \"c\" : \"Hello\", \"d\" : 30, " 332"\"e\": null, \"f\": true }" ; 333 334JSONBuilder builder (container ); 335SLANG_CHECK (SLANG_SUCCEEDED (_parse (aText ,& sink ,& builder ))); 336const JSONValue rootValue = builder .getRootValue (); 337 338List < PersistentJSONValue > values ; 339 340for (char c = 'a' ;c <='f' ;c ++ ) 341 { 342const char name []= {c ,0 }; 343JSONKey key = container -> getKey (UnownedStringSlice (name ,1 )); 344auto value = container -> findObjectValue (rootValue ,key ); 345 346SLANG_CHECK (value .type != JSONValue ::Type ::Invalid ); 347 348PersistentJSONValue persistentValue (value ,container ); 349values .add (persistentValue ); 350 351PersistentJSONValue copyValue (persistentValue ); 352PersistentJSONValue assignValue ; 353assignValue = persistentValue ; 354 355SLANG_CHECK (copyValue == persistentValue ); 356SLANG_CHECK (assignValue == persistentValue ); 357 } 358 359// Destroy the container 360container .setNull (); 361 362SLANG_CHECK (values [0 ].getSlice ()== "Hi!" ); 363SLANG_CHECK (values [1 ].asFloat ()== 20.0f ); 364SLANG_CHECK (values [2 ].getSlice ()== "Hello" ); 365SLANG_CHECK (values [3 ].asInteger ()== 30 ); 366SLANG_CHECK (values [4 ].type == JSONValue ::Type ::Null ); 367SLANG_CHECK (values [5 ].asBool ()== true); 368 } 369}