import NListOp from '@cafetextual/nlist/dist/src/nsource/NListOp'; import PObjectMap, { PRuleResult } from './../org/subalternproductions/seepResource/dsl/parser/PObjectMap'; import { NSourceIncrement } from '@cafetextual/nlist/dist/src/nsource/NSourceIncremet'; import { Assert } from "@cafetextual/util"; import ParseMgr from "./ParseMgr"; import ParseModel from "./ParseModel"; import NSourceList, { applyIncrement } from "@cafetextual/nlist/dist/src/nsource/NSourceList"; import AnyonicParseResult from "./AnyonicParseResult"; import { int } from "@cafetextual/nlist/dist/src/ntree/types"; import AnnotatableGrammarSpec from './AnnotatableGammarSpec'; import GRule from '../org/subalternproductions/seepResource/dsl/parser/grammar/GRule'; import PAnnotator from '../org/subalternproductions/seepResource/dsl/parser/annotator/PAnnotator'; import ISourceList from '@cafetextual/nlist/dist/src/nsource/ISourceList'; import SourceLocation from '@cafetextual/util/dist/src/source/SourceLocation'; import SourceNListWrapper from '@cafetextual/nlist/dist/src/nsource/SourceNListWrapper'; import BreakExpression from '../org/subalternproductions/seepResource/dsl/parsertooling/breakpoint/BreakExpression'; import SeepGrammar from '../org/subalternproductions/seepResource/dsl/parser/SeepGrammar'; import AnnotationStore from '../org/subalternproductions/seepResource/dsl/parser/annotator/annotations/AnnotationStore'; import AAnnotation from '../org/subalternproductions/seepResource/dsl/parser/annotator/annotations/AAnnotation'; function createErrAnnotation(loc:SourceLocation, msg:string):AAnnotation { return new AAnnotation(loc, msg) } /** * Stateful parser. * * - words with an immutable * - Paramatarized by A, the annotation type * */ export default class AnyonicIncrementalParser { constructor (source:NSourceList, aspec:AnnotatableGrammarSpec) { this.suri = source.docURI this.source = source this.content = new SourceNListWrapper(this.source.data, null) this.model = AnyonicIncrementalParser.createParseModel(this.source, aspec) this.parser = ParseMgr.create(this.model) Assert.assert(this.parser.isStartable()) this.parser.start() } parser:ParseMgr model:ParseModel aspec:AnnotatableGrammarSpec // <-- grammar, annotators etc source:NSourceList // <--- source /w versioning, history etc, immutable content:SourceNListWrapper // <-- wrapper around the actual content exposing it to the parser // Q: any need to keep this inmmutable suri:string static createParseModel(source:NSourceList, aspec:AnnotatableGrammarSpec ):ParseModel { // ---- debug state, tdb ---- var debugEnabled:boolean = false var breakPt:BreakExpression = null var parsedGrammar:PRuleResult = null var aspec:AnnotatableGrammarSpec = aspec; var rule:GRule = aspec.rule var grammar:SeepGrammar = aspec.grammar var ruleName:string = aspec.ruleName var content = new SourceNListWrapper(source.data, null) return new ParseModel(content, parsedGrammar, grammar ? grammar : rule, ruleName, breakPt, debugEnabled) } private createParser( model:ParseModel ):ParseMgr { var parser:ParseMgr = ParseMgr.create(model) var debugEnabled:boolean = false var breakPt:BreakExpression = null var parsedGrammar:PRuleResult = null Assert.assert(parser.isStartable()) parser.start() Assert.assert(parser.isValid()) // <--- assume that grammar etc is already validated return parser } doParseAll():AnyonicParseResult { this.parser.invalidate(0) if (!this.parser.isDone() && !this.parser.hasErrored() || this.parser.isValid()) { this.parser = this.parser.parseLine(-1) var suri:string = this.source.docURI var lastValid:int = this.parser.lastValidLine() if (this.parser.hasErrored()) { return this.toParserErrorResult() } Assert.assert(this.parser.isDone()) return this.toParseResult() } Assert.fail() return null } doIncrementalParse(inc:NSourceIncrement):AnyonicParseResult { // apply the incemental change var newSrc = applyIncrement(this.source, inc) // <-- transform (immutable) source data var invalidateAt:int = this.source.invalidateAt if (invalidateAt >= 0) { this.source = newSrc this.model.replaceContent( new SourceNListWrapper( this.source.data, null ) ); // <-- and swap in the new content return this.doParse_low(invalidateAt) } return null // unchanged } protected doParse_low(n:int, isAsync:boolean = false):AnyonicParseResult { // new ParseModel(_content, parsedGrammar, _grammar ? _grammar : _rule, _ruleName, breakPt, debugEnabled) if (!isAsync) { this.parser.invalidate(n) if (!this.parser.isDone() && !this.parser.hasErrored() || this.parser.isValid()) { this.parser = this.parser.parseLine(-1) // <--- parser all lines var lastValid:int = this.parser.lastValidLine() if (this.parser.hasErrored()) { // stopTicking() // reportError(parser) console.log(' ---- errored ----- line: ' + lastValid) return this.toParserErrorResult() } else if (this.parser.isDone()) { // stopTicking() var data:Object = this.parser.data console.log(' ------ parsed ok --------- line: ' + lastValid) console.log(this.showObject(data)) console.log(' --------------- ') return this.toParseResult() } else { console.log(' ---- parsed line ' + this.parser.lastValid() + ' ----') } } } else { // asynchronous Assert.fail() // TODO - implement if (n == this.parser.getLastInvalidated()) { } else { try { var hasInvalidated:boolean = this.parser.invalidate(n) } catch (e) { throw new Error } if (hasInvalidated) { //startTicking() } } } return null } private toParserErrorResult():AnyonicParseResult { var errs:AnnotationStore = this.toParserFailAnnotaion() return new AnyonicParseResult(true, this.suri, null, null, errs, this.source.version, null) } private toParserFailAnnotaion():AnnotationStore { Assert.assert(this.parser.hasErrored()) var content:SourceNListWrapper = this.parser.model.content var errOb:any = this.parser.errorObject() var line:int = errOb.line var loc:SourceLocation = errOb.loc var msg:string = errOb.msg console.log(' error at line' + line + "\n") if (line >= 0) { var txt:string = content.indexToObject(line) console.log(line + ': "' + txt + '"\n') } if (loc) { console.log(' (' +loc.start.column + " - " + loc.end.column + ")\n") } var err:AAnnotation = createErrAnnotation( loc, "parser err: [" + line + "]" + msg) //err.err = "parse" //err.style = "error-link" var store:AnnotationStore = new AnnotationStore(null) store.append(err) store.setVersion(this.source.docURI, this.source.version) return store } private toParseResult():AnyonicParseResult { var annotators:Array = this.aspec.annotators var data:any = this.parser.data var map:PObjectMap = this.parser.map() var annotations:AnnotationStore = this.toAnnotations(data, map, annotators, this.source) return new AnyonicParseResult(false, this.suri, data, map, annotations, this.source.version, this.parser.result()) } private toAnnotations(data:Object, map:PObjectMap, annotators:Array, content:NSourceList):AnnotationStore { var tmp:boolean = false if (tmp && annotators) { var store:AnnotationStore = new AnnotationStore(null) var annotator:PAnnotator for (annotator of annotators) { store = annotator.toAnnotaions( annotator.globaldefs, annotator.globaldefs, data, map, this, store) store.setVersion(content.docURI, content.version) } } return store } private showObject(o:Object):string { return JSON.stringify(o, null, " ") } } // class