implements strongSpaces parsing mode

This commit is contained in:
Araq 2014-03-07 22:25:05 +01:00
commit 91d842e1ec
8 changed files with 123 additions and 43 deletions

View file

@ -38,7 +38,6 @@ type
inSemiStmtList: int
proc parseAll*(p: var TParser): PNode
proc openParser*(p: var TParser, filename: string, inputstream: PLLStream)
proc closeParser*(p: var TParser)
proc parseTopLevelStmt*(p: var TParser): PNode
# implements an iterator. Returns the next top-level statement or
@ -50,7 +49,6 @@ proc parseString*(s: string, filename: string = "", line: int = 0): PNode
# correct error messages referring to the original source.
# helpers for the other parsers
proc getPrecedence*(tok: TToken): int
proc isOperator*(tok: TToken): bool
proc getTok*(p: var TParser)
proc parMessage*(p: TParser, msg: TMsgKind, arg: string = "")
@ -77,14 +75,17 @@ proc parseCase(p: var TParser): PNode
proc getTok(p: var TParser) =
rawGetTok(p.lex, p.tok)
proc openParser*(p: var TParser, fileIdx: int32, inputStream: PLLStream) =
proc openParser*(p: var TParser, fileIdx: int32, inputStream: PLLStream,
strongSpaces=false) =
initToken(p.tok)
openLexer(p.lex, fileIdx, inputStream)
getTok(p) # read the first token
p.firstTok = true
p.strongSpaces = strongSpaces
proc openParser*(p: var TParser, filename: string, inputStream: PLLStream) =
openParser(p, filename.fileInfoIdx, inputstream)
proc openParser*(p: var TParser, filename: string, inputStream: PLLStream,
strongSpaces=false) =
openParser(p, filename.fileInfoIdx, inputstream, strongSpaces)
proc closeParser(p: var TParser) =
closeLexer(p.lex)
@ -193,34 +194,52 @@ proc isSigilLike(tok: TToken): bool {.inline.} =
proc isLeftAssociative(tok: TToken): bool {.inline.} =
result = tok.tokType != tkOpr or relevantOprChar(tok.ident) != '^'
proc getPrecedence(tok: TToken): int =
proc getPrecedence(tok: TToken, strongSpaces: bool): int =
template considerStrongSpaces(x): expr =
x + (if strongSpaces: 100 - tok.strongSpaceA.int*10 else: 0)
case tok.tokType
of tkOpr:
let L = tok.ident.s.len
let relevantChar = relevantOprChar(tok.ident)
template considerAsgn(value: expr) =
result = if tok.ident.s[L-1] == '=': 1 else: value
template considerAsgn(value: expr) =
result = if tok.ident.s[L-1] == '=': 1 else: considerStrongSpaces(value)
case relevantChar
of '$', '^': considerAsgn(10)
of '*', '%', '/', '\\': considerAsgn(9)
of '~': result = 8
of '~': result = considerStrongSpaces(8)
of '+', '-', '|': considerAsgn(8)
of '&': considerAsgn(7)
of '=', '<', '>', '!': result = 5
of '=', '<', '>', '!': result = considerStrongSpaces(5)
of '.': considerAsgn(6)
of '?': result = 2
of '?': result = considerStrongSpaces(2)
else: considerAsgn(2)
of tkDiv, tkMod, tkShl, tkShr: result = 9
of tkIn, tkNotin, tkIs, tkIsnot, tkNot, tkOf, tkAs: result = 5
of tkDotDot: result = 6
of tkDotDot: result = considerStrongSpaces(6)
of tkAnd: result = 4
of tkOr, tkXor: result = 3
else: result = - 10
proc isOperator(tok: TToken): bool =
result = getPrecedence(tok) >= 0
else: result = -10
proc isOperator(tok: TToken): bool =
tok.tokType in {tkOpr, tkDiv, tkMod, tkShl, tkShr, tkIn, tkNotin, tkIs,
tkIsnot, tkNot, tkOf, tkAs, tkDotDot, tkAnd, tkOr, tkXor}
proc isUnary(p: TParser): bool =
p.strongSpaces and p.tok.tokType in {tkOpr, tkDotDot} and
p.tok.strongSpaceB == 0 and
p.tok.strongSpaceA > 0
proc checkBinary(p: TParser) {.inline.} =
# we don't check '..' here as that's too annoying
if p.strongSpaces and p.tok.tokType == tkOpr:
if p.tok.strongSpaceB > 0 and p.tok.strongSpaceA != p.tok.strongSpaceB:
parMessage(p, errGenerated, "number of spaces around '$#' not consistent"%
prettyTok(p.tok))
elif p.tok.strongSpaceA notin {0,1,2,4,8}:
parMessage(p, errGenerated, "number of spaces must be 0,1,2,4 or 8")
#| module = stmt ^* (';' / IND{=})
#|
@ -650,6 +669,7 @@ proc primarySuffix(p: var TParser, r: PNode): PNode =
while p.tok.indent < 0:
case p.tok.tokType
of tkParLe:
if p.strongSpaces and p.tok.strongSpaceA > 0: break
result = namedParams(p, result, nkCall, tkParRi)
if result.len > 1 and result.sons[1].kind == nkExprColonExpr:
result.kind = nkObjConstr
@ -664,8 +684,10 @@ proc primarySuffix(p: var TParser, r: PNode): PNode =
result = dotExpr(p, result)
result = parseGStrLit(p, result)
of tkBracketLe:
if p.strongSpaces and p.tok.strongSpaceA > 0: break
result = namedParams(p, result, nkBracketExpr, tkBracketRi)
of tkCurlyLe:
if p.strongSpaces and p.tok.strongSpaceA > 0: break
result = namedParams(p, result, nkCurlyExpr, tkCurlyRi)
of tkSymbol, tkAccent, tkIntLit..tkCharLit, tkNil, tkCast:
if p.inPragma == 0:
@ -695,10 +717,11 @@ proc primary(p: var TParser, mode: TPrimaryMode): PNode
proc simpleExprAux(p: var TParser, limit: int, mode: TPrimaryMode): PNode =
result = primary(p, mode)
# expand while operators have priorities higher than 'limit'
var opPrec = getPrecedence(p.tok)
var opPrec = getPrecedence(p.tok, p.strongSpaces)
let modeB = if mode == pmTypeDef: pmTypeDesc else: mode
# the operator itself must not start on a new line:
while opPrec >= limit and p.tok.indent < 0:
while opPrec >= limit and p.tok.indent < 0 and not isUnary(p):
checkBinary(p)
var leftAssoc = ord(isLeftAssociative(p.tok))
var a = newNodeP(nkInfix, p)
var opNode = newIdentNodeP(p.tok.ident, p) # skip operator:
@ -710,7 +733,7 @@ proc simpleExprAux(p: var TParser, limit: int, mode: TPrimaryMode): PNode =
addSon(a, result)
addSon(a, b)
result = a
opPrec = getPrecedence(p.tok)
opPrec = getPrecedence(p.tok, p.strongSpaces)
proc simpleExpr(p: var TParser, mode = pmNormal): PNode =
result = simpleExprAux(p, -1, mode)
@ -1933,7 +1956,9 @@ proc parseString(s: string, filename: string = "", line: int = 0): PNode =
stream.lineOffset = line
var parser: TParser
openParser(parser, filename, stream)
# XXX for now the builtin 'parseStmt/Expr' functions do not know about strong
# spaces...
openParser(parser, filename, stream, false)
result = parser.parseAll
closeParser(parser)