syntaxes.nim 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. #
  2. #
  3. # The Nim Compiler
  4. # (c) Copyright 2012 Andreas Rumpf
  5. #
  6. # See the file "copying.txt", included in this
  7. # distribution, for details about the copyright.
  8. #
  9. ## Implements the dispatcher for the different parsers.
  10. import
  11. strutils, llstream, ast, astalgo, idents, lexer, options, msgs, parser,
  12. pbraces, filters, filter_tmpl, renderer
  13. type
  14. TFilterKind* = enum
  15. filtNone, filtTemplate, filtReplace, filtStrip
  16. TParserKind* = enum
  17. skinStandard, skinStrongSpaces, skinBraces, skinEndX
  18. const
  19. parserNames*: array[TParserKind, string] = ["standard", "strongspaces",
  20. "braces", "endx"]
  21. filterNames*: array[TFilterKind, string] = ["none", "stdtmpl", "replace",
  22. "strip"]
  23. type
  24. TParsers* = object
  25. skin*: TParserKind
  26. parser*: TParser
  27. proc parseAll*(p: var TParsers): PNode =
  28. case p.skin
  29. of skinStandard, skinStrongSpaces:
  30. result = parser.parseAll(p.parser)
  31. of skinBraces:
  32. result = pbraces.parseAll(p.parser)
  33. of skinEndX:
  34. internalError("parser to implement")
  35. result = ast.emptyNode
  36. proc parseTopLevelStmt*(p: var TParsers): PNode =
  37. case p.skin
  38. of skinStandard, skinStrongSpaces:
  39. result = parser.parseTopLevelStmt(p.parser)
  40. of skinBraces:
  41. result = pbraces.parseTopLevelStmt(p.parser)
  42. of skinEndX:
  43. internalError("parser to implement")
  44. result = ast.emptyNode
  45. proc utf8Bom(s: string): int =
  46. if s[0] == '\xEF' and s[1] == '\xBB' and s[2] == '\xBF':
  47. result = 3
  48. else:
  49. result = 0
  50. proc containsShebang(s: string, i: int): bool =
  51. if s[i] == '#' and s[i+1] == '!':
  52. var j = i + 2
  53. while s[j] in Whitespace: inc(j)
  54. result = s[j] == '/'
  55. proc parsePipe(filename: string, inputStream: PLLStream; cache: IdentCache): PNode =
  56. result = ast.emptyNode
  57. var s = llStreamOpen(filename, fmRead)
  58. if s != nil:
  59. var line = newStringOfCap(80)
  60. discard llStreamReadLine(s, line)
  61. var i = utf8Bom(line)
  62. var linenumber = 1
  63. if containsShebang(line, i):
  64. discard llStreamReadLine(s, line)
  65. i = 0
  66. inc linenumber
  67. if line[i] == '#' and line[i+1] == '?':
  68. inc(i, 2)
  69. while line[i] in Whitespace: inc(i)
  70. var q: TParser
  71. parser.openParser(q, filename, llStreamOpen(substr(line, i)), cache)
  72. result = parser.parseAll(q)
  73. parser.closeParser(q)
  74. llStreamClose(s)
  75. proc getFilter(ident: PIdent): TFilterKind =
  76. for i in countup(low(TFilterKind), high(TFilterKind)):
  77. if cmpIgnoreStyle(ident.s, filterNames[i]) == 0:
  78. return i
  79. result = filtNone
  80. proc getParser(ident: PIdent): TParserKind =
  81. for i in countup(low(TParserKind), high(TParserKind)):
  82. if cmpIgnoreStyle(ident.s, parserNames[i]) == 0:
  83. return i
  84. rawMessage(errInvalidDirectiveX, ident.s)
  85. proc getCallee(n: PNode): PIdent =
  86. if n.kind in nkCallKinds and n.sons[0].kind == nkIdent:
  87. result = n.sons[0].ident
  88. elif n.kind == nkIdent:
  89. result = n.ident
  90. else:
  91. rawMessage(errXNotAllowedHere, renderTree(n))
  92. proc applyFilter(p: var TParsers, n: PNode, filename: string,
  93. stdin: PLLStream): PLLStream =
  94. var ident = getCallee(n)
  95. var f = getFilter(ident)
  96. case f
  97. of filtNone:
  98. p.skin = getParser(ident)
  99. result = stdin
  100. of filtTemplate:
  101. result = filterTmpl(stdin, filename, n)
  102. of filtStrip:
  103. result = filterStrip(stdin, filename, n)
  104. of filtReplace:
  105. result = filterReplace(stdin, filename, n)
  106. if f != filtNone:
  107. if hintCodeBegin in gNotes:
  108. rawMessage(hintCodeBegin, [])
  109. msgWriteln(result.s)
  110. rawMessage(hintCodeEnd, [])
  111. proc evalPipe(p: var TParsers, n: PNode, filename: string,
  112. start: PLLStream): PLLStream =
  113. result = start
  114. if n.kind == nkEmpty: return
  115. if n.kind == nkInfix and n[0].kind == nkIdent and n[0].ident.s == "|":
  116. for i in countup(1, 2):
  117. if n.sons[i].kind == nkInfix:
  118. result = evalPipe(p, n.sons[i], filename, result)
  119. else:
  120. result = applyFilter(p, n.sons[i], filename, result)
  121. elif n.kind == nkStmtList:
  122. result = evalPipe(p, n.sons[0], filename, result)
  123. else:
  124. result = applyFilter(p, n, filename, result)
  125. proc openParsers*(p: var TParsers, fileIdx: int32, inputstream: PLLStream;
  126. cache: IdentCache) =
  127. var s: PLLStream
  128. p.skin = skinStandard
  129. let filename = fileIdx.toFullPathConsiderDirty
  130. var pipe = parsePipe(filename, inputstream, cache)
  131. if pipe != nil: s = evalPipe(p, pipe, filename, inputstream)
  132. else: s = inputstream
  133. case p.skin
  134. of skinStandard, skinBraces, skinEndX:
  135. parser.openParser(p.parser, fileIdx, s, cache, false)
  136. of skinStrongSpaces:
  137. parser.openParser(p.parser, fileIdx, s, cache, true)
  138. proc closeParsers*(p: var TParsers) =
  139. parser.closeParser(p.parser)
  140. proc parseFile*(fileIdx: int32; cache: IdentCache): PNode {.procvar.} =
  141. var
  142. p: TParsers
  143. f: File
  144. let filename = fileIdx.toFullPathConsiderDirty
  145. if not open(f, filename):
  146. rawMessage(errCannotOpenFile, filename)
  147. return
  148. openParsers(p, fileIdx, llStreamOpen(f), cache)
  149. result = parseAll(p)
  150. closeParsers(p)