n3parser.js (41650B)
1 $rdf.N3Parser = function () { 2 3 function hexify(str) { // also used in parser 4 return encodeURI(str); 5 } 6 7 // Things we need to define to make converted pythn code work in js 8 // environment of $rdf 9 var RDFSink_forSomeSym = "http://www.w3.org/2000/10/swap/log#forSome"; 10 var RDFSink_forAllSym = "http://www.w3.org/2000/10/swap/log#forAll"; 11 var Logic_NS = "http://www.w3.org/2000/10/swap/log#"; 12 13 // pyjs seems to reference runtime library which I didn't find 14 var pyjslib_Tuple = function (theList) { 15 return theList 16 }; 17 18 var pyjslib_List = function (theList) { 19 return theList 20 }; 21 22 var pyjslib_Dict = function (listOfPairs) { 23 if(listOfPairs.length > 0) 24 throw "missing.js: oops nnonempty dict not imp"; 25 return []; 26 } 27 28 var pyjslib_len = function (s) { 29 return s.length 30 } 31 32 var pyjslib_slice = function (str, i, j) { 33 if(typeof str.slice == 'undefined') 34 throw '@@ mising.js: No .slice function for ' + str + ' of type ' + (typeof str) 35 if((typeof j == 'undefined') || (j == null)) return str.slice(i); 36 return str.slice(i, j) // @ exactly the same spec? 37 } 38 var StopIteration = Error('dummy error stop iteration'); 39 40 var pyjslib_Iterator = function (theList) { 41 this.last = 0; 42 this.li = theList; 43 this.next = function () { 44 if(this.last == this.li.length) throw StopIteration; 45 return this.li[this.last++]; 46 } 47 return this; 48 }; 49 50 var ord = function (str) { 51 return str.charCodeAt(0) 52 } 53 54 var string_find = function (str, s) { 55 return str.indexOf(s) 56 } 57 58 var assertFudge = function (condition, desc) { 59 if(condition) return; 60 if(desc) throw "python Assertion failed: " + desc; 61 throw "(python) Assertion failed."; 62 } 63 64 65 var stringFromCharCode = function (uesc) { 66 return String.fromCharCode(uesc); 67 } 68 69 var uripath_join = function (base, given) { 70 return $rdf.Util.uri.join(given, base) // sad but true 71 } 72 73 var becauseSubexpression = null; // No reason needed 74 var diag_tracking = 0; 75 var diag_chatty_flag = 0; 76 var diag_progress = function (str) { 77 /*$rdf.log.debug(str);*/ 78 } 79 80 // why_BecauseOfData = function(doc, reason) { return doc }; 81 82 var RDF_type_URI = "http://www.w3.org/1999/02/22-rdf-syntax-ns#type"; 83 var DAML_sameAs_URI = "http://www.w3.org/2002/07/owl#sameAs"; 84 85 /* 86 function SyntaxError(details) { 87 return new __SyntaxError(details); 88 } 89 */ 90 91 function __SyntaxError(details) { 92 this.details = details 93 } 94 95 /* 96 97 $Id: n3parser.js 14561 2008-02-23 06:37:26Z kennyluck $ 98 99 HAND EDITED FOR CONVERSION TO JAVASCRIPT 100 101 This module implements a Nptation3 parser, and the final 102 part of a notation3 serializer. 103 104 See also: 105 106 Notation 3 107 http://www.w3.org/DesignIssues/Notation3 108 109 Closed World Machine - and RDF Processor 110 http://www.w3.org/2000/10/swap/cwm 111 112 To DO: See also "@@" in comments 113 114 - Clean up interfaces 115 ______________________________________________ 116 117 Module originally by Dan Connolly, includeing notation3 118 parser and RDF generator. TimBL added RDF stream model 119 and N3 generation, replaced stream model with use 120 of common store/formula API. Yosi Scharf developped 121 the module, including tests and test harness. 122 123 */ 124 125 var ADDED_HASH = "#"; 126 var LOG_implies_URI = "http://www.w3.org/2000/10/swap/log#implies"; 127 var INTEGER_DATATYPE = "http://www.w3.org/2001/XMLSchema#integer"; 128 var FLOAT_DATATYPE = "http://www.w3.org/2001/XMLSchema#double"; 129 var DECIMAL_DATATYPE = "http://www.w3.org/2001/XMLSchema#decimal"; 130 var BOOLEAN_DATATYPE = "http://www.w3.org/2001/XMLSchema#boolean"; 131 var option_noregen = 0; 132 var _notQNameChars = "\t\r\n !\"#$%&'()*.,+/;<=>?@[\\]^`{|}~"; 133 var _notNameChars = (_notQNameChars + ":"); 134 var _rdfns = "http://www.w3.org/1999/02/22-rdf-syntax-ns#"; 135 var N3CommentCharacter = "#"; 136 var eol = new RegExp("^[ \\t]*(#[^\\n]*)?\\r?\\n", 'g'); 137 var eof = new RegExp("^[ \\t]*(#[^\\n]*)?$", 'g'); 138 var ws = new RegExp("^[ \\t]*", 'g'); 139 var signed_integer = new RegExp("^[-+]?[0-9]+", 'g'); 140 var number_syntax = new RegExp("^([-+]?[0-9]+)(\\.[0-9]+)?(e[-+]?[0-9]+)?", 'g'); 141 var digitstring = new RegExp("^[0-9]+", 'g'); 142 var interesting = new RegExp("[\\\\\\r\\n\\\"]", 'g'); 143 var langcode = new RegExp("^[a-zA-Z0-9]+(-[a-zA-Z0-9]+)?", 'g'); 144 145 function SinkParser(store, openFormula, thisDoc, baseURI, genPrefix, metaURI, flags, why) { 146 return new __SinkParser(store, openFormula, thisDoc, baseURI, genPrefix, metaURI, flags, why); 147 } 148 149 function __SinkParser(store, openFormula, thisDoc, baseURI, genPrefix, metaURI, flags, why) { 150 if(typeof openFormula == 'undefined') openFormula = null; 151 if(typeof thisDoc == 'undefined') thisDoc = ""; 152 if(typeof baseURI == 'undefined') baseURI = null; 153 if(typeof genPrefix == 'undefined') genPrefix = ""; 154 if(typeof metaURI == 'undefined') metaURI = null; 155 if(typeof flags == 'undefined') flags = ""; 156 if(typeof why == 'undefined') why = null; 157 /* 158 note: namespace names should *not* end in #; 159 the # will get added during qname processing */ 160 161 this._bindings = new pyjslib_Dict([]); 162 this._flags = flags; 163 if((thisDoc != "")) { 164 assertFudge((thisDoc.indexOf(":") >= 0), ("Document URI not absolute: " + thisDoc)); 165 this._bindings[""] = ((thisDoc + "#")); 166 } 167 this._store = store; 168 if(genPrefix) { 169 store.setGenPrefix(genPrefix); 170 } 171 this._thisDoc = thisDoc; 172 this.source = store.sym(thisDoc); 173 this.lines = 0; 174 this.statementCount = 0; 175 this.startOfLine = 0; 176 this.previousLine = 0; 177 this._genPrefix = genPrefix; 178 this.keywords = new pyjslib_List(["a", "this", "bind", "has", "is", "of", "true", "false"]); 179 this.keywordsSet = 0; 180 this._anonymousNodes = new pyjslib_Dict([]); 181 this._variables = new pyjslib_Dict([]); 182 this._parentVariables = new pyjslib_Dict([]); 183 this._reason = why; 184 this._reason2 = null; 185 if(diag_tracking) { 186 this._reason2 = why_BecauseOfData(store.sym(thisDoc), this._reason); 187 } 188 if(baseURI) { 189 this._baseURI = baseURI; 190 } else { 191 if(thisDoc) { 192 this._baseURI = thisDoc; 193 } else { 194 this._baseURI = null; 195 } 196 } 197 assertFudge(!(this._baseURI) || (this._baseURI.indexOf(":") >= 0)); 198 if(!(this._genPrefix)) { 199 if(this._thisDoc) { 200 this._genPrefix = (this._thisDoc + "#_g"); 201 } else { 202 this._genPrefix = RDFSink_uniqueURI(); 203 } 204 } 205 if((openFormula == null)) { 206 if(this._thisDoc) { 207 this._formula = store.formula((thisDoc + "#_formula")); 208 } else { 209 this._formula = store.formula(); 210 } 211 } else { 212 this._formula = openFormula; 213 } 214 this._context = this._formula; 215 this._parentContext = null; 216 } 217 __SinkParser.prototype.here = function (i) { 218 return((((this._genPrefix + "_L") + this.lines) + "C") + ((i - this.startOfLine) + 1)); 219 }; 220 __SinkParser.prototype.formula = function () { 221 return this._formula; 222 }; 223 __SinkParser.prototype.loadStream = function (stream) { 224 return this.loadBuf(stream.read()); 225 }; 226 __SinkParser.prototype.loadBuf = function (buf) { 227 /* 228 Parses a buffer and returns its top level formula*/ 229 230 this.startDoc(); 231 this.feed(buf); 232 return this.endDoc(); 233 }; 234 __SinkParser.prototype.feed = function (octets) { 235 /* 236 Feed an octet stream tothe parser 237 238 if BadSyntax is raised, the string 239 passed in the exception object is the 240 remainder after any statements have been parsed. 241 So if there is more data to feed to the 242 parser, it should be straightforward to recover.*/ 243 244 var str = octets; 245 var i = 0; 246 while((i >= 0)) { 247 var j = this.skipSpace(str, i); 248 if((j < 0)) { 249 return; 250 } 251 var i = this.directiveOrStatement(str, j); 252 if((i < 0)) { 253 throw BadSyntax(this._thisDoc, this.lines, str, j, "expected directive or statement"); 254 } 255 } 256 }; 257 __SinkParser.prototype.directiveOrStatement = function (str, h) { 258 var i = this.skipSpace(str, h); 259 if((i < 0)) { 260 return i; 261 } 262 var j = this.directive(str, i); 263 if((j >= 0)) { 264 return this.checkDot(str, j); 265 } 266 var j = this.statement(str, i); 267 if((j >= 0)) { 268 return this.checkDot(str, j); 269 } 270 return j; 271 }; 272 __SinkParser.prototype.tok = function (tok, str, i) { 273 /* 274 Check for keyword. Space must have been stripped on entry and 275 we must not be at end of file.*/ 276 var whitespace = "\t\n\v\f\r "; 277 if((pyjslib_slice(str, i, (i + 1)) == "@")) { 278 var i = (i + 1); 279 } else { 280 if(($rdf.Util.ArrayIndexOf(this.keywords, tok) < 0)) { 281 return -1; 282 } 283 } 284 var k = (i + pyjslib_len(tok)); 285 if((pyjslib_slice(str, i, k) == tok) && (_notQNameChars.indexOf(str.charAt(k)) >= 0)) { 286 return k; 287 } else { 288 return -1; 289 } 290 }; 291 __SinkParser.prototype.directive = function (str, i) { 292 var j = this.skipSpace(str, i); 293 if((j < 0)) { 294 return j; 295 } 296 var res = new pyjslib_List([]); 297 var j = this.tok("bind", str, i); 298 if((j > 0)) { 299 throw BadSyntax(this._thisDoc, this.lines, str, i, "keyword bind is obsolete: use @prefix"); 300 } 301 var j = this.tok("keywords", str, i); 302 if((j > 0)) { 303 var i = this.commaSeparatedList(str, j, res, false); 304 if((i < 0)) { 305 throw BadSyntax(this._thisDoc, this.lines, str, i, "'@keywords' needs comma separated list of words"); 306 } 307 this.setKeywords(pyjslib_slice(res, null, null)); 308 if((diag_chatty_flag > 80)) { 309 diag_progress("Keywords ", this.keywords); 310 } 311 return i; 312 } 313 var j = this.tok("forAll", str, i); 314 if((j > 0)) { 315 var i = this.commaSeparatedList(str, j, res, true); 316 if((i < 0)) { 317 throw BadSyntax(this._thisDoc, this.lines, str, i, "Bad variable list after @forAll"); 318 } 319 320 var __x = new pyjslib_Iterator(res); 321 try { 322 while(true) { 323 var x = __x.next(); 324 325 326 if($rdf.Util.ArrayIndexOf(this._variables, x) < 0 || ($rdf.Util.ArrayIndexOf(this._parentVariables, x) >= 0)) { 327 this._variables[x] = (this._context.newUniversal(x)); 328 } 329 330 } 331 } catch(e) { 332 if(e != StopIteration) { 333 throw e; 334 } 335 } 336 337 return i; 338 } 339 var j = this.tok("forSome", str, i); 340 if((j > 0)) { 341 var i = this.commaSeparatedList(str, j, res, this.uri_ref2); 342 if((i < 0)) { 343 throw BadSyntax(this._thisDoc, this.lines, str, i, "Bad variable list after @forSome"); 344 } 345 346 var __x = new pyjslib_Iterator(res); 347 try { 348 while(true) { 349 var x = __x.next(); 350 351 352 this._context.declareExistential(x); 353 354 } 355 } catch(e) { 356 if(e != StopIteration) { 357 throw e; 358 } 359 } 360 361 return i; 362 } 363 var j = this.tok("prefix", str, i); 364 if((j >= 0)) { 365 var t = new pyjslib_List([]); 366 var i = this.qname(str, j, t); 367 if((i < 0)) { 368 throw BadSyntax(this._thisDoc, this.lines, str, j, "expected qname after @prefix"); 369 } 370 var j = this.uri_ref2(str, i, t); 371 if((j < 0)) { 372 throw BadSyntax(this._thisDoc, this.lines, str, i, "expected <uriref> after @prefix _qname_"); 373 } 374 var ns = t[1].uri; 375 if(this._baseURI) { 376 var ns = uripath_join(this._baseURI, ns); 377 } else { 378 assertFudge((ns.indexOf(":") >= 0), "With no base URI, cannot handle relative URI for NS"); 379 } 380 assertFudge((ns.indexOf(":") >= 0)); 381 this._bindings[t[0][0]] = (ns); 382 383 this.bind(t[0][0], hexify(ns)); 384 return j; 385 } 386 var j = this.tok("base", str, i); 387 if((j >= 0)) { 388 var t = new pyjslib_List([]); 389 var i = this.uri_ref2(str, j, t); 390 if((i < 0)) { 391 throw BadSyntax(this._thisDoc, this.lines, str, j, "expected <uri> after @base "); 392 } 393 var ns = t[0].uri; 394 if(this._baseURI) { 395 var ns = uripath_join(this._baseURI, ns); 396 } else { 397 throw BadSyntax(this._thisDoc, this.lines, str, j, (("With no previous base URI, cannot use relative URI in @base <" + ns) + ">")); 398 } 399 assertFudge((ns.indexOf(":") >= 0)); 400 this._baseURI = ns; 401 return i; 402 } 403 return -1; 404 }; 405 __SinkParser.prototype.bind = function (qn, uri) { 406 if((qn == "")) { 407 } else { 408 this._store.setPrefixForURI(qn, uri); 409 } 410 }; 411 __SinkParser.prototype.setKeywords = function (k) { 412 /* 413 Takes a list of strings*/ 414 415 if((k == null)) { 416 this.keywordsSet = 0; 417 } else { 418 this.keywords = k; 419 this.keywordsSet = 1; 420 } 421 }; 422 __SinkParser.prototype.startDoc = function () {}; 423 __SinkParser.prototype.endDoc = function () { 424 /* 425 Signal end of document and stop parsing. returns formula*/ 426 427 return this._formula; 428 }; 429 __SinkParser.prototype.makeStatement = function (quad) { 430 quad[0].add(quad[2], quad[1], quad[3], this.source); 431 this.statementCount += 1; 432 }; 433 __SinkParser.prototype.statement = function (str, i) { 434 var r = new pyjslib_List([]); 435 var i = this.object(str, i, r); 436 if((i < 0)) { 437 return i; 438 } 439 var j = this.property_list(str, i, r[0]); 440 if((j < 0)) { 441 throw BadSyntax(this._thisDoc, this.lines, str, i, "expected propertylist"); 442 } 443 return j; 444 }; 445 __SinkParser.prototype.subject = function (str, i, res) { 446 return this.item(str, i, res); 447 }; 448 __SinkParser.prototype.verb = function (str, i, res) { 449 /* 450 has _prop_ 451 is _prop_ of 452 a 453 = 454 _prop_ 455 >- prop -> 456 <- prop -< 457 _operator_*/ 458 459 var j = this.skipSpace(str, i); 460 if((j < 0)) { 461 return j; 462 } 463 var r = new pyjslib_List([]); 464 var j = this.tok("has", str, i); 465 if((j >= 0)) { 466 var i = this.prop(str, j, r); 467 if((i < 0)) { 468 throw BadSyntax(this._thisDoc, this.lines, str, j, "expected property after 'has'"); 469 } 470 res.push(new pyjslib_Tuple(["->", r[0]])); 471 return i; 472 } 473 var j = this.tok("is", str, i); 474 if((j >= 0)) { 475 var i = this.prop(str, j, r); 476 if((i < 0)) { 477 throw BadSyntax(this._thisDoc, this.lines, str, j, "expected <property> after 'is'"); 478 } 479 var j = this.skipSpace(str, i); 480 if((j < 0)) { 481 throw BadSyntax(this._thisDoc, this.lines, str, i, "End of file found, expected property after 'is'"); 482 return j; 483 } 484 var i = j; 485 var j = this.tok("of", str, i); 486 if((j < 0)) { 487 throw BadSyntax(this._thisDoc, this.lines, str, i, "expected 'of' after 'is' <prop>"); 488 } 489 res.push(new pyjslib_Tuple(["<-", r[0]])); 490 return j; 491 } 492 var j = this.tok("a", str, i); 493 if((j >= 0)) { 494 res.push(new pyjslib_Tuple(["->", this._store.sym(RDF_type_URI)])); 495 return j; 496 } 497 if((pyjslib_slice(str, i, (i + 2)) == "<=")) { 498 res.push(new pyjslib_Tuple(["<-", this._store.sym((Logic_NS + "implies"))])); 499 return(i + 2); 500 } 501 if((pyjslib_slice(str, i, (i + 1)) == "=")) { 502 if((pyjslib_slice(str, (i + 1), (i + 2)) == ">")) { 503 res.push(new pyjslib_Tuple(["->", this._store.sym((Logic_NS + "implies"))])); 504 return(i + 2); 505 } 506 res.push(new pyjslib_Tuple(["->", this._store.sym(DAML_sameAs_URI)])); 507 return(i + 1); 508 } 509 if((pyjslib_slice(str, i, (i + 2)) == ":=")) { 510 res.push(new pyjslib_Tuple(["->", (Logic_NS + "becomes")])); 511 return(i + 2); 512 } 513 var j = this.prop(str, i, r); 514 if((j >= 0)) { 515 res.push(new pyjslib_Tuple(["->", r[0]])); 516 return j; 517 } 518 if((pyjslib_slice(str, i, (i + 2)) == ">-") || (pyjslib_slice(str, i, (i + 2)) == "<-")) { 519 throw BadSyntax(this._thisDoc, this.lines, str, j, ">- ... -> syntax is obsolete."); 520 } 521 return -1; 522 }; 523 __SinkParser.prototype.prop = function (str, i, res) { 524 return this.item(str, i, res); 525 }; 526 __SinkParser.prototype.item = function (str, i, res) { 527 return this.path(str, i, res); 528 }; 529 __SinkParser.prototype.blankNode = function (uri) { 530 return this._context.bnode(uri, this._reason2); 531 }; 532 __SinkParser.prototype.path = function (str, i, res) { 533 /* 534 Parse the path production. 535 */ 536 537 var j = this.nodeOrLiteral(str, i, res); 538 if((j < 0)) { 539 return j; 540 } 541 while(("!^.".indexOf(pyjslib_slice(str, j, (j + 1))) >= 0)) { 542 var ch = pyjslib_slice(str, j, (j + 1)); 543 if((ch == ".")) { 544 var ahead = pyjslib_slice(str, (j + 1), (j + 2)); 545 if(!(ahead) || (_notNameChars.indexOf(ahead) >= 0) && (":?<[{(".indexOf(ahead) < 0)) { 546 break; 547 } 548 } 549 var subj = res.pop(); 550 var obj = this.blankNode(this.here(j)); 551 var j = this.node(str, (j + 1), res); 552 if((j < 0)) { 553 throw BadSyntax(this._thisDoc, this.lines, str, j, "EOF found in middle of path syntax"); 554 } 555 var pred = res.pop(); 556 if((ch == "^")) { 557 this.makeStatement(new pyjslib_Tuple([this._context, pred, obj, subj])); 558 } else { 559 this.makeStatement(new pyjslib_Tuple([this._context, pred, subj, obj])); 560 } 561 res.push(obj); 562 } 563 return j; 564 }; 565 __SinkParser.prototype.anonymousNode = function (ln) { 566 /* 567 Remember or generate a term for one of these _: anonymous nodes*/ 568 569 var term = this._anonymousNodes[ln]; 570 if(term) { 571 return term; 572 } 573 var term = this._store.bnode(this._context, this._reason2); 574 this._anonymousNodes[ln] = (term); 575 return term; 576 }; 577 __SinkParser.prototype.node = function (str, i, res, subjectAlready) { 578 if(typeof subjectAlready == 'undefined') subjectAlready = null; 579 /* 580 Parse the <node> production. 581 Space is now skipped once at the beginning 582 instead of in multipe calls to self.skipSpace(). 583 */ 584 585 var subj = subjectAlready; 586 var j = this.skipSpace(str, i); 587 if((j < 0)) { 588 return j; 589 } 590 var i = j; 591 var ch = pyjslib_slice(str, i, (i + 1)); 592 if((ch == "[")) { 593 var bnodeID = this.here(i); 594 var j = this.skipSpace(str, (i + 1)); 595 if((j < 0)) { 596 throw BadSyntax(this._thisDoc, this.lines, str, i, "EOF after '['"); 597 } 598 if((pyjslib_slice(str, j, (j + 1)) == "=")) { 599 var i = (j + 1); 600 var objs = new pyjslib_List([]); 601 var j = this.objectList(str, i, objs); 602 603 if((j >= 0)) { 604 var subj = objs[0]; 605 if((pyjslib_len(objs) > 1)) { 606 607 var __obj = new pyjslib_Iterator(objs); 608 try { 609 while(true) { 610 var obj = __obj.next(); 611 612 613 this.makeStatement(new pyjslib_Tuple([this._context, this._store.sym(DAML_sameAs_URI), subj, obj])); 614 615 } 616 } catch(e) { 617 if(e != StopIteration) { 618 throw e; 619 } 620 } 621 622 } 623 var j = this.skipSpace(str, j); 624 if((j < 0)) { 625 throw BadSyntax(this._thisDoc, this.lines, str, i, "EOF when objectList expected after [ = "); 626 } 627 if((pyjslib_slice(str, j, (j + 1)) == ";")) { 628 var j = (j + 1); 629 } 630 } else { 631 throw BadSyntax(this._thisDoc, this.lines, str, i, "objectList expected after [= "); 632 } 633 } 634 if((subj == null)) { 635 var subj = this.blankNode(bnodeID); 636 } 637 var i = this.property_list(str, j, subj); 638 if((i < 0)) { 639 throw BadSyntax(this._thisDoc, this.lines, str, j, "property_list expected"); 640 } 641 var j = this.skipSpace(str, i); 642 if((j < 0)) { 643 throw BadSyntax(this._thisDoc, this.lines, str, i, "EOF when ']' expected after [ <propertyList>"); 644 } 645 if((pyjslib_slice(str, j, (j + 1)) != "]")) { 646 throw BadSyntax(this._thisDoc, this.lines, str, j, "']' expected"); 647 } 648 res.push(subj); 649 return(j + 1); 650 } 651 if((ch == "{")) { 652 var ch2 = pyjslib_slice(str, (i + 1), (i + 2)); 653 if((ch2 == "$")) { 654 i += 1; 655 var j = (i + 1); 656 var mylist = new pyjslib_List([]); 657 var first_run = true; 658 while(1) { 659 var i = this.skipSpace(str, j); 660 if((i < 0)) { 661 throw BadSyntax(this._thisDoc, this.lines, str, i, "needed '$}', found end."); 662 } 663 if((pyjslib_slice(str, i, (i + 2)) == "$}")) { 664 var j = (i + 2); 665 break; 666 } 667 if(!(first_run)) { 668 if((pyjslib_slice(str, i, (i + 1)) == ",")) { 669 i += 1; 670 } else { 671 throw BadSyntax(this._thisDoc, this.lines, str, i, "expected: ','"); 672 } 673 } else { 674 var first_run = false; 675 } 676 var item = new pyjslib_List([]); 677 var j = this.item(str, i, item); 678 if((j < 0)) { 679 throw BadSyntax(this._thisDoc, this.lines, str, i, "expected item in set or '$}'"); 680 } 681 mylist.push(item[0]); 682 } 683 res.push(this._store.newSet(mylist, this._context)); 684 return j; 685 } else { 686 var j = (i + 1); 687 var oldParentContext = this._parentContext; 688 this._parentContext = this._context; 689 var parentAnonymousNodes = this._anonymousNodes; 690 var grandParentVariables = this._parentVariables; 691 this._parentVariables = this._variables; 692 this._anonymousNodes = new pyjslib_Dict([]); 693 this._variables = this._variables.slice(); 694 var reason2 = this._reason2; 695 this._reason2 = becauseSubexpression; 696 if((subj == null)) { 697 var subj = this._store.formula(); 698 } 699 this._context = subj; 700 while(1) { 701 var i = this.skipSpace(str, j); 702 if((i < 0)) { 703 throw BadSyntax(this._thisDoc, this.lines, str, i, "needed '}', found end."); 704 } 705 if((pyjslib_slice(str, i, (i + 1)) == "}")) { 706 var j = (i + 1); 707 break; 708 } 709 var j = this.directiveOrStatement(str, i); 710 if((j < 0)) { 711 throw BadSyntax(this._thisDoc, this.lines, str, i, "expected statement or '}'"); 712 } 713 } 714 this._anonymousNodes = parentAnonymousNodes; 715 this._variables = this._parentVariables; 716 this._parentVariables = grandParentVariables; 717 this._context = this._parentContext; 718 this._reason2 = reason2; 719 this._parentContext = oldParentContext; 720 res.push(subj.close()); 721 return j; 722 } 723 } 724 if((ch == "(")) { 725 var thing_type = this._store.list; 726 var ch2 = pyjslib_slice(str, (i + 1), (i + 2)); 727 if((ch2 == "$")) { 728 var thing_type = this._store.newSet; 729 i += 1; 730 } 731 var j = (i + 1); 732 var mylist = new pyjslib_List([]); 733 while(1) { 734 var i = this.skipSpace(str, j); 735 if((i < 0)) { 736 throw BadSyntax(this._thisDoc, this.lines, str, i, "needed ')', found end."); 737 } 738 if((pyjslib_slice(str, i, (i + 1)) == ")")) { 739 var j = (i + 1); 740 break; 741 } 742 var item = new pyjslib_List([]); 743 var j = this.item(str, i, item); 744 if((j < 0)) { 745 throw BadSyntax(this._thisDoc, this.lines, str, i, "expected item in list or ')'"); 746 } 747 mylist.push(item[0]); 748 } 749 res.push(thing_type(mylist, this._context)); 750 return j; 751 } 752 var j = this.tok("this", str, i); 753 if((j >= 0)) { 754 throw BadSyntax(this._thisDoc, this.lines, str, i, "Keyword 'this' was ancient N3. Now use @forSome and @forAll keywords."); 755 res.push(this._context); 756 return j; 757 } 758 var j = this.tok("true", str, i); 759 if((j >= 0)) { 760 res.push(true); 761 return j; 762 } 763 var j = this.tok("false", str, i); 764 if((j >= 0)) { 765 res.push(false); 766 return j; 767 } 768 if((subj == null)) { 769 var j = this.uri_ref2(str, i, res); 770 if((j >= 0)) { 771 return j; 772 } 773 } 774 return -1; 775 }; 776 __SinkParser.prototype.property_list = function (str, i, subj) { 777 /* 778 Parse property list 779 Leaves the terminating punctuation in the buffer 780 */ 781 782 while(1) { 783 var j = this.skipSpace(str, i); 784 if((j < 0)) { 785 throw BadSyntax(this._thisDoc, this.lines, str, i, "EOF found when expected verb in property list"); 786 return j; 787 } 788 if((pyjslib_slice(str, j, (j + 2)) == ":-")) { 789 var i = (j + 2); 790 var res = new pyjslib_List([]); 791 var j = this.node(str, i, res, subj); 792 if((j < 0)) { 793 throw BadSyntax(this._thisDoc, this.lines, str, i, "bad {} or () or [] node after :- "); 794 } 795 var i = j; 796 continue; 797 } 798 var i = j; 799 var v = new pyjslib_List([]); 800 var j = this.verb(str, i, v); 801 if((j <= 0)) { 802 return i; 803 } 804 var objs = new pyjslib_List([]); 805 var i = this.objectList(str, j, objs); 806 if((i < 0)) { 807 throw BadSyntax(this._thisDoc, this.lines, str, j, "objectList expected"); 808 } 809 810 var __obj = new pyjslib_Iterator(objs); 811 try { 812 while(true) { 813 var obj = __obj.next(); 814 815 816 var pairFudge = v[0]; 817 var dir = pairFudge[0]; 818 var sym = pairFudge[1]; 819 if((dir == "->")) { 820 this.makeStatement(new pyjslib_Tuple([this._context, sym, subj, obj])); 821 } else { 822 this.makeStatement(new pyjslib_Tuple([this._context, sym, obj, subj])); 823 } 824 825 } 826 } catch(e) { 827 if(e != StopIteration) { 828 throw e; 829 } 830 } 831 832 var j = this.skipSpace(str, i); 833 if((j < 0)) { 834 throw BadSyntax(this._thisDoc, this.lines, str, j, "EOF found in list of objects"); 835 return j; 836 } 837 if((pyjslib_slice(str, i, (i + 1)) != ";")) { 838 return i; 839 } 840 var i = (i + 1); 841 } 842 }; 843 __SinkParser.prototype.commaSeparatedList = function (str, j, res, ofUris) { 844 /* 845 return value: -1 bad syntax; >1 new position in str 846 res has things found appended 847 848 Used to use a final value of the function to be called, e.g. this.bareWord 849 but passing the function didn't work fo js converion pyjs 850 */ 851 852 var i = this.skipSpace(str, j); 853 if((i < 0)) { 854 throw BadSyntax(this._thisDoc, this.lines, str, i, "EOF found expecting comma sep list"); 855 return i; 856 } 857 if((str.charAt(i) == ".")) { 858 return j; 859 } 860 if(ofUris) { 861 var i = this.uri_ref2(str, i, res); 862 } else { 863 var i = this.bareWord(str, i, res); 864 } 865 if((i < 0)) { 866 return -1; 867 } 868 while(1) { 869 var j = this.skipSpace(str, i); 870 if((j < 0)) { 871 return j; 872 } 873 var ch = pyjslib_slice(str, j, (j + 1)); 874 if((ch != ",")) { 875 if((ch != ".")) { 876 return -1; 877 } 878 return j; 879 } 880 if(ofUris) { 881 var i = this.uri_ref2(str, (j + 1), res); 882 } else { 883 var i = this.bareWord(str, (j + 1), res); 884 } 885 if((i < 0)) { 886 throw BadSyntax(this._thisDoc, this.lines, str, i, "bad list content"); 887 return i; 888 } 889 } 890 }; 891 __SinkParser.prototype.objectList = function (str, i, res) { 892 var i = this.object(str, i, res); 893 if((i < 0)) { 894 return -1; 895 } 896 while(1) { 897 var j = this.skipSpace(str, i); 898 if((j < 0)) { 899 throw BadSyntax(this._thisDoc, this.lines, str, j, "EOF found after object"); 900 return j; 901 } 902 if((pyjslib_slice(str, j, (j + 1)) != ",")) { 903 return j; 904 } 905 var i = this.object(str, (j + 1), res); 906 if((i < 0)) { 907 return i; 908 } 909 } 910 }; 911 __SinkParser.prototype.checkDot = function (str, i) { 912 var j = this.skipSpace(str, i); 913 if((j < 0)) { 914 return j; 915 } 916 if((pyjslib_slice(str, j, (j + 1)) == ".")) { 917 return(j + 1); 918 } 919 if((pyjslib_slice(str, j, (j + 1)) == "}")) { 920 return j; 921 } 922 if((pyjslib_slice(str, j, (j + 1)) == "]")) { 923 return j; 924 } 925 throw BadSyntax(this._thisDoc, this.lines, str, j, "expected '.' or '}' or ']' at end of statement"); 926 return i; 927 }; 928 __SinkParser.prototype.uri_ref2 = function (str, i, res) { 929 /* 930 Generate uri from n3 representation. 931 932 Note that the RDF convention of directly concatenating 933 NS and local name is now used though I prefer inserting a '#' 934 to make the namesapces look more like what XML folks expect. 935 */ 936 937 var qn = new pyjslib_List([]); 938 var j = this.qname(str, i, qn); 939 if((j >= 0)) { 940 var pairFudge = qn[0]; 941 var pfx = pairFudge[0]; 942 var ln = pairFudge[1]; 943 if((pfx == null)) { 944 assertFudge(0, "not used?"); 945 var ns = (this._baseURI + ADDED_HASH); 946 } else { 947 var ns = this._bindings[pfx]; 948 if(!(ns)) { 949 if((pfx == "_")) { 950 res.push(this.anonymousNode(ln)); 951 return j; 952 } 953 throw BadSyntax(this._thisDoc, this.lines, str, i, (("Prefix " + pfx) + " not bound.")); 954 } 955 } 956 var symb = this._store.sym((ns + ln)); 957 if(($rdf.Util.ArrayIndexOf(this._variables, symb) >= 0)) { 958 res.push(this._variables[symb]); 959 } else { 960 res.push(symb); 961 } 962 return j; 963 } 964 var i = this.skipSpace(str, i); 965 if((i < 0)) { 966 return -1; 967 } 968 if((str.charAt(i) == "?")) { 969 var v = new pyjslib_List([]); 970 var j = this.variable(str, i, v); 971 if((j > 0)) { 972 res.push(v[0]); 973 return j; 974 } 975 return -1; 976 } else if((str.charAt(i) == "<")) { 977 var i = (i + 1); 978 var st = i; 979 while((i < pyjslib_len(str))) { 980 if((str.charAt(i) == ">")) { 981 var uref = pyjslib_slice(str, st, i); 982 if(this._baseURI) { 983 var uref = uripath_join(this._baseURI, uref); 984 } else { 985 assertFudge((uref.indexOf(":") >= 0), "With no base URI, cannot deal with relative URIs"); 986 } 987 if((pyjslib_slice(str, (i - 1), i) == "#") && !((pyjslib_slice(uref, -1, null) == "#"))) { 988 var uref = (uref + "#"); 989 } 990 var symb = this._store.sym(uref); 991 if(($rdf.Util.ArrayIndexOf(this._variables, symb) >= 0)) { 992 res.push(this._variables[symb]); 993 } else { 994 res.push(symb); 995 } 996 return(i + 1); 997 } 998 var i = (i + 1); 999 } 1000 throw BadSyntax(this._thisDoc, this.lines, str, j, "unterminated URI reference"); 1001 } else if(this.keywordsSet) { 1002 var v = new pyjslib_List([]); 1003 var j = this.bareWord(str, i, v); 1004 if((j < 0)) { 1005 return -1; 1006 } 1007 if(($rdf.Util.ArrayIndexOf(this.keywords, v[0]) >= 0)) { 1008 throw BadSyntax(this._thisDoc, this.lines, str, i, (("Keyword \"" + v[0]) + "\" not allowed here.")); 1009 } 1010 res.push(this._store.sym((this._bindings[""] + v[0]))); 1011 return j; 1012 } else { 1013 return -1; 1014 } 1015 }; 1016 __SinkParser.prototype.skipSpace = function (str, i) { 1017 /* 1018 Skip white space, newlines and comments. 1019 return -1 if EOF, else position of first non-ws character*/ 1020 var tmp = str; 1021 var whitespace = ' \n\r\t\f\x0b\xa0\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u200b\u2028\u2029\u3000'; 1022 for(var j = (i ? i : 0); j < str.length; j++) { 1023 if(whitespace.indexOf(str.charAt(j)) === -1) { 1024 if(str.charAt(j) === '#') { 1025 str = str.slice(i).replace(/^[^\n]*\n/, ""); 1026 i = 0; 1027 j = -1; 1028 } else { 1029 break; 1030 } 1031 } 1032 } 1033 var val = (tmp.length - str.length) + j; 1034 if(val === tmp.length) { 1035 return -1; 1036 } 1037 return val; 1038 }; 1039 __SinkParser.prototype.variable = function (str, i, res) { 1040 /* 1041 ?abc -> variable(:abc) 1042 */ 1043 1044 var j = this.skipSpace(str, i); 1045 if((j < 0)) { 1046 return -1; 1047 } 1048 if((pyjslib_slice(str, j, (j + 1)) != "?")) { 1049 return -1; 1050 } 1051 var j = (j + 1); 1052 var i = j; 1053 if(("0123456789-".indexOf(str.charAt(j)) >= 0)) { 1054 throw BadSyntax(this._thisDoc, this.lines, str, j, (("Varible name can't start with '" + str.charAt(j)) + "s'")); 1055 return -1; 1056 } 1057 while((i < pyjslib_len(str)) && (_notNameChars.indexOf(str.charAt(i)) < 0)) { 1058 var i = (i + 1); 1059 } 1060 if((this._parentContext == null)) { 1061 throw BadSyntax(this._thisDoc, this.lines, str, j, ("Can't use ?xxx syntax for variable in outermost level: " + pyjslib_slice(str, (j - 1), i))); 1062 } 1063 res.push(this._store.variable(pyjslib_slice(str, j, i))); 1064 return i; 1065 }; 1066 __SinkParser.prototype.bareWord = function (str, i, res) { 1067 /* 1068 abc -> :abc 1069 */ 1070 1071 var j = this.skipSpace(str, i); 1072 if((j < 0)) { 1073 return -1; 1074 } 1075 var ch = str.charAt(j); 1076 if(("0123456789-".indexOf(ch) >= 0)) { 1077 return -1; 1078 } 1079 if((_notNameChars.indexOf(ch) >= 0)) { 1080 return -1; 1081 } 1082 var i = j; 1083 while((i < pyjslib_len(str)) && (_notNameChars.indexOf(str.charAt(i)) < 0)) { 1084 var i = (i + 1); 1085 } 1086 res.push(pyjslib_slice(str, j, i)); 1087 return i; 1088 }; 1089 __SinkParser.prototype.qname = function (str, i, res) { 1090 /* 1091 1092 xyz:def -> ('xyz', 'def') 1093 If not in keywords and keywordsSet: def -> ('', 'def') 1094 :def -> ('', 'def') 1095 */ 1096 1097 var i = this.skipSpace(str, i); 1098 if((i < 0)) { 1099 return -1; 1100 } 1101 var c = str.charAt(i); 1102 if(("0123456789-+".indexOf(c) >= 0)) { 1103 return -1; 1104 } 1105 if((_notNameChars.indexOf(c) < 0)) { 1106 var ln = c; 1107 var i = (i + 1); 1108 while((i < pyjslib_len(str))) { 1109 var c = str.charAt(i); 1110 if((_notNameChars.indexOf(c) < 0)) { 1111 var ln = (ln + c); 1112 var i = (i + 1); 1113 } else { 1114 break; 1115 } 1116 } 1117 } else { 1118 var ln = ""; 1119 } 1120 if((i < pyjslib_len(str)) && (str.charAt(i) == ":")) { 1121 var pfx = ln; 1122 var i = (i + 1); 1123 var ln = ""; 1124 while((i < pyjslib_len(str))) { 1125 var c = str.charAt(i); 1126 if((_notNameChars.indexOf(c) < 0)) { 1127 var ln = (ln + c); 1128 var i = (i + 1); 1129 } else { 1130 break; 1131 } 1132 } 1133 res.push(new pyjslib_Tuple([pfx, ln])); 1134 return i; 1135 } else { 1136 if(ln && this.keywordsSet && ($rdf.Util.ArrayIndexOf(this.keywords, ln) < 0)) { 1137 res.push(new pyjslib_Tuple(["", ln])); 1138 return i; 1139 } 1140 return -1; 1141 } 1142 }; 1143 __SinkParser.prototype.object = function (str, i, res) { 1144 var j = this.subject(str, i, res); 1145 if((j >= 0)) { 1146 return j; 1147 } else { 1148 var j = this.skipSpace(str, i); 1149 if((j < 0)) { 1150 return -1; 1151 } else { 1152 var i = j; 1153 } 1154 if((str.charAt(i) == "\"")) { 1155 if((pyjslib_slice(str, i, (i + 3)) == "\"\"\"")) { 1156 var delim = "\"\"\""; 1157 } else { 1158 var delim = "\""; 1159 } 1160 var i = (i + pyjslib_len(delim)); 1161 var pairFudge = this.strconst(str, i, delim); 1162 var j = pairFudge[0]; 1163 var s = pairFudge[1]; 1164 res.push(this._store.literal(s)); 1165 diag_progress("New string const ", s, j); 1166 return j; 1167 } else { 1168 return -1; 1169 } 1170 } 1171 }; 1172 __SinkParser.prototype.nodeOrLiteral = function (str, i, res) { 1173 var j = this.node(str, i, res); 1174 if((j >= 0)) { 1175 return j; 1176 } else { 1177 var j = this.skipSpace(str, i); 1178 if((j < 0)) { 1179 return -1; 1180 } else { 1181 var i = j; 1182 } 1183 var ch = str.charAt(i); 1184 if(("-+0987654321".indexOf(ch) >= 0)) { 1185 number_syntax.lastIndex = 0; 1186 var m = number_syntax.exec(str.slice(i)); 1187 if((m == null)) { 1188 throw BadSyntax(this._thisDoc, this.lines, str, i, "Bad number syntax"); 1189 } 1190 var j = (i + number_syntax.lastIndex); 1191 var val = pyjslib_slice(str, i, j); 1192 if((val.indexOf("e") >= 0)) { 1193 res.push(this._store.literal(parseFloat(val), undefined, this._store.sym(FLOAT_DATATYPE))); 1194 } else if((pyjslib_slice(str, i, j).indexOf(".") >= 0)) { 1195 res.push(this._store.literal(parseFloat(val), undefined, this._store.sym(DECIMAL_DATATYPE))); 1196 } else { 1197 res.push(this._store.literal(parseInt(val), undefined, this._store.sym(INTEGER_DATATYPE))); 1198 } 1199 return j; 1200 } 1201 if((str.charAt(i) == "\"")) { 1202 if((pyjslib_slice(str, i, (i + 3)) == "\"\"\"")) { 1203 var delim = "\"\"\""; 1204 } else { 1205 var delim = "\""; 1206 } 1207 var i = (i + pyjslib_len(delim)); 1208 var dt = null; 1209 var pairFudge = this.strconst(str, i, delim); 1210 var j = pairFudge[0]; 1211 var s = pairFudge[1]; 1212 var lang = null; 1213 if((pyjslib_slice(str, j, (j + 1)) == "@")) { 1214 langcode.lastIndex = 0; 1215 1216 var m = langcode.exec(str.slice((j + 1))); 1217 if((m == null)) { 1218 throw BadSyntax(this._thisDoc, startline, str, i, "Bad language code syntax on string literal, after @"); 1219 } 1220 var i = ((langcode.lastIndex + j) + 1); 1221 1222 var lang = pyjslib_slice(str, (j + 1), i); 1223 var j = i; 1224 } 1225 if((pyjslib_slice(str, j, (j + 2)) == "^^")) { 1226 var res2 = new pyjslib_List([]); 1227 var j = this.uri_ref2(str, (j + 2), res2); 1228 var dt = res2[0]; 1229 } 1230 res.push(this._store.literal(s, lang, dt)); 1231 return j; 1232 } else { 1233 return -1; 1234 } 1235 } 1236 }; 1237 __SinkParser.prototype.strconst = function (str, i, delim) { 1238 /* 1239 parse an N3 string constant delimited by delim. 1240 return index, val 1241 */ 1242 1243 var j = i; 1244 var ustr = ""; 1245 var startline = this.lines; 1246 while((j < pyjslib_len(str))) { 1247 var i = (j + pyjslib_len(delim)); 1248 if((pyjslib_slice(str, j, i) == delim)) { 1249 return new pyjslib_Tuple([i, ustr]); 1250 } 1251 if((str.charAt(j) == "\"")) { 1252 var ustr = (ustr + "\""); 1253 var j = (j + 1); 1254 continue; 1255 } 1256 interesting.lastIndex = 0; 1257 var m = interesting.exec(str.slice(j)); 1258 if(!(m)) { 1259 throw BadSyntax(this._thisDoc, startline, str, j, ((("Closing quote missing in string at ^ in " + pyjslib_slice(str, (j - 20), j)) + "^") + pyjslib_slice(str, j, (j + 20)))); 1260 } 1261 var i = ((j + interesting.lastIndex) - 1); 1262 var ustr = (ustr + pyjslib_slice(str, j, i)); 1263 var ch = str.charAt(i); 1264 if((ch == "\"")) { 1265 var j = i; 1266 continue; 1267 } else if((ch == "\r")) { 1268 var j = (i + 1); 1269 continue; 1270 } else if((ch == "\n")) { 1271 if((delim == "\"")) { 1272 throw BadSyntax(this._thisDoc, startline, str, i, "newline found in string literal"); 1273 } 1274 this.lines = (this.lines + 1); 1275 var ustr = (ustr + ch); 1276 var j = (i + 1); 1277 this.previousLine = this.startOfLine; 1278 this.startOfLine = j; 1279 } else if((ch == "\\")) { 1280 var j = (i + 1); 1281 var ch = pyjslib_slice(str, j, (j + 1)); 1282 if(!(ch)) { 1283 throw BadSyntax(this._thisDoc, startline, str, i, "unterminated string literal (2)"); 1284 } 1285 var k = string_find("abfrtvn\\\"", ch); 1286 if((k >= 0)) { 1287 var uch = "\a\b\f\r\t\v\n\\\"".charAt(k); 1288 var ustr = (ustr + uch); 1289 var j = (j + 1); 1290 } else if((ch == "u")) { 1291 var pairFudge = this.uEscape(str, (j + 1), startline); 1292 var j = pairFudge[0]; 1293 var ch = pairFudge[1]; 1294 var ustr = (ustr + ch); 1295 } else if((ch == "U")) { 1296 var pairFudge = this.UEscape(str, (j + 1), startline); 1297 var j = pairFudge[0]; 1298 var ch = pairFudge[1]; 1299 var ustr = (ustr + ch); 1300 } else { 1301 throw BadSyntax(this._thisDoc, this.lines, str, i, "bad escape"); 1302 } 1303 } 1304 } 1305 throw BadSyntax(this._thisDoc, this.lines, str, i, "unterminated string literal"); 1306 }; 1307 __SinkParser.prototype.uEscape = function (str, i, startline) { 1308 var j = i; 1309 var count = 0; 1310 var value = 0; 1311 while((count < 4)) { 1312 var chFudge = pyjslib_slice(str, j, (j + 1)); 1313 var ch = chFudge.toLowerCase(); 1314 var j = (j + 1); 1315 if((ch == "")) { 1316 throw BadSyntax(this._thisDoc, startline, str, i, "unterminated string literal(3)"); 1317 } 1318 var k = string_find("0123456789abcdef", ch); 1319 if((k < 0)) { 1320 throw BadSyntax(this._thisDoc, startline, str, i, "bad string literal hex escape"); 1321 } 1322 var value = ((value * 16) + k); 1323 var count = (count + 1); 1324 } 1325 var uch = String.fromCharCode(value); 1326 return new pyjslib_Tuple([j, uch]); 1327 }; 1328 __SinkParser.prototype.UEscape = function (str, i, startline) { 1329 var j = i; 1330 var count = 0; 1331 var value = "\\U"; 1332 while((count < 8)) { 1333 var chFudge = pyjslib_slice(str, j, (j + 1)); 1334 var ch = chFudge.toLowerCase(); 1335 var j = (j + 1); 1336 if((ch == "")) { 1337 throw BadSyntax(this._thisDoc, startline, str, i, "unterminated string literal(3)"); 1338 } 1339 var k = string_find("0123456789abcdef", ch); 1340 if((k < 0)) { 1341 throw BadSyntax(this._thisDoc, startline, str, i, "bad string literal hex escape"); 1342 } 1343 var value = (value + ch); 1344 var count = (count + 1); 1345 } 1346 var uch = stringFromCharCode((("0x" + pyjslib_slice(value, 2, 10)) - 0)); 1347 return new pyjslib_Tuple([j, uch]); 1348 }; 1349 1350 function BadSyntax(uri, lines, str, i, why) { 1351 return(((((((("Line " + (lines + 1)) + " of <") + uri) + ">: Bad syntax: ") + why) + "\nat: \"") + pyjslib_slice(str, i, (i + 30))) + "\""); 1352 } 1353 1354 1355 function stripCR(str) { 1356 var res = ""; 1357 1358 var __ch = new pyjslib_Iterator(str); 1359 try { 1360 while(true) { 1361 var ch = __ch.next(); 1362 1363 1364 if((ch != "\r")) { 1365 var res = (res + ch); 1366 } 1367 1368 } 1369 } catch(e) { 1370 if(e != StopIteration) { 1371 throw e; 1372 } 1373 } 1374 1375 return res; 1376 } 1377 1378 1379 function dummyWrite(x) { 1380 } 1381 1382 return SinkParser; 1383 1384 }();