diff options
Diffstat (limited to 'compiler/syntaxes.nim')
-rw-r--r-- | compiler/syntaxes.nim | 176 |
1 files changed, 76 insertions, 100 deletions
diff --git a/compiler/syntaxes.nim b/compiler/syntaxes.nim index 069f65eee..6b325c77f 100644 --- a/compiler/syntaxes.nim +++ b/compiler/syntaxes.nim @@ -10,55 +10,37 @@ ## Implements the dispatcher for the different parsers. import - strutils, llstream, ast, astalgo, idents, lexer, options, msgs, parser, - filters, filter_tmpl, renderer, lineinfos + llstream, ast, idents, lexer, options, msgs, parser, + filters, filter_tmpl, renderer, lineinfos, pathutils -type - TFilterKind* = enum - filtNone, filtTemplate, filtReplace, filtStrip - TParserKind* = enum - skinStandard, skinStrongSpaces, skinEndX +import std/strutils +when defined(nimPreviewSlimSystem): + import std/[syncio, assertions] -const - parserNames*: array[TParserKind, string] = ["standard", "strongspaces", - "endx"] - filterNames*: array[TFilterKind, string] = ["none", "stdtmpl", "replace", - "strip"] +export Parser, parseAll, parseTopLevelStmt, checkFirstLineIndentation, closeParser type - TParsers* = object - skin*: TParserKind - parser*: TParser - -template config(p: TParsers): ConfigRef = p.parser.lex.config - -proc parseAll*(p: var TParsers): PNode = - case p.skin - of skinStandard, skinStrongSpaces: - result = parser.parseAll(p.parser) - of skinEndX: - internalError(p.config, "parser to implement") - -proc parseTopLevelStmt*(p: var TParsers): PNode = - case p.skin - of skinStandard, skinStrongSpaces: - result = parser.parseTopLevelStmt(p.parser) - of skinEndX: - internalError(p.config, "parser to implement") + FilterKind = enum + filtNone = "none" + filtTemplate = "stdtmpl" + filtReplace = "replace" + filtStrip = "strip" proc utf8Bom(s: string): int = if s.len >= 3 and s[0] == '\xEF' and s[1] == '\xBB' and s[2] == '\xBF': - result = 3 + 3 else: - result = 0 + 0 proc containsShebang(s: string, i: int): bool = if i+1 < s.len and s[i] == '#' and s[i+1] == '!': var j = i + 2 while j < s.len and s[j] in Whitespace: inc(j) result = s[j] == '/' + else: + result = false -proc parsePipe(filename: string, inputStream: PLLStream; cache: IdentCache; +proc parsePipe(filename: AbsoluteFile, inputStream: PLLStream; cache: IdentCache; config: ConfigRef): PNode = result = newNode(nkEmpty) var s = llStreamOpen(filename, fmRead) @@ -72,98 +54,92 @@ proc parsePipe(filename: string, inputStream: PLLStream; cache: IdentCache; i = 0 inc linenumber if i+1 < line.len and line[i] == '#' and line[i+1] == '?': - inc(i, 2) - while i < line.len and line[i] in Whitespace: inc(i) - var q: TParser - parser.openParser(q, filename, llStreamOpen(substr(line, i)), cache, config) - result = parser.parseAll(q) - parser.closeParser(q) + when defined(nimpretty): + # XXX this is a bit hacky, but oh well... + config.quitOrRaise "can't nimpretty a source code filter: " & $filename + else: + inc(i, 2) + while i < line.len and line[i] in Whitespace: inc(i) + var p: Parser = default(Parser) + openParser(p, filename, llStreamOpen(substr(line, i)), cache, config) + result = parseAll(p) + closeParser(p) llStreamClose(s) -proc getFilter(ident: PIdent): TFilterKind = - for i in countup(low(TFilterKind), high(TFilterKind)): - if cmpIgnoreStyle(ident.s, filterNames[i]) == 0: - return i +proc getFilter(ident: PIdent): FilterKind = result = filtNone - -proc getParser(conf: ConfigRef; n: PNode; ident: PIdent): TParserKind = - for i in countup(low(TParserKind), high(TParserKind)): - if cmpIgnoreStyle(ident.s, parserNames[i]) == 0: + for i in FilterKind: + if cmpIgnoreStyle(ident.s, $i) == 0: return i - localError(conf, n.info, "unknown parser: " & ident.s) proc getCallee(conf: ConfigRef; n: PNode): PIdent = - if n.kind in nkCallKinds and n.sons[0].kind == nkIdent: - result = n.sons[0].ident + if n.kind in nkCallKinds and n[0].kind == nkIdent: + result = n[0].ident elif n.kind == nkIdent: result = n.ident else: + result = nil localError(conf, n.info, "invalid filter: " & renderTree(n)) -proc applyFilter(p: var TParsers, n: PNode, filename: string, +proc applyFilter(p: var Parser, n: PNode, filename: AbsoluteFile, stdin: PLLStream): PLLStream = - var ident = getCallee(p.config, n) - var f = getFilter(ident) - case f - of filtNone: - p.skin = getParser(p.config, n, ident) - result = stdin - of filtTemplate: - result = filterTmpl(stdin, filename, n, p.config) - of filtStrip: - result = filterStrip(p.config, stdin, filename, n) - of filtReplace: - result = filterReplace(p.config, stdin, filename, n) + var f = getFilter(getCallee(p.lex.config, n)) + result = case f + of filtNone: + stdin + of filtTemplate: + filterTmpl(p.lex.config, stdin, filename, n) + of filtStrip: + filterStrip(p.lex.config, stdin, filename, n) + of filtReplace: + filterReplace(p.lex.config, stdin, filename, n) if f != filtNone: - assert p.config != nil - if hintCodeBegin in p.config.notes: - rawMessage(p.config, hintCodeBegin, []) - msgWriteln(p.config, result.s) - rawMessage(p.config, hintCodeEnd, []) + assert p.lex.config != nil + if p.lex.config.hasHint(hintCodeBegin): + rawMessage(p.lex.config, hintCodeBegin, "") + msgWriteln(p.lex.config, result.s) + rawMessage(p.lex.config, hintCodeEnd, "") -proc evalPipe(p: var TParsers, n: PNode, filename: string, +proc evalPipe(p: var Parser, n: PNode, filename: AbsoluteFile, start: PLLStream): PLLStream = - assert p.config != nil + assert p.lex.config != nil result = start if n.kind == nkEmpty: return if n.kind == nkInfix and n[0].kind == nkIdent and n[0].ident.s == "|": - for i in countup(1, 2): - if n.sons[i].kind == nkInfix: - result = evalPipe(p, n.sons[i], filename, result) + for i in 1..2: + if n[i].kind == nkInfix: + result = evalPipe(p, n[i], filename, result) else: - result = applyFilter(p, n.sons[i], filename, result) + result = applyFilter(p, n[i], filename, result) elif n.kind == nkStmtList: - result = evalPipe(p, n.sons[0], filename, result) + result = evalPipe(p, n[0], filename, result) else: result = applyFilter(p, n, filename, result) -proc openParsers*(p: var TParsers, fileIdx: FileIndex, inputstream: PLLStream; +proc openParser*(p: var Parser, fileIdx: FileIndex, inputstream: PLLStream; cache: IdentCache; config: ConfigRef) = assert config != nil - var s: PLLStream - p.skin = skinStandard let filename = toFullPathConsiderDirty(config, fileIdx) var pipe = parsePipe(filename, inputstream, cache, config) - p.config() = config - if pipe != nil: s = evalPipe(p, pipe, filename, inputstream) - else: s = inputstream - case p.skin - of skinStandard, skinEndX: - parser.openParser(p.parser, fileIdx, s, cache, config, false) - of skinStrongSpaces: - parser.openParser(p.parser, fileIdx, s, cache, config, true) + p.lex.config = config + let s = if pipe != nil: evalPipe(p, pipe, filename, inputstream) + else: inputstream + parser.openParser(p, fileIdx, s, cache, config) -proc closeParsers*(p: var TParsers) = - parser.closeParser(p.parser) - -proc parseFile*(fileIdx: FileIndex; cache: IdentCache; config: ConfigRef): PNode {.procvar.} = - var - p: TParsers - f: File +proc setupParser*(p: var Parser; fileIdx: FileIndex; cache: IdentCache; + config: ConfigRef): bool = let filename = toFullPathConsiderDirty(config, fileIdx) - if not open(f, filename): - rawMessage(config, errGenerated, "cannot open file: " & filename) - return - openParsers(p, fileIdx, llStreamOpen(f), cache, config) - result = parseAll(p) - closeParsers(p) + var f: File = default(File) + if not open(f, filename.string): + rawMessage(config, errGenerated, "cannot open file: " & filename.string) + return false + openParser(p, fileIdx, llStreamOpen(f), cache, config) + result = true + +proc parseFile*(fileIdx: FileIndex; cache: IdentCache; config: ConfigRef): PNode = + var p: Parser = default(Parser) + if setupParser(p, fileIdx, cache, config): + result = parseAll(p) + closeParser(p) + else: + result = nil |