summary refs log tree commit diff stats
path: root/rod/syntaxes.nim
diff options
context:
space:
mode:
Diffstat (limited to 'rod/syntaxes.nim')
-rwxr-xr-xrod/syntaxes.nim177
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)