import { PRuleResult } from './../org/subalternproductions/seepResource/dsl/parser/PObjectMap'; import ParserDebug from "../org/subalternproductions/seepResource/dsl/parsertooling/ParserDebug"; import ParserState from "../org/subalternproductions/seepResource/dsl/parsertooling/ParserState"; import { int } from "@cafetextual/nlist/dist/src/ntree/types"; import ElementState from "../org/subalternproductions/seepResource/dsl/parsertooling/ElementState"; import RuleState from "../org/subalternproductions/seepResource/dsl/parsertooling/RuleState"; import Assert from "@cafetextual/util/dist/src/assert/Assert"; import GRule, { GElement } from "../org/subalternproductions/seepResource/dsl/parser/grammar/GRule"; import { PElementResult } from "../org/subalternproductions/seepResource/dsl/parser/PObjectMap"; import ParseStackItem from "../org/subalternproductions/seepResource/dsl/parsertooling/ParseStackItem"; import SeepParser from '../org/subalternproductions/seepResource/dsl/parser/SeepParser'; export default class ParseDebugUtil { private static _labels:any; static get labels():any { if (!this._labels) { this._labels = {}; var _labels = this._labels _labels[ParserDebug.ELEMENT_BEFORE] = " about to match element" ; _labels[ParserDebug.ELEMENT_FAIL] = " element failed: "; _labels[ParserDebug.ELEMENT_SKIP] = " element skipped: "; _labels[ParserDebug.ELEMENT_MATCH] = " element matched: "; _labels[ParserDebug.RULE_BEFORE] = "about to attempt to match rule: "; _labels[ParserDebug.RULE_FAIL] = "rule failed: " _labels[ParserDebug.RULE_MATCH] = "rule matched: " _labels[ParserDebug.LINE_RULE_MATCH] = "line matched: " ; _labels[ParserDebug.LINE_RULE_FAIL] = "line failed: "; _labels[ParserDebug.LINE_ELEMENT_SKIP] = "line skip: "; _labels[-1] = "element in progress: "; } return _labels; } static toDetailStr(state:ParserState, breakpoint:int = -1):string { var out:string = "" if (state instanceof ElementState) { var estate:ElementState = state as ElementState; var parent:RuleState = estate.parentRuleState; Assert.assert(estate == parent.currentElementState); out += this.labels[breakpoint]; "\n" out += " " + this.elementToString(estate) + "\n\n" if (estate.element.prefixTokenValue) { if (breakpoint == -1) { out += " matched prefix " + estate.element.prefixTokenValue; } else if (breakpoint == ParserDebug.ELEMENT_FAIL) { if (estate.elementResult.tokenPrefixIndex < 0) { out += " failed to match prefix \"" + estate.element.prefixTokenValue + "\"\n" } } } // --- tokens var e:GElement = estate.element; if (e.possibleNextTokens) { out += "possibleNextTokens: [" var t:string for (t of e.possibleNextTokens) { out += "\"" + t + "\" , "; } out += "]\n" } if (e.nextElementTokens) { out += "nextElementTokens: [ " for (t of e.nextElementTokens) { out += "\"" + t + "\" , "; } out += "]\n" } if (estate.element.childRule == null) { // x. leaf out += this.toElementSummary(parent, estate, null, true); } else if (estate.childResult) { // x. child result out += "\n" + estate.childResult.toString(); } } else if (state instanceof RuleState) { this.labels[-1] = "rule in progress: " var rstate:RuleState = state as RuleState; out = (rstate.asLineRule) ? "--> " : "" out += rstate.showItem(); if (breakpoint == ParserDebug.RULE_FAIL) { out += " rule failed to match \n" out += rstate.ruleResult.toString(); } else if (breakpoint == ParserDebug.RULE_BEFORE) { out += "about to match rule \n" if (rstate.parentElementState.element.prefixTokenValue) { out += " matched token prefix: "; out += " " + rstate.parentElementState.element.tokenName + " = " + rstate.parentElementState.element.prefixTokenValue; } } else { out += this.labels[breakpoint] out += this.ruleToLabel(rstate) + "\n" var len:Number = rstate.ruleResult.results.length; for (var i:int = 0; i < len; i++) { var elementResult:PElementResult = rstate.ruleResult.results[i] out += "\n ---------------- \n" out += elementResult.tr() + "\n" out += this.toElementSummary(rstate, null, elementResult.element, false) + "\n"; } } } return out; } // toDetailStr static toElementSummary(parent:RuleState, estate:ElementState, element:GElement, includeTokens:boolean = true):string { var out:string = ""; var elementResult:PElementResult = element ? this.getResultForElement(parent.ruleResult, element) : estate.elementResult element = element ? element : estate.element; // var elementResult:PElementResult = getResultForElement(parent.ruleResult, element) if (elementResult == null) { out += " no element result found"; return out; } if (elementResult.err != null) { out += "element failed to match: \n" + elementResult.err; } else { out += "element matched: \n" if (elementResult.tokenPrefixIndex >=0) { out += " prefix: " + elementResult.element.tokenName + " = " + this.rawContent(parent.ruleResult, elementResult, "prefix") + "\n" } if (elementResult.tokenSuffixIndex >= 0) { out += " suffix: " + elementResult.element.tokenName + " = " + this.rawContent(parent.ruleResult, elementResult, "suffix") + "\n"; } var contentStr:string = this.rawContent(parent.ruleResult, elementResult, "content") if (elementResult.element.varName) { out += " var \"" + elementResult.element.varName + "\" = \"" out += contentStr + "\"\n"; } else if (elementResult.element.contentTokens && elementResult.element.contentTokens.length > 0) { if (contentStr == null) { console.log(' x '); } out += " content tokens: \"" + contentStr + "\"\n"; } if (elementResult.element.allowMany && elementResult.children) { for (var i:int = 0; i < elementResult.children.length; i++) { out += ' ' + i.toString() + '---' out += this.toSimpleElementTrace(elementResult.children[i]); } } if (elementResult.element.lineAllowMany && elementResult.children) { for (i = 0; i < elementResult.children.length; i++) { out += ' --> ' + i.toString() + '---' out += this.toSimpleElementTrace(elementResult.children[i]); } } } if ( includeTokens) { var e:GElement = elementResult.element; if (e.possibleNextTokens || e.nextElementTokens ) { out += "\n\n ------- token details -----------\n" } if (e.possibleNextTokens) { out += "possibleNextTokens: "; var nt:string for (nt of e.possibleNextTokens) { out += nt + " " } out += "\n" } if (e.nextElementTokens) { out += "nextElementTokens: "; var net:string for (net of e.nextElementTokens) { out += net + " "; } out += "\n" } } return out; } // toElementSummary static toSimpleElementTrace(er:PElementResult):string { return " ----"; } private static ruleToLabel(state:RuleState):string { var r:GRule = state.rule; if (r.name) { return r.name; } return "unnamed rule:" } // ruleToLabel private static rawContent(item:PRuleResult, element:PElementResult, type:string = "all"):string { var from:int; var to:int; if (type == "prefix") { from = element.tokenPrefixIndex; to = element.contentIndex >=0 ? element.contentIndex -1 : element.endIndex; } else if (type == "suffix") { from = element.tokenSuffixIndex; to = element.endIndex } else { from = element.contentIndex to = element.contentEndIndex } if (item.source && from >=0 && to >= 0) { return item.source.slice(from, to+1); } return null; } // rawContent static getResultForElement(result:PRuleResult, e:GElement):PElementResult { var er:PElementResult for (er of result.results) { if (er.element == e) { return er; } } return null; } static toStateString(state:ParserState, includeStackTrace:boolean = true):string { var p:SeepParser = state.p; var out:string = ' -------- parsing state ----------' out += ( "o parsing line " + p.getCurrentLineIndex().toString() + " char index = " + p.getPos().toString() + "\n" ); out += this.toCurrentLineTrace(state); if (includeStackTrace) { out += ' -------- stack trace ----------\n' var stackTrace:Array = this.toStackTrace(state); for (var i:int = 0; i < stackTrace.length; i++) { var s:ParseStackItem = stackTrace[i] s.href = "#parse-debug/" + i.toString(); out += s.text + '\n'; } out += ' ---------------------------------'; } return out; } static toCurrentLineTrace(state:ParserState):string { var p:SeepParser = state.p; var out:string = ""; out += "line " + p.getCurrentLineIndex() + ": \"" + state.p.getCurrentLine() + "\"\n"; if (p.getPos() >0 ) { var matchedText:string = p.getCurrentLine().substr(0, p.getPos()) } else { matchedText = ""; } var unmatchedText:string = "" for (var i:int = 0; i< p.getPos(); i++) { //unmatchedText += " " } if (p.getPos() >= 0) { if (p.getCurrentLine() && (p.getPos() < (p.getCurrentLine().length - 1)) ) { unmatchedText += p.getCurrentLine().substr(p.getPos() , (p.getCurrentLine().length - p.getPos() ) ); } } else { unmatchedText = ""; } out += "line " + p.getCurrentLineIndex() + ": \"" + matchedText + "\" <--(matched until here) \n"; out += "line " + p.getCurrentLineIndex() + ": \"" + unmatchedText + "\" <--- (unmatched from here) \n"; return out; } /** * returns an array of ParseStackItem */ static toStackTrace(state:ParserState, out:Array = null, breakpoint:int = -1):Array { out = out ? out : []; var outStr:string = ""; if (state instanceof ElementState) { var estate:ElementState = state as ElementState; if (estate.parentRuleState) { this.toStackTrace(estate.parentRuleState, out); } out.push(this.toStackItem( this.elementToString(estate), state, breakpoint) ); } else if (state instanceof RuleState) { var rstate:RuleState = state as RuleState; if (breakpoint == ParserDebug.RULE_BEFORE) { outStr += "rule before"; } else { var elementState:ElementState = rstate.currentElementState; if (elementState) { outStr += this.elementToString(elementState); } else { outStr += " -- no current element found --- \n\n" + rstate.ruleResult.toString(); } } // recurse up the call chain if (rstate.parentElementState) { this.toStackTrace(rstate.parentElementState, out); } else if (rstate.parentRuleState) { outStr = "--> " + outStr; this.toStackTrace(rstate.parentRuleState, out); } if (rstate.rule.name) { out.push(this.toStackItem( (rstate.rule.name + ":"), rstate, breakpoint) ); } else { out.push(this.toStackItem((" " + outStr), state, breakpoint)); } } return out; } // toStackTrace private static toStackItem(text:string, state:ParserState, breakpoint:int = -1):ParseStackItem { var o:ParseStackItem = new ParseStackItem; o.label = state.toTraceString(); o.text = text; o.match = "n/a" o.state = state; o.breakpoint = breakpoint; return o; } static elementToString(v:ElementState | GElement):string { var e:GElement = (v instanceof ElementState) ? (v as ElementState).element : v as GElement var out:string = ""; out += e.asTreeType ? "^^" : ""; out += e.asTree ? "^" : ""; out += e.tokenName ? e.tokenName : ""; out += e.varName ? ('(' + e.varName + ')' ) : ""; out += e.childRuleStr ? ("[" + e.childRuleStr + ']') : ""; // FIX_THIS - line rule elememt doesn't seem to have this if (e.childRule && !e.childRuleStr && !e.childRuleName && e.childRule.elements.length == 1) { out += "::" + this.elementToString(e.childRule.child(0) ); } out += e.childRuleName ? (":" + e.childRuleName) : ""; out += e.multiplicity ? e.multiplicity : ""; out += e.wsPolicy ? e.wsPolicy : ""; return out; } // elementToString static toStateStack(state:ParserState, asItems:boolean = false, hrefPrefix:string = "#parse-debug"):Array | Array{ var itemStack:Array = ParseDebugUtil.toStackTrace(state, null, state.breakpoint); var stack:Array = []; for (var i:int = 0; i < itemStack.length; i++) { var item:ParseStackItem = itemStack[i]; item.href = hrefPrefix + i.toString(); } if (!asItems) { for (item of itemStack) { stack.push(item.state); } return stack } return itemStack; } static traceState(state:ParserState):string { var stack:Array = this.toStateStack(state) as Array var out:string = this.traceStack(stack); console.log("=== state ===\n" + out + " paused at: " + ParserDebug.toBreakStr(state.breakpoint) ) if (state.breakpoint == ParserDebug.ELEMENT_LEAF_POST) { var e:GElement = (state as ElementState).element; var result:PElementResult = (state as ElementState).elementResult; if (e.varName || e.tokenName) { if (e.varName) { var match:string = result.varStr; console.log(' matched (' + e.varName + ') = "' + match + '"'); } else if (e.tokenName) { console.log(' matched : ' + e.tokenName); } console.log(" >> " + state.p.matchStatus); var x:int = 1; } } console.log("\n=============="); return out; } static traceStack(stack:Array):string { var out:string = "" for (var i:int = 0; i < stack.length; i++) { out += i.toString() + stack[i].toTraceString() + "\n"; } return out; } } // class