summary refs log tree commit diff stats
path: root/compiler/syntaxes.nim
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/syntaxes.nim')
-rw-r--r--compiler/syntaxes.nim203
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