diff options
Diffstat (limited to 'compiler/syntaxes.nim')
-rw-r--r-- | compiler/syntaxes.nim | 203 |
1 files changed, 90 insertions, 113 deletions
diff --git a/compiler/syntaxes.nim b/compiler/syntaxes.nim index 4745b1ac7..6b325c77f 100644 --- a/compiler/syntaxes.nim +++ b/compiler/syntaxes.nim @@ -10,60 +10,39 @@ ## Implements the dispatcher for the different parsers. import - strutils, llstream, ast, astalgo, idents, lexer, options, msgs, parser, - pbraces, filters, filter_tmpl, renderer + llstream, ast, idents, lexer, options, msgs, parser, + filters, filter_tmpl, renderer, lineinfos, pathutils -type - TFilterKind* = enum - filtNone, filtTemplate, filtReplace, filtStrip - TParserKind* = enum - skinStandard, skinStrongSpaces, skinBraces, skinEndX +import std/strutils +when defined(nimPreviewSlimSystem): + import std/[syncio, assertions] -const - parserNames*: array[TParserKind, string] = ["standard", "strongspaces", - "braces", "endx"] - filterNames*: array[TFilterKind, string] = ["none", "stdtmpl", "replace", - "strip"] +export Parser, parseAll, parseTopLevelStmt, checkFirstLineIndentation, closeParser type - TParsers* = object - skin*: TParserKind - parser*: TParser - -proc parseAll*(p: var TParsers): PNode = - case p.skin - of skinStandard, skinStrongSpaces: - result = parser.parseAll(p.parser) - of skinBraces: - result = pbraces.parseAll(p.parser) - of skinEndX: - internalError("parser to implement") - result = ast.emptyNode - -proc parseTopLevelStmt*(p: var TParsers): PNode = - case p.skin - of skinStandard, skinStrongSpaces: - result = parser.parseTopLevelStmt(p.parser) - of skinBraces: - result = pbraces.parseTopLevelStmt(p.parser) - of skinEndX: - internalError("parser to implement") - result = ast.emptyNode + FilterKind = enum + filtNone = "none" + filtTemplate = "stdtmpl" + filtReplace = "replace" + filtStrip = "strip" proc utf8Bom(s: string): int = - if s[0] == '\xEF' and s[1] == '\xBB' and s[2] == '\xBF': - result = 3 + if s.len >= 3 and s[0] == '\xEF' and s[1] == '\xBB' and s[2] == '\xBF': + 3 else: - result = 0 + 0 proc containsShebang(s: string, i: int): bool = - if s[i] == '#' and s[i+1] == '!': + if i+1 < s.len and s[i] == '#' and s[i+1] == '!': var j = i + 2 - while s[j] in Whitespace: inc(j) + 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): PNode = - result = ast.emptyNode +proc parsePipe(filename: AbsoluteFile, inputStream: PLLStream; cache: IdentCache; + config: ConfigRef): PNode = + result = newNode(nkEmpty) var s = llStreamOpen(filename, fmRead) if s != nil: var line = newStringOfCap(80) @@ -74,95 +53,93 @@ proc parsePipe(filename: string, inputStream: PLLStream; cache: IdentCache): PNo discard llStreamReadLine(s, line) i = 0 inc linenumber - if line[i] == '#' and line[i+1] == '?': - inc(i, 2) - while line[i] in Whitespace: inc(i) - var q: TParser - parser.openParser(q, filename, llStreamOpen(substr(line, i)), cache) - result = parser.parseAll(q) - parser.closeParser(q) + if i+1 < line.len and line[i] == '#' and line[i+1] == '?': + 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(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 - rawMessage(errInvalidDirectiveX, ident.s) -proc getCallee(n: PNode): PIdent = - if n.kind in nkCallKinds and n.sons[0].kind == nkIdent: - result = n.sons[0].ident +proc getCallee(conf: ConfigRef; n: PNode): PIdent = + if n.kind in nkCallKinds and n[0].kind == nkIdent: + result = n[0].ident elif n.kind == nkIdent: result = n.ident else: - rawMessage(errXNotAllowedHere, renderTree(n)) + 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(n) - var f = getFilter(ident) - case f - of filtNone: - p.skin = getParser(ident) - result = stdin - of filtTemplate: - result = filterTmpl(stdin, filename, n) - of filtStrip: - result = filterStrip(stdin, filename, n) - of filtReplace: - result = filterReplace(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: - if hintCodeBegin in gNotes: - rawMessage(hintCodeBegin, []) - msgWriteln(result.s) - rawMessage(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.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: int32, inputstream: PLLStream; - cache: IdentCache) = - var s: PLLStream - p.skin = skinStandard - let filename = fileIdx.toFullPathConsiderDirty - var pipe = parsePipe(filename, inputstream, cache) - if pipe != nil: s = evalPipe(p, pipe, filename, inputstream) - else: s = inputstream - case p.skin - of skinStandard, skinBraces, skinEndX: - parser.openParser(p.parser, fileIdx, s, cache, false) - of skinStrongSpaces: - parser.openParser(p.parser, fileIdx, s, cache, true) - -proc closeParsers*(p: var TParsers) = - parser.closeParser(p.parser) - -proc parseFile*(fileIdx: int32; cache: IdentCache): PNode {.procvar.} = - var - p: TParsers - f: File - let filename = fileIdx.toFullPathConsiderDirty - if not open(f, filename): - rawMessage(errCannotOpenFile, filename) - return - openParsers(p, fileIdx, llStreamOpen(f), cache) - result = parseAll(p) - closeParsers(p) +proc openParser*(p: var Parser, fileIdx: FileIndex, inputstream: PLLStream; + cache: IdentCache; config: ConfigRef) = + assert config != nil + let filename = toFullPathConsiderDirty(config, fileIdx) + var pipe = parsePipe(filename, inputstream, cache, config) + p.lex.config = config + let s = if pipe != nil: evalPipe(p, pipe, filename, inputstream) + else: inputstream + parser.openParser(p, fileIdx, s, cache, config) + +proc setupParser*(p: var Parser; fileIdx: FileIndex; cache: IdentCache; + config: ConfigRef): bool = + let filename = toFullPathConsiderDirty(config, fileIdx) + 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 |