diff options
Diffstat (limited to 'rod/syntaxes.nim')
-rwxr-xr-x | rod/syntaxes.nim | 177 |
1 files changed, 177 insertions, 0 deletions
diff --git a/rod/syntaxes.nim b/rod/syntaxes.nim new file mode 100755 index 000000000..b8e4c1837 --- /dev/null +++ b/rod/syntaxes.nim @@ -0,0 +1,177 @@ +# +# +# The Nimrod Compiler +# (c) Copyright 2009 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +# Implements the dispatcher for the different parsers. + +import + strutils, llstream, ast, astalgo, idents, scanner, options, msgs, pnimsyn, + pbraces, ptmplsyn, filters, rnimsyn + +type + TFilterKind* = enum + filtNone, filtTemplate, filtReplace, filtStrip + TParserKind* = enum + skinStandard, skinBraces, skinEndX + +const + parserNames*: array[TParserKind, string] = ["standard", "braces", "endx"] + filterNames*: array[TFilterKind, string] = ["none", "stdtmpl", "replace", + "strip"] + +type + TParsers*{.final.} = object + skin*: TParserKind + parser*: TParser + + +proc ParseFile*(filename: string): PNode{.procvar.} +proc openParsers*(p: var TParsers, filename: string, inputstream: PLLStream) +proc closeParsers*(p: var TParsers) +proc parseAll*(p: var TParsers): PNode +proc parseTopLevelStmt*(p: var TParsers): PNode + # implements an iterator. Returns the next top-level statement or nil if end + # of stream. +# implementation + +proc ParseFile(filename: string): PNode = + var + p: TParsers + f: tfile + if not open(f, filename): + rawMessage(errCannotOpenFile, filename) + return + OpenParsers(p, filename, LLStreamOpen(f)) + result = ParseAll(p) + CloseParsers(p) + +proc parseAll(p: var TParsers): PNode = + case p.skin + of skinStandard: + result = pnimsyn.parseAll(p.parser) + of skinBraces: + result = pbraces.parseAll(p.parser) + of skinEndX: + InternalError("parser to implement") # skinEndX: result := pendx.parseAll(p.parser); + +proc parseTopLevelStmt(p: var TParsers): PNode = + case p.skin + of skinStandard: + result = pnimsyn.parseTopLevelStmt(p.parser) + of skinBraces: + result = pbraces.parseTopLevelStmt(p.parser) + of skinEndX: + InternalError("parser to implement") #skinEndX: result := pendx.parseTopLevelStmt(p.parser); + +proc UTF8_BOM(s: string): int = + if (s[0] == '\xEF') and (s[0 + 1] == '\xBB') and (s[0 + 2] == '\xBF'): + result = 3 + else: + result = 0 + +proc containsShebang(s: string, i: int): bool = + var j: int + result = false + if (s[i] == '#') and (s[i + 1] == '!'): + j = i + 2 + while s[j] in WhiteSpace: inc(j) + result = s[j] == '/' + +proc parsePipe(filename: string, inputStream: PLLStream): PNode = + var + line: string + s: PLLStream + i: int + q: TParser + result = nil + s = LLStreamOpen(filename, fmRead) + if s != nil: + line = LLStreamReadLine(s) + i = UTF8_Bom(line) + 0 + if containsShebang(line, i): + line = LLStreamReadLine(s) + i = 0 + if (line[i] == '#') and (line[i + 1] == '!'): + inc(i, 2) + while line[i] in WhiteSpace: inc(i) + OpenParser(q, filename, LLStreamOpen(copy(line, i))) + result = pnimsyn.parseAll(q) + CloseParser(q) + LLStreamClose(s) + +proc getFilter(ident: PIdent): TFilterKind = + for i in countup(low(TFilterKind), high(TFilterKind)): + if IdentEq(ident, filterNames[i]): + return i + result = filtNone + +proc getParser(ident: PIdent): TParserKind = + for i in countup(low(TParserKind), high(TParserKind)): + if IdentEq(ident, parserNames[i]): + return i + rawMessage(errInvalidDirectiveX, ident.s) + +proc getCallee(n: PNode): PIdent = + if (n.kind == nkCall) and (n.sons[0].kind == nkIdent): + result = n.sons[0].ident + elif n.kind == nkIdent: + result = n.ident + else: + rawMessage(errXNotAllowedHere, renderTree(n)) + +proc applyFilter(p: var TParsers, n: PNode, filename: string, stdin: PLLStream): PLLStream = + var + ident: PIdent + f: TFilterKind + ident = getCallee(n) + 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) + if f != filtNone: + if gVerbosity >= 2: + rawMessage(hintCodeBegin) + messageOut(result.s) + rawMessage(hintCodeEnd) + +proc evalPipe(p: var TParsers, n: PNode, filename: string, start: PLLStream): PLLStream = + result = start + if n == nil: return + if (n.kind == nkInfix) and (n.sons[0].kind == nkIdent) and + IdentEq(n.sons[0].ident, "|"): + for i in countup(1, 2): + if n.sons[i].kind == nkInfix: + result = evalPipe(p, n.sons[i], filename, result) + else: + result = applyFilter(p, n.sons[i], filename, result) + elif n.kind == nkStmtList: + result = evalPipe(p, n.sons[0], filename, result) + else: + result = applyFilter(p, n, filename, result) + +proc openParsers(p: var TParsers, filename: string, inputstream: PLLStream) = + var + pipe: PNode + s: PLLStream + p.skin = skinStandard + pipe = parsePipe(filename, inputStream) + if pipe != nil: s = evalPipe(p, pipe, filename, inputStream) + else: s = inputStream + case p.skin + of skinStandard, skinBraces, skinEndX: pnimsyn.openParser(p.parser, filename, + s) + +proc closeParsers(p: var TParsers) = + pnimsyn.closeParser(p.parser) |