first step to get rid of nil in the AST

This commit is contained in:
Araq 2011-02-09 00:26:41 +01:00
commit 27dc54cbda
17 changed files with 505 additions and 436 deletions

View file

@ -577,12 +577,10 @@ proc newSons*(father: PNode, length: int)
proc newSons*(father: PType, length: int) proc newSons*(father: PType, length: int)
proc addSon*(father, son: PNode) proc addSon*(father, son: PNode)
proc addSon*(father, son: PType) proc addSon*(father, son: PType)
proc addSonIfNotNil*(father, n: PNode)
proc delSon*(father: PNode, idx: int) proc delSon*(father: PNode, idx: int)
proc hasSonWith*(n: PNode, kind: TNodeKind): bool proc hasSonWith*(n: PNode, kind: TNodeKind): bool
proc hasSubnodeWith*(n: PNode, kind: TNodeKind): bool proc hasSubnodeWith*(n: PNode, kind: TNodeKind): bool
proc replaceSons*(n: PNode, oldKind, newKind: TNodeKind) proc replaceSons*(n: PNode, oldKind, newKind: TNodeKind)
proc sonsNotNil*(n: PNode): bool
proc copyNode*(src: PNode): PNode proc copyNode*(src: PNode): PNode
# does not copy its sons! # does not copy its sons!
proc copyTree*(src: PNode): PNode proc copyTree*(src: PNode): PNode
@ -590,6 +588,10 @@ proc copyTree*(src: PNode): PNode
proc discardSons*(father: PNode) proc discardSons*(father: PNode)
var emptyNode* = newNode(nkEmpty)
# There is a single empty node that is shared! Do not overwrite it!
const # for all kind of hash tables: const # for all kind of hash tables:
GrowthFactor* = 2 # must be power of 2, > 0 GrowthFactor* = 2 # must be power of 2, > 0
StartSize* = 8 # must be power of 2, > 0 StartSize* = 8 # must be power of 2, > 0
@ -868,6 +870,7 @@ proc len*(n: PNode): int {.inline.} =
else: result = len(n.sons) else: result = len(n.sons)
proc add*(father, son: PNode) = proc add*(father, son: PNode) =
assert son != nil
if isNil(father.sons): father.sons = @[] if isNil(father.sons): father.sons = @[]
add(father.sons, son) add(father.sons, son)
@ -879,6 +882,7 @@ proc newSons(father: PNode, length: int) =
setlen(father.sons, len(father.sons) + length) setlen(father.sons, len(father.sons) + length)
proc addSon(father, son: PNode) = proc addSon(father, son: PNode) =
assert son != nil
if isNil(father.sons): father.sons = @[] if isNil(father.sons): father.sons = @[]
add(father.sons, son) add(father.sons, son)
@ -947,7 +951,7 @@ proc lastSon(n: PType): PType =
proc hasSonWith(n: PNode, kind: TNodeKind): bool = proc hasSonWith(n: PNode, kind: TNodeKind): bool =
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):
if (n.sons[i] != nil) and (n.sons[i].kind == kind): if n.sons[i].kind == kind:
return true return true
result = false result = false
@ -956,9 +960,8 @@ proc hasSubnodeWith(n: PNode, kind: TNodeKind): bool =
of nkEmpty..nkNilLit: result = n.kind == kind of nkEmpty..nkNilLit: result = n.kind == kind
else: else:
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):
if n.sons[i] != nil: if (n.sons[i].kind == kind) or hasSubnodeWith(n.sons[i], kind):
if (n.sons[i].kind == kind) or hasSubnodeWith(n.sons[i], kind): return true
return true
result = false result = false
proc replaceSons(n: PNode, oldKind, newKind: TNodeKind) = proc replaceSons(n: PNode, oldKind, newKind: TNodeKind) =
@ -971,9 +974,6 @@ proc sonsNotNil(n: PNode): bool =
return false return false
result = true result = true
proc addSonIfNotNil(father, n: PNode) =
if n != nil: addSon(father, n)
proc getInt*(a: PNode): biggestInt = proc getInt*(a: PNode): biggestInt =
case a.kind case a.kind
of nkIntLit..nkInt64Lit: result = a.intVal of nkIntLit..nkInt64Lit: result = a.intVal

View file

@ -1,7 +1,7 @@
# #
# #
# c2nim - C to Nimrod source converter # c2nim - C to Nimrod source converter
# (c) Copyright 2010 Andreas Rumpf # (c) Copyright 2011 Andreas Rumpf
# #
# See the file "copying.txt", included in this # See the file "copying.txt", included in this
# distribution, for details about the copyright. # distribution, for details about the copyright.
@ -15,7 +15,7 @@ const
Version = NimrodVersion Version = NimrodVersion
Usage = """ Usage = """
c2nim - C to Nimrod source converter c2nim - C to Nimrod source converter
(c) 2010 Andreas Rumpf (c) 2011 Andreas Rumpf
Usage: c2nim [options] inputfile [options] Usage: c2nim [options] inputfile [options]
Options: Options:
-o, --out:FILE set output filename -o, --out:FILE set output filename

View file

@ -197,7 +197,7 @@ proc parLineInfo(p: TParser): TLineInfo =
result = getLineInfo(p.lex) result = getLineInfo(p.lex)
proc skipComAux(p: var TParser, n: PNode) = proc skipComAux(p: var TParser, n: PNode) =
if (n != nil): if n != nil and n.kind != nkEmpty:
if pfSkipComments notin p.options.flags: if pfSkipComments notin p.options.flags:
if n.comment == nil: n.comment = p.tok.s if n.comment == nil: n.comment = p.tok.s
else: add(n.comment, "\n" & p.tok.s) else: add(n.comment, "\n" & p.tok.s)
@ -216,8 +216,7 @@ proc getTok(p: var TParser, n: PNode) =
skipCom(p, n) skipCom(p, n)
proc ExpectIdent(p: TParser) = proc ExpectIdent(p: TParser) =
if p.tok.xkind != pxSymbol: if p.tok.xkind != pxSymbol: parMessage(p, errIdentifierExpected, $(p.tok^))
parMessage(p, errIdentifierExpected, $(p.tok^))
proc Eat(p: var TParser, xkind: TTokKind, n: PNode) = proc Eat(p: var TParser, xkind: TTokKind, n: PNode) =
if p.tok.xkind == xkind: getTok(p, n) if p.tok.xkind == xkind: getTok(p, n)
@ -375,7 +374,7 @@ proc skipTypeIdentExport(p: var TParser, prefix='T'): PNode =
proc markTypeIdent(p: var TParser, typ: PNode) = proc markTypeIdent(p: var TParser, typ: PNode) =
if pfTypePrefixes in p.options.flags: if pfTypePrefixes in p.options.flags:
var prefix = "" var prefix = ""
if typ == nil: if typ == nil or typ.kind == nkEmpty:
prefix = "T" prefix = "T"
else: else:
var t = typ var t = typ
@ -479,11 +478,12 @@ proc newProcPragmas(p: TParser): PNode =
proc addPragmas(father, pragmas: PNode) = proc addPragmas(father, pragmas: PNode) =
if sonsLen(pragmas) > 0: addSon(father, pragmas) if sonsLen(pragmas) > 0: addSon(father, pragmas)
else: addSon(father, nil) else: addSon(father, ast.emptyNode)
proc addReturnType(params, rettyp: PNode) = proc addReturnType(params, rettyp: PNode) =
if rettyp == nil or rettyp.kind != nkNilLit: addSon(params, rettyp) if rettyp == nil: addSon(params, ast.emptyNode)
else: addson(params, nil) elif rettyp.kind != nkNilLit: addSon(params, rettyp)
else: addson(params, ast.emptyNode)
proc parseFormalParams(p: var TParser, params, pragmas: PNode) proc parseFormalParams(p: var TParser, params, pragmas: PNode)
@ -527,9 +527,6 @@ proc parseTypeSuffix(p: var TParser, typ: PNode): PNode =
else: break else: break
proc typeDesc(p: var TParser): PNode = proc typeDesc(p: var TParser): PNode =
#result = typeAtom(p)
#if result != nil:
# result = pointer(p, result)
result = pointer(p, typeAtom(p)) result = pointer(p, typeAtom(p))
proc parseField(p: var TParser, kind: TNodeKind): PNode = proc parseField(p: var TParser, kind: TNodeKind): PNode =
@ -560,7 +557,7 @@ proc parseStructBody(p: var TParser, isUnion: bool,
var t = pointer(p, baseTyp) var t = pointer(p, baseTyp)
var i = parseField(p, kind) var i = parseField(p, kind)
t = parseTypeSuffix(p, t) t = parseTypeSuffix(p, t)
addSon(def, i, t, nil) addSon(def, i, t, ast.emptyNode)
if not takeOnlyFirstField(p, isUnion) or sonsLen(result) < 1: if not takeOnlyFirstField(p, isUnion) or sonsLen(result) < 1:
addSon(result, def) addSon(result, def)
if p.tok.xkind != pxComma: break if p.tok.xkind != pxComma: break
@ -591,7 +588,7 @@ proc enumPragmas(p: TParser, name: PNode): PNode =
proc parseStruct(p: var TParser, isUnion: bool): PNode = proc parseStruct(p: var TParser, isUnion: bool): PNode =
result = newNodeP(nkObjectTy, p) result = newNodeP(nkObjectTy, p)
addSon(result, nil, nil) # no pragmas, no inheritance addSon(result, ast.emptyNode, ast.emptyNode) # no pragmas, no inheritance
if p.tok.xkind == pxCurlyLe: if p.tok.xkind == pxCurlyLe:
addSon(result, parseStructBody(p, isUnion)) addSon(result, parseStructBody(p, isUnion))
else: else:
@ -616,7 +613,7 @@ proc parseParam(p: var TParser, params: PNode) =
getTok(p, x) getTok(p, x)
addSon(x, assignmentExpression(p)) addSon(x, assignmentExpression(p))
else: else:
addSon(x, nil) addSon(x, ast.emptyNode)
addSon(params, x) addSon(params, x)
proc parseFormalParams(p: var TParser, params, pragmas: PNode) = proc parseFormalParams(p: var TParser, params, pragmas: PNode) =
@ -662,15 +659,16 @@ proc parseFunctionPointerDecl(p: var TParser, rettyp: PNode): PNode =
if p.inTypeDef == 0: if p.inTypeDef == 0:
result = newNodeP(nkVarSection, p) result = newNodeP(nkVarSection, p)
var def = newNodeP(nkIdentDefs, p) var def = newNodeP(nkIdentDefs, p)
addSon(def, name, procType, nil) addSon(def, name, procType, ast.emptyNode)
addSon(result, def) addSon(result, def)
else: else:
result = newNodeP(nkTypeDef, p) result = newNodeP(nkTypeDef, p)
addSon(result, name, nil, procType) addSon(result, name, ast.emptyNode, procType)
assert result != nil
proc addTypeDef(section, name, t: PNode) = proc addTypeDef(section, name, t: PNode) =
var def = newNodeI(nkTypeDef, name.info) var def = newNodeI(nkTypeDef, name.info)
addSon(def, name, nil, t) addSon(def, name, ast.emptyNode, t)
addSon(section, def) addSon(section, def)
proc otherTypeDef(p: var TParser, section, typ: PNode) = proc otherTypeDef(p: var TParser, section, typ: PNode) =
@ -705,7 +703,7 @@ proc parseTrailingDefinedTypes(p: var TParser, section, typ: PNode) =
proc enumFields(p: var TParser): PNode = proc enumFields(p: var TParser): PNode =
result = newNodeP(nkEnumTy, p) result = newNodeP(nkEnumTy, p)
addSon(result, nil) # enum does not inherit from anything addSon(result, ast.emptyNode) # enum does not inherit from anything
while true: while true:
var e = skipIdent(p) var e = skipIdent(p)
if p.tok.xkind == pxAsgn: if p.tok.xkind == pxAsgn:
@ -846,7 +844,7 @@ proc addInitializer(p: var TParser, def: PNode) =
getTok(p, def) getTok(p, def)
addSon(def, parseInitializer(p)) addSon(def, parseInitializer(p))
else: else:
addSon(def, nil) addSon(def, ast.emptyNode)
proc parseVarDecl(p: var TParser, baseTyp, typ: PNode, proc parseVarDecl(p: var TParser, baseTyp, typ: PNode,
origName: string): PNode = origName: string): PNode =
@ -921,22 +919,24 @@ proc declaration(p: var TParser): PNode =
addSon(pragmas, newIdentNodeP("cdecl", p)) addSon(pragmas, newIdentNodeP("cdecl", p))
elif pfStdcall in p.options.flags: elif pfStdcall in p.options.flags:
addSon(pragmas, newIdentNodeP("stdcall", p)) addSon(pragmas, newIdentNodeP("stdcall", p))
addSon(result, exportSym(p, name, origName), nil) # no generics addSon(result, exportSym(p, name, origName), ast.emptyNode) # no generics
addSon(result, params, pragmas) addSon(result, params, pragmas)
case p.tok.xkind case p.tok.xkind
of pxSemicolon: of pxSemicolon:
getTok(p) getTok(p)
addSon(result, nil) # nobody addSon(result, ast.emptyNode) # nobody
if p.scopeCounter == 0: DoImport(origName, pragmas, p) if p.scopeCounter == 0: DoImport(origName, pragmas, p)
of pxCurlyLe: of pxCurlyLe:
addSon(result, compoundStatement(p)) addSon(result, compoundStatement(p))
else: else:
parMessage(p, errTokenExpected, ";") parMessage(p, errTokenExpected, ";")
if sonsLen(result.sons[pragmasPos]) == 0: result.sons[pragmasPos] = nil if sonsLen(result.sons[pragmasPos]) == 0:
result.sons[pragmasPos] = ast.emptyNode
of pxAsgn, pxSemicolon, pxComma: of pxAsgn, pxSemicolon, pxComma:
result = parseVarDecl(p, baseTyp, rettyp, origName) result = parseVarDecl(p, baseTyp, rettyp, origName)
else: else:
parMessage(p, errTokenExpected, ";") parMessage(p, errTokenExpected, ";")
assert result != nil
proc createConst(name, typ, val: PNode, p: TParser): PNode = proc createConst(name, typ, val: PNode, p: TParser): PNode =
result = newNodeP(nkConstDef, p) result = newNodeP(nkConstDef, p)
@ -963,7 +963,7 @@ proc enumSpecifier(p: var TParser): PNode =
else: else:
val = newIntNodeP(nkIntLit, i, p) val = newIntNodeP(nkIntLit, i, p)
inc(i) inc(i)
var c = createConst(name, nil, val, p) var c = createConst(name, ast.emptyNode, val, p)
addSon(result, c) addSon(result, c)
if p.tok.xkind != pxComma: break if p.tok.xkind != pxComma: break
getTok(p, c) getTok(p, c)
@ -984,7 +984,7 @@ proc enumSpecifier(p: var TParser): PNode =
var t = newNodeP(nkTypeDef, p) var t = newNodeP(nkTypeDef, p)
getTok(p, t) getTok(p, t)
var e = enumFields(p) var e = enumFields(p)
addSon(t, exportSym(p, name, origName), nil, e) # nil for generic params addSon(t, exportSym(p, name, origName), ast.emptyNode, e)
addSon(result, t) addSon(result, t)
eat(p, pxCurlyRi, result) eat(p, pxCurlyRi, result)
eat(p, pxSemicolon) eat(p, pxSemicolon)
@ -998,6 +998,7 @@ proc enumSpecifier(p: var TParser): PNode =
else: else:
closeContext(p) closeContext(p)
parMessage(p, errTokenExpected, "{") parMessage(p, errTokenExpected, "{")
result = ast.emptyNode
# Expressions # Expressions
@ -1085,7 +1086,7 @@ proc primaryExpression(p: var TParser): PNode =
of pxParLe: of pxParLe:
result = castExpression(p) result = castExpression(p)
else: else:
result = nil result = ast.emptyNode
proc multiplicativeExpression(p: var TParser): PNode = proc multiplicativeExpression(p: var TParser): PNode =
result = castExpression(p) result = castExpression(p)
@ -1309,7 +1310,7 @@ proc andExpression(p: var TParser): PNode =
getTok(p, result) getTok(p, result)
var a = result var a = result
var b = equalityExpression(p) var b = equalityExpression(p)
result = newBinary("&", a, b, p) result = newBinary("and", a, b, p)
proc exclusiveOrExpression(p: var TParser): PNode = proc exclusiveOrExpression(p: var TParser): PNode =
result = andExpression(p) result = andExpression(p)
@ -1390,10 +1391,12 @@ proc expressionStatement(p: var TParser): PNode =
# do not skip the comment after a semicolon to make a new nkCommentStmt # do not skip the comment after a semicolon to make a new nkCommentStmt
if p.tok.xkind == pxSemicolon: if p.tok.xkind == pxSemicolon:
getTok(p) getTok(p)
result = ast.emptyNode
else: else:
result = expression(p) result = expression(p)
if p.tok.xkind == pxSemicolon: getTok(p) if p.tok.xkind == pxSemicolon: getTok(p)
else: parMessage(p, errTokenExpected, ";") else: parMessage(p, errTokenExpected, ";")
assert result != nil
proc parseIf(p: var TParser): PNode = proc parseIf(p: var TParser): PNode =
# we parse additional "else if"s too here for better Nimrod code # we parse additional "else if"s too here for better Nimrod code
@ -1431,7 +1434,7 @@ proc parseDoWhile(p: var TParser): PNode =
# ``block: stmt`` # ``block: stmt``
result = newNodeP(nkBlockStmt, p) result = newNodeP(nkBlockStmt, p)
getTok(p, result) # skip "do" getTok(p, result) # skip "do"
addSon(result, nil, nestedStatement(p)) addSon(result, ast.emptyNode, nestedStatement(p))
eat(p, "while", result) eat(p, "while", result)
eat(p, pxParLe, result) eat(p, pxParLe, result)
if p.tok.xkind == pxIntLit and p.tok.iNumber == 0: getTok(p, result) if p.tok.xkind == pxIntLit and p.tok.iNumber == 0: getTok(p, result)
@ -1465,6 +1468,7 @@ proc declarationOrStatement(p: var TParser): PNode =
else: else:
backtrackContext(p) backtrackContext(p)
result = expressionStatement(p) result = expressionStatement(p)
assert result != nil
proc parseTuple(p: var TParser, isUnion: bool): PNode = proc parseTuple(p: var TParser, isUnion: bool): PNode =
result = parseStructBody(p, isUnion, nkTupleTy) result = parseStructBody(p, isUnion, nkTupleTy)
@ -1516,15 +1520,16 @@ proc parseFor(p: var TParser, result: PNode) =
getTok(p, result) getTok(p, result)
eat(p, pxParLe, result) eat(p, pxParLe, result)
var initStmt = declarationOrStatement(p) var initStmt = declarationOrStatement(p)
addSonIfNotNil(result, initStmt) if initStmt.kind != nkEmpty:
addSon(result, initStmt)
var w = newNodeP(nkWhileStmt, p) var w = newNodeP(nkWhileStmt, p)
var condition = expressionStatement(p) var condition = expressionStatement(p)
if condition == nil: condition = newIdentNodeP("true", p) if condition.kind == nkEmpty: condition = newIdentNodeP("true", p)
addSon(w, condition) addSon(w, condition)
var step = if p.tok.xkind != pxParRi: expression(p) else: nil var step = if p.tok.xkind != pxParRi: expression(p) else: ast.emptyNode
eat(p, pxParRi, step) eat(p, pxParRi, step)
var loopBody = nestedStatement(p) var loopBody = nestedStatement(p)
if step != nil: if step.kind != nkEmpty:
loopBody = buildStmtList(loopBody) loopBody = buildStmtList(loopBody)
addSon(loopBody, step) addSon(loopBody, step)
addSon(w, loopBody) addSon(w, loopBody)
@ -1604,7 +1609,7 @@ proc embedStmts(sl, a: PNode) =
addStmt(sl, a) addStmt(sl, a)
else: else:
for i in 0..sonsLen(a)-1: for i in 0..sonsLen(a)-1:
if a[i] != nil: addStmt(sl, a[i]) if a[i].kind != nkEmpty: addStmt(sl, a[i])
proc compoundStatement(p: var TParser): PNode = proc compoundStatement(p: var TParser): PNode =
result = newNodeP(nkStmtList, p) result = newNodeP(nkStmtList, p)
@ -1612,7 +1617,7 @@ proc compoundStatement(p: var TParser): PNode =
inc(p.scopeCounter) inc(p.scopeCounter)
while p.tok.xkind notin {pxEof, pxCurlyRi}: while p.tok.xkind notin {pxEof, pxCurlyRi}:
var a = statement(p) var a = statement(p)
if a == nil: break if a.kind == nkEmpty: break
embedStmts(result, a) embedStmts(result, a)
if sonsLen(result) == 0: if sonsLen(result) == 0:
# translate ``{}`` to Nimrod's ``nil`` statement # translate ``{}`` to Nimrod's ``nil`` statement
@ -1644,12 +1649,12 @@ proc statement(p: var TParser): PNode =
result = newNodeP(nkContinueStmt, p) result = newNodeP(nkContinueStmt, p)
getTok(p) getTok(p)
eat(p, pxSemicolon) eat(p, pxSemicolon)
addSon(result, nil) addSon(result, ast.emptyNode)
of "break": of "break":
result = newNodeP(nkBreakStmt, p) result = newNodeP(nkBreakStmt, p)
getTok(p) getTok(p)
eat(p, pxSemicolon) eat(p, pxSemicolon)
addSon(result, nil) addSon(result, ast.emptyNode)
of "return": of "return":
result = newNodeP(nkReturnStmt, p) result = newNodeP(nkReturnStmt, p)
getTok(p) getTok(p)
@ -1662,18 +1667,13 @@ proc statement(p: var TParser): PNode =
elif p.tok.xkind != pxSemicolon: elif p.tok.xkind != pxSemicolon:
addSon(result, expression(p)) addSon(result, expression(p))
else: else:
addSon(result, nil) addSon(result, ast.emptyNode)
eat(p, pxSemicolon) eat(p, pxSemicolon)
of "enum": of "enum": result = enumSpecifier(p)
result = enumSpecifier(p) of "typedef": result = parseTypeDef(p)
of "typedef": of "struct": result = parseStandaloneStruct(p, isUnion=false)
result = parseTypeDef(p) of "union": result = parseStandaloneStruct(p, isUnion=true)
of "struct": else: result = declarationOrStatement(p)
result = parseStandaloneStruct(p, isUnion=false)
of "union":
result = parseStandaloneStruct(p, isUnion=true)
else:
result = declarationOrStatement(p)
of pxCurlyLe: of pxCurlyLe:
result = compoundStatement(p) result = compoundStatement(p)
of pxDirective, pxDirectiveParLe: of pxDirective, pxDirectiveParLe:
@ -1691,12 +1691,12 @@ proc statement(p: var TParser): PNode =
result = newNodeP(nkNilLit, p) result = newNodeP(nkNilLit, p)
else: else:
result = expressionStatement(p) result = expressionStatement(p)
#parMessage(p, errStmtExpected) assert result != nil
proc parseUnit(p: var TParser): PNode = proc parseUnit(p: var TParser): PNode =
result = newNodeP(nkStmtList, p) result = newNodeP(nkStmtList, p)
getTok(p) # read first token getTok(p) # read first token
while p.tok.xkind != pxEof: while p.tok.xkind != pxEof:
var s = statement(p) var s = statement(p)
if s != nil: embedStmts(result, s) if s.kind != nkEmpty: embedStmts(result, s)

View file

@ -45,7 +45,7 @@ proc parseDefine(p: var TParser): PNode =
eat(p, pxParLe) eat(p, pxParLe)
var params = newNodeP(nkFormalParams, p) var params = newNodeP(nkFormalParams, p)
# return type; not known yet: # return type; not known yet:
addSon(params, nil) addSon(params, ast.emptyNode)
var identDefs = newNodeP(nkIdentDefs, p) var identDefs = newNodeP(nkIdentDefs, p)
while p.tok.xkind != pxParRi: while p.tok.xkind != pxParRi:
addSon(identDefs, skipIdent(p)) addSon(identDefs, skipIdent(p))
@ -53,13 +53,13 @@ proc parseDefine(p: var TParser): PNode =
if p.tok.xkind != pxComma: break if p.tok.xkind != pxComma: break
getTok(p) getTok(p)
addSon(identDefs, newIdentNodeP("expr", p)) addSon(identDefs, newIdentNodeP("expr", p))
addSon(identDefs, nil) addSon(identDefs, ast.emptyNode)
addSon(params, identDefs) addSon(params, identDefs)
eat(p, pxParRi) eat(p, pxParRi)
addSon(result, nil) # no generic parameters addSon(result, ast.emptyNode) # no generic parameters
addSon(result, params) addSon(result, params)
addSon(result, nil) # no pragmas addSon(result, ast.emptyNode) # no pragmas
var kind = parseDefineBody(p, result) var kind = parseDefineBody(p, result)
params.sons[0] = newIdentNodeP(kind, p) params.sons[0] = newIdentNodeP(kind, p)
eatNewLine(p, result) eatNewLine(p, result)
@ -70,7 +70,7 @@ proc parseDefine(p: var TParser): PNode =
getTok(p) # skip #define getTok(p) # skip #define
var c = newNodeP(nkConstDef, p) var c = newNodeP(nkConstDef, p)
addSon(c, skipIdentExport(p)) addSon(c, skipIdentExport(p))
addSon(c, nil) addSon(c, ast.emptyNode)
skipStarCom(p, c) skipStarCom(p, c)
if p.tok.xkind in {pxLineComment, pxNewLine, pxEof}: if p.tok.xkind in {pxLineComment, pxNewLine, pxEof}:
addSon(c, newIdentNodeP("true", p)) addSon(c, newIdentNodeP("true", p))
@ -78,6 +78,7 @@ proc parseDefine(p: var TParser): PNode =
addSon(c, expression(p)) addSon(c, expression(p))
addSon(result, c) addSon(result, c)
eatNewLine(p, c) eatNewLine(p, c)
assert result != nil
proc parseDefBody(p: var TParser, m: var TMacro, params: seq[string]) = proc parseDefBody(p: var TParser, m: var TMacro, params: seq[string]) =
m.body = @[] m.body = @[]
@ -147,7 +148,7 @@ proc parseInclude(p: var TParser): PNode =
skipLine(p) skipLine(p)
if sonsLen(result) == 0: if sonsLen(result) == 0:
# we only parsed includes that we chose to ignore: # we only parsed includes that we chose to ignore:
result = nil result = ast.emptyNode
proc definedExprAux(p: var TParser): PNode = proc definedExprAux(p: var TParser): PNode =
result = newNodeP(nkCall, p) result = newNodeP(nkCall, p)
@ -226,6 +227,7 @@ proc parseIfdef(p: var TParser): PNode =
case p.tok.s case p.tok.s
of "__cplusplus": of "__cplusplus":
skipUntilEndif(p) skipUntilEndif(p)
result = ast.emptyNode
of c2nimSymbol: of c2nimSymbol:
skipLine(p) skipLine(p)
result = parseStmtList(p) result = parseStmtList(p)
@ -238,6 +240,7 @@ proc parseIfdef(p: var TParser): PNode =
parseIfDirAux(p, result) parseIfDirAux(p, result)
proc parseIfndef(p: var TParser): PNode = proc parseIfndef(p: var TParser): PNode =
result = ast.emptyNode
getTok(p) # skip #ifndef getTok(p) # skip #ifndef
ExpectIdent(p) ExpectIdent(p)
if p.tok.s == c2nimSymbol: if p.tok.s == c2nimSymbol:
@ -295,6 +298,7 @@ proc parseMangleDir(p: var TParser) =
eatNewLine(p, nil) eatNewLine(p, nil)
proc parseDir(p: var TParser): PNode = proc parseDir(p: var TParser): PNode =
result = ast.emptyNode
assert(p.tok.xkind in {pxDirective, pxDirectiveParLe}) assert(p.tok.xkind in {pxDirective, pxDirectiveParLe})
case p.tok.s case p.tok.s
of "define": result = parseDefine(p) of "define": result = parseDefine(p)

View file

@ -29,7 +29,6 @@ proc addDependencyAux(importing, imported: string) =
proc addDotDependency(c: PPassContext, n: PNode): PNode = proc addDotDependency(c: PPassContext, n: PNode): PNode =
result = n result = n
if n == nil: return
var g = PGen(c) var g = PGen(c)
case n.kind case n.kind
of nkImportStmt: of nkImportStmt:

View file

@ -771,7 +771,6 @@ proc traceDeps(d: PDoc, n: PNode) =
"$1", [toRope(getModuleFile(n))]) "$1", [toRope(getModuleFile(n))])
proc generateDoc(d: PDoc, n: PNode) = proc generateDoc(d: PDoc, n: PNode) =
if n == nil: return
case n.kind case n.kind
of nkCommentStmt: app(d.modDesc, genComment(d, n)) of nkCommentStmt: app(d.modDesc, genComment(d, n))
of nkProcDef: genItem(d, n, n.sons[namePos], skProc) of nkProcDef: genItem(d, n, n.sons[namePos], skProc)

View file

@ -54,8 +54,6 @@ const
evalMaxIterations = 10000000 # max iterations of all loops evalMaxIterations = 10000000 # max iterations of all loops
evalMaxRecDepth = 100000 # max recursion depth for evaluation evalMaxRecDepth = 100000 # max recursion depth for evaluation
var emptyNode: PNode
proc newStackFrame(): PStackFrame = proc newStackFrame(): PStackFrame =
new(result) new(result)
initIdNodeTable(result.mapping) initIdNodeTable(result.mapping)
@ -136,7 +134,7 @@ proc evalWhile(c: PEvalContext, n: PNode): PNode =
result = evalAux(c, n.sons[1], {}) result = evalAux(c, n.sons[1], {})
case result.kind case result.kind
of nkBreakStmt: of nkBreakStmt:
if result.sons[0] == nil: if result.sons[0].kind == nkEmpty:
result = emptyNode # consume ``break`` token result = emptyNode # consume ``break`` token
break break
of nkExceptBranch, nkReturnToken: of nkExceptBranch, nkReturnToken:
@ -153,7 +151,7 @@ proc evalBlock(c: PEvalContext, n: PNode): PNode =
if result.kind == nkBreakStmt: if result.kind == nkBreakStmt:
if result.sons[0] != nil: if result.sons[0] != nil:
assert(result.sons[0].kind == nkSym) assert(result.sons[0].kind == nkSym)
if n.sons[0] != nil: if n.sons[0].kind != nkempty:
assert(n.sons[0].kind == nkSym) assert(n.sons[0].kind == nkSym)
if result.sons[0].sym.id == n.sons[0].sym.id: result = emptyNode if result.sons[0].sym.id == n.sons[0].sym.id: result = emptyNode
else: else:
@ -228,7 +226,7 @@ proc evalVar(c: PEvalContext, n: PNode): PNode =
assert(a.kind == nkIdentDefs) assert(a.kind == nkIdentDefs)
assert(a.sons[0].kind == nkSym) assert(a.sons[0].kind == nkSym)
var v = a.sons[0].sym var v = a.sons[0].sym
if a.sons[2] != nil: if a.sons[2].kind != nkEmpty:
result = evalAux(c, a.sons[2], {}) result = evalAux(c, a.sons[2], {})
if isSpecial(result): return if isSpecial(result): return
else: else:
@ -507,7 +505,7 @@ proc evalConvCStrToStr(c: PEvalContext, n: PNode): PNode =
result.typ = n.typ result.typ = n.typ
proc evalRaise(c: PEvalContext, n: PNode): PNode = proc evalRaise(c: PEvalContext, n: PNode): PNode =
if n.sons[0] != nil: if n.sons[0].kind != nkEmpty:
result = evalAux(c, n.sons[0], {}) result = evalAux(c, n.sons[0], {})
if isSpecial(result): return if isSpecial(result): return
var a = result var a = result
@ -519,17 +517,17 @@ proc evalRaise(c: PEvalContext, n: PNode): PNode =
else: else:
stackTrace(c, n, errExceptionAlreadyHandled) stackTrace(c, n, errExceptionAlreadyHandled)
result = newNodeIT(nkExceptBranch, n.info, nil) result = newNodeIT(nkExceptBranch, n.info, nil)
addSon(result, nil) addSon(result, ast.emptyNode)
proc evalReturn(c: PEvalContext, n: PNode): PNode = proc evalReturn(c: PEvalContext, n: PNode): PNode =
if n.sons[0] != nil: if n.sons[0].kind != nkEmpty:
result = evalAsgn(c, n.sons[0]) result = evalAsgn(c, n.sons[0])
if isSpecial(result): return if isSpecial(result): return
result = newNodeIT(nkReturnToken, n.info, nil) result = newNodeIT(nkReturnToken, n.info, nil)
proc evalProc(c: PEvalContext, n: PNode): PNode = proc evalProc(c: PEvalContext, n: PNode): PNode =
if n.sons[genericParamsPos] == nil: if n.sons[genericParamsPos].kind == nkEmpty:
if (resultPos < sonsLen(n)) and (n.sons[resultPos] != nil): if (resultPos < sonsLen(n)) and (n.sons[resultPos].kind != nkEmpty):
var v = n.sons[resultPos].sym var v = n.sons[resultPos].sym
result = getNullValue(v.typ, n.info) result = getNullValue(v.typ, n.info)
IdNodeTablePut(c.tos.mapping, v, result) IdNodeTablePut(c.tos.mapping, v, result)
@ -740,8 +738,7 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode =
if isSpecial(result): return if isSpecial(result): return
var k = getOrdValue(b) var k = getOrdValue(b)
if (k >= 0) and (k < sonsLen(a)) and not (a.kind in {nkEmpty..nkNilLit}): if (k >= 0) and (k < sonsLen(a)) and not (a.kind in {nkEmpty..nkNilLit}):
if result.kind == nkEmpty: a.sons[int(k)] = nil a.sons[int(k)] = result
else: a.sons[int(k)] = result
else: else:
stackTrace(c, n, errIndexOutOfBounds) stackTrace(c, n, errIndexOutOfBounds)
result = emptyNode result = emptyNode
@ -1055,4 +1052,3 @@ proc evalPass(): TPass =
result.close = myProcess result.close = myProcess
result.process = myProcess result.process = myProcess
emptyNode = newNode(nkEmpty)

View file

@ -109,6 +109,7 @@ proc CommandGenDepend(filename: string) =
changeFileExt(filename, "dot")) changeFileExt(filename, "dot"))
proc CommandCheck(filename: string) = proc CommandCheck(filename: string) =
msgs.gErrorMax = high(int) # do not stop after first error
semanticPasses() # use an empty backend for semantic checking only semanticPasses() # use an empty backend for semantic checking only
compileProject(filename) compileProject(filename)

View file

@ -62,7 +62,7 @@ type
errImplOfXexpected, errNoSymbolToBorrowFromFound, errDiscardValue, errImplOfXexpected, errNoSymbolToBorrowFromFound, errDiscardValue,
errInvalidDiscard, errIllegalConvFromXtoY, errCannotBindXTwice, errInvalidDiscard, errIllegalConvFromXtoY, errCannotBindXTwice,
errInvalidOrderInArrayConstructor, errInvalidOrderInArrayConstructor,
errInvalidOrderInEnumX, errEnumXHasWholes, errExceptExpected, errInvalidTry, errInvalidOrderInEnumX, errEnumXHasHoles, errExceptExpected, errInvalidTry,
errOptionExpected, errXisNoLabel, errNotAllCasesCovered, errOptionExpected, errXisNoLabel, errNotAllCasesCovered,
errUnkownSubstitionVar, errComplexStmtRequiresInd, errXisNotCallable, errUnkownSubstitionVar, errComplexStmtRequiresInd, errXisNotCallable,
errNoPragmasAllowedForX, errNoGenericParamsAllowedForX, errNoPragmasAllowedForX, errNoGenericParamsAllowedForX,
@ -96,154 +96,245 @@ type
hintProcessing, hintCodeBegin, hintCodeEnd, hintConf, hintPath, hintUser hintProcessing, hintCodeBegin, hintCodeEnd, hintConf, hintPath, hintUser
const const
MsgKindToStr*: array[TMsgKind, string] = ["unknown error", MsgKindToStr*: array[TMsgKind, string] = [
"illformed AST: $1", "cannot open \'$1\'", "internal error: $1", "$1", errUnknown: "unknown error",
"\'$1\' compiler does not support C++", "string literal expected", errIllFormedAstX: "illformed AST: $1",
"integer literal expected", "invalid character constant", errCannotOpenFile: "cannot open \'$1\'",
"closing \"\"\" expected, but end of file reached", "closing \" expected", errInternal: "internal error: $1",
"tabulators are not allowed", "invalid token: $1", "line too long", errGenerated: "$1",
"$1 is not a valid number", "number $1 out of valid range", errXCompilerDoesNotSupportCpp: "\'$1\' compiler does not support C++",
"\\n not allowed in character literal", errStringLiteralExpected: "string literal expected",
"closing \']\' expected, but end of file reached", "missing final \'", errIntLiteralExpected: "integer literal expected",
"identifier expected, but found \'$1\'", errInvalidCharacterConstant: "invalid character constant",
"operator expected, but found \'$1\'", "\'$1\' expected", errClosingTripleQuoteExpected: "closing \"\"\" expected, but end of file reached",
"string after \'include\' expected", "recursive dependency: \'$1\'", errClosingQuoteExpected: "closing \" expected",
"\'on\' or \'off\' expected", "\'none\', \'speed\' or \'size\' expected", errTabulatorsAreNotAllowed: "tabulators are not allowed",
"invalid pragma", "unknown pragma: \'$1\'", "invalid directive: \'$1\'", errInvalidToken: "invalid token: $1",
"\'pop\' without a \'push\' pragma", "empty asm statement", errLineTooLong: "line too long",
"invalid indentation", "exception expected", "exception already handled", errInvalidNumber: "$1 is not a valid number",
"\'yield\' only allowed in a loop of an iterator", errNumberOutOfRange: "number $1 out of valid range",
"invalid number of \'yield\' expresions", errNnotAllowedInCharacter: "\\n not allowed in character literal",
"current routine cannot return an expression", "attempt to redefine \'$1\'", errClosingBracketExpected: "closing ']' expected, but end of file reached",
"statement not allowed after \'return\', \'break\' or \'raise\'", errMissingFinalQuote: "missing final \'",
"statement expected", "\'$1\' is no label", errIdentifierExpected: "identifier expected, but found \'$1\'",
"invalid command line option: \'$1\'", errOperatorExpected: "operator expected, but found \'$1\'",
"argument for command line option expected: \'$1\'", errTokenExpected: "\'$1\' expected",
"invalid argument for command line option: \'$1\'", errStringAfterIncludeExpected: "string after \'include\' expected",
"invalid variable substitution in \'$1\'", "unknown variable: \'$1\'", errRecursiveDependencyX: "recursive dependency: \'$1\'",
"unknown C compiler: \'$1\'", errOnOrOffExpected: "\'on\' or \'off\' expected",
"\'on\' or \'off\' expected, but \'$1\' found", errNoneSpeedOrSizeExpected: "\'none\', \'speed\' or \'size\' expected",
"\'none\', \'boehm\' or \'refc\' expected, but \'$1\' found", errInvalidPragma: "invalid pragma",
"\'none\', \'speed\' or \'size\' expected, but \'$1\' found", errUnknownPragma: "unknown pragma: \'$1\'",
"\'gui\', \'console\' or \'lib\' expected, but \'$1\' found", errInvalidDirectiveX: "invalid directive: \'$1\'",
"unknown OS: \'$1\'", "unknown CPU: \'$1\'", errAtPopWithoutPush: "\'pop\' without a \'push\' pragma",
"\'c\', \'c++\' or \'yaml\' expected, but \'$1\' found", errEmptyAsm: "empty asm statement",
"arguments can only be given if the \'--run\' option is selected", errInvalidIndentation: "invalid indentation",
"multiple assignment is not allowed", errExceptionExpected: "exception expected",
"\':\' or \'=\' expected, but found \'$1\'", errExceptionAlreadyHandled: "exception already handled",
"expression expected, but found \'$1\'", "undeclared identifier: \'$1\'", errYieldNotAllowedHere: "\'yield\' only allowed in a loop of an iterator",
"ambiguous identifier: \'$1\' -- use a qualifier", "type expected", errInvalidNumberOfYieldExpr: "invalid number of \'yield\' expresions",
"system module needs \'$1\'", "execution of an external program failed", errCannotReturnExpr: "current routine cannot return an expression",
"overloaded \'$1\' leads to ambiguous calls", "invalid argument for \'$1\'", errAttemptToRedefine: "attempt to redefine \'$1\'",
"statement has no effect", "\'$1\' expects a type or value", errStmtInvalidAfterReturn: "statement not allowed after \'return\', \'break\' or \'raise\'",
"\'$1\' expects an array type", errStmtExpected: "statement expected",
"\'$1\' cannot be instantiated because its body has not been compiled yet", errInvalidLabel: "\'$1\' is no label",
"expression \'$1\' ambiguous in this context", "constant division by zero", errInvalidCmdLineOption: "invalid command line option: \'$1\'",
"ordinal type expected", "ordinal or float type expected", errCmdLineArgExpected: "argument for command line option expected: \'$1\'",
"over- or underflow", errCmdLineNoArgExpected: "invalid argument for command line option: \'$1\'",
"cannot evalutate \'$1\' because type is not defined completely", errInvalidVarSubstitution: "invalid variable substitution in \'$1\'",
"\'chr\' expects an int in the range 0..255", errUnknownVar: "unknown variable: \'$1\'",
"\'dynlib\' requires \'exportc\'", "undeclared field: \'$1\'", errUnknownCcompiler: "unknown C compiler: \'$1\'",
"attempt to access a nil address", "index out of bounds", errOnOrOffExpectedButXFound: "\'on\' or \'off\' expected, but \'$1\' found",
"index types do not match", "\'[]\' operator invalid for this type", errNoneBoehmRefcExpectedButXFound: "'none', 'boehm' or 'refc' expected, but '$1' found",
"value out of set bounds", "field initialized twice: \'$1\'", errNoneSpeedOrSizeExpectedButXFound: "'none', 'speed' or 'size' expected, but '$1' found",
"field \'$1\' not initialized", "expression \'$1\' cannot be called", errGuiConsoleOrLibExpectedButXFound: "'gui', 'console' or 'lib' expected, but '$1' found",
"expression has no type", "expression \'$1\' has no type (or is ambiguous)", errUnknownOS: "unknown OS: '$1'",
"\'cast\' not allowed in safe mode", "expression cannot be casted to $1", errUnknownCPU: "unknown CPU: '$1'",
"\',\' or \')\' expected", "\'{\' or \'(\' expected", errGenOutExpectedButXFound: "'c', 'c++' or 'yaml' expected, but '$1' found",
"section (\'type\', \'proc\', etc.) expected", "range expected", errArgsNeedRunOption: "arguments can only be given if the '--run' option is selected",
"attempt to redefine \'$1\'", "\'magic\' only allowed in system module", errInvalidMultipleAsgn: "multiple assignment is not allowed",
"power of two expected", "string literal may not be empty", errColonOrEqualsExpected: "\':\' or \'=\' expected, but found \'$1\'",
"calling convention expected", errExprExpected: "expression expected, but found \'$1\'",
"a proc can only have one calling convention", errUndeclaredIdentifier: "undeclared identifier: \'$1\'",
"symbol must be imported if \'lib\' pragma is used", errUseQualifier: "ambiguous identifier: \'$1\' -- use a qualifier",
"expression must be of type \'bool\'", "constant expression expected", errTypeExpected: "type expected",
"duplicate case label", "range is empty", errSystemNeeds: "system module needs \'$1\'",
"selector must be of an ordinal type, real or string", errExecutionOfProgramFailed: "execution of an external program failed",
"selector must be of an ordinal type", "ord($1) must not be negative", errNotOverloadable: "overloaded \'$1\' leads to ambiguous calls",
"len($1) must be less than 32768", "wrong number of variables", errInvalidArgForX: "invalid argument for \'$1\'",
"only objects can be raised", "\'break\' only allowed in loop construct", errStmtHasNoEffect: "statement has no effect",
"type \'$1\' has unknown size", errXExpectsTypeOrValue: "\'$1\' expects a type or value",
"a constant can only be initialized with a constant expression", errXExpectsArrayType: "\'$1\' expects an array type",
"a constant needs a value", "the result type cannot be on open array", errIteratorCannotBeInstantiated: "'$1' cannot be instantiated because its body has not been compiled yet",
"computing the type\'s size produced an overflow", "set is too large", errExprXAmbiguous: "expression '$1' ambiguous in this context",
"base type of a set must be an ordinal", errConstantDivisionByZero: "constant division by zero",
"inheritance only works with non-final objects", errOrdinalTypeExpected: "ordinal type expected",
"inheritance only works with an enum", "illegal recursion in type \'$1\'", errOrdinalOrFloatTypeExpected: "ordinal or float type expected",
"cannot instantiate: \'$1\'", "expression has no address", errOverOrUnderflow: "over- or underflow",
"for a \'var\' type a variable needs to be passed", "type mismatch", errCannotEvalXBecauseIncompletelyDefined: "cannot evalutate '$1' because type is not defined completely",
"type mismatch: got (", "but expected one of: ", "but expected \'$1\'", errChrExpectsRange0_255: "\'chr\' expects an int in the range 0..255",
"ambiguous call; both $1 and $2 match for: $3", "wrong number of arguments", errDynlibRequiresExportc: "\'dynlib\' requires \'exportc\'",
"\'$1\' cannot be passed to a procvar", errUndeclaredFieldX: "undeclared field: \'$1\'",
"$1 cannot be declared in parameter declaration", errNilAccess: "attempt to access a nil address",
"pragmas are only in the header of a proc allowed", errIndexOutOfBounds: "index out of bounds",
"implementation of \'$1\' is not allowed", errIndexTypesDoNotMatch: "index types do not match",
"implementation of \'$1\' expected", "no symbol to borrow from found", errBracketsInvalidForType: "\'[]\' operator invalid for this type",
"value returned by statement has to be discarded", errValueOutOfSetBounds: "value out of set bounds",
"statement returns no value that can be discarded", errFieldInitTwice: "field initialized twice: \'$1\'",
"conversion from $1 to $2 is invalid", "cannot bind parameter \'$1\' twice", errFieldNotInit: "field \'$1\' not initialized",
"invalid order in array constructor", errExprXCannotBeCalled: "expression \'$1\' cannot be called",
"invalid order in enum \'$1\'", "enum \'$1\' has wholes", errExprHasNoType: "expression has no type",
"\'except\' or \'finally\' expected", errExprXHasNoType: "expression \'$1\' has no type (or is ambiguous)",
"after catch all \'except\' or \'finally\' no section may follow", errCastNotInSafeMode: "\'cast\' not allowed in safe mode",
"option expected, but found \'$1\'", "\'$1\' is not a label", errExprCannotBeCastedToX: "expression cannot be casted to $1",
"not all cases are covered", "unknown substitution variable: \'$1\'", errCommaOrParRiExpected: "',' or ')' expected",
"complex statement requires indentation", "\'$1\' is not callable", errCurlyLeOrParLeExpected: "\'{\' or \'(\' expected",
"no pragmas allowed for $1", "no generic parameters allowed for $1", errSectionExpected: "section (\'type\', \'proc\', etc.) expected",
"invalid param kind: \'$1\'", "default argument invalid", errRangeExpected: "range expected",
"named parameter has to be an identifier", "no return type for $1 allowed", errAttemptToRedefineX: "attempt to redefine \'$1\'",
"a type conversion needs exactly one argument", "invalid pragma: $1", errMagicOnlyInSystem: "\'magic\' only allowed in system module",
"$1 not allowed here", "invalid control flow: $1", "a type has no value", errPowerOfTwoExpected: "power of two expected",
"invalid type: \'$1\'", "\'^\' needs a pointer or reference type", errStringMayNotBeEmpty: "string literal may not be empty",
"invalid expression", "invalid expression: \'$1\'", errCallConvExpected: "calling convention expected",
"enum has no value \'$1\'", "named expression expected", errProcOnlyOneCallConv: "a proc can only have one calling convention",
"named expression not allowed here", "\'$1\' expects one type parameter", errSymbolMustBeImported: "symbol must be imported if 'lib' pragma is used",
"array expects two type parameters", "invalid visibility: \'$1\'", errExprMustBeBool: "expression must be of type 'bool'",
"initialization not allowed here", "\'$1\' cannot be assigned to", errConstExprExpected: "constant expression expected",
"iterators can only be defined at the module\'s top level", errDuplicateCaseLabel: "duplicate case label",
"$1 needs a return type", "invalid command: \'$1\'", errRangeIsEmpty: "range is empty",
"\'$1\' is only allowed at top level", errSelectorMustBeOfCertainTypes: "selector must be of an ordinal type, float or string",
"'$1' needs a parameter that has an object type", errSelectorMustBeOrdinal: "selector must be of an ordinal type",
"template/macro instantiation too nested", "instantiation from here", errOrdXMustNotBeNegative: "ord($1) must not be negative",
"invalid index value for tuple subscript", errLenXinvalid: "len($1) must be less than 32768",
"command expects a filename argument", "\'$1\' expected", errWrongNumberOfVariables: "wrong number of variables",
"invalid section start", "grid table is not implemented", errExprCannotBeRaised: "only objects can be raised",
"general parse error", "new section expected", errBreakOnlyInLoop: "'break' only allowed in loop construct",
"whitespace expected, got \'$1\'", "\'$1\' is no valid index file", errTypeXhasUnknownSize: "type \'$1\' has unknown size",
"cannot render reStructuredText element \'$1\'", errConstNeedsConstExpr: "a constant can only be initialized with a constant expression",
"type \'var var\' is not allowed", "\'is\' expects two arguments", errConstNeedsValue: "a constant needs a value",
"\'is\' expects object types", "\'$1\' can never be of this subtype", errResultCannotBeOpenArray: "the result type cannot be on open array",
"interpretation requires too many iterations", errSizeTooBig: "computing the type\'s size produced an overflow",
"cannot interpret node kind \'$1\'", "field \'$1\' cannot be found", errSetTooBig: "set is too large",
"invalid conversion from type \'$1\'", "assertion failed", errBaseTypeMustBeOrdinal: "base type of a set must be an ordinal",
"cannot generate code for \'$1\'", "$1 requires one parameter", errInheritanceOnlyWithNonFinalObjects: "inheritance only works with non-final objects",
"unhandled exception: $1", "macro returned a cyclic abstract syntax tree", errInheritanceOnlyWithEnums: "inheritance only works with an enum",
"\'$1\' is no macro or template", "\'$1\' can have side effects", errIllegalRecursionInTypeX: "illegal recursion in type \'$1\'",
"iterator within for loop context expected", "$1", errCannotInstantiateX: "cannot instantiate: \'$1\'",
"cannot open \'$1\' [CannotOpenFile]", "octal escape sequences do not exist; leading zero is ignored [OctalEscape]", errExprHasNoAddress: "expression has no address",
"\'$1\' is never read [XIsNeverRead]", errVarForOutParamNeeded: "for a \'var\' type a variable needs to be passed",
"\'$1\' might not have been initialized [XmightNotBeenInit]", errPureTypeMismatch: "type mismatch",
"cannot write file \'$1\' [CannotWriteMO2]", errTypeMismatch: "type mismatch: got (",
"cannot read file \'$1\' [CannotReadMO2]", errButExpected: "but expected one of: ",
"\'$1\' is deprecated [Deprecated]", "\'l\' should not be used as an identifier; may look like \'1\' (one) [SmallLshouldNotBeUsed]", errButExpectedX: "but expected \'$1\'",
"unknown magic \'$1\' might crash the compiler [UnknownMagic]", errAmbiguousCallXYZ: "ambiguous call; both $1 and $2 match for: $3",
"redefinition of label \'$1\' [RedefinitionOfLabel]", errWrongNumberOfArguments: "wrong number of arguments",
"unknown substitution \'$1\' [UnknownSubstitutionX]", errXCannotBePassedToProcVar: "\'$1\' cannot be passed to a procvar",
"language \'$1\' not supported [LanguageXNotSupported]", errXCannotBeInParamDecl: "$1 cannot be declared in parameter declaration",
"comment \'$1\' ignored [CommentXIgnored]", errPragmaOnlyInHeaderOfProc: "pragmas are only in the header of a proc allowed",
"\'$1\' is passed to a procvar; deprecated [XisPassedToProcVar]", errImplOfXNotAllowed: "implementation of \'$1\' is not allowed",
"$1 [User]", "operation successful [Success]", errImplOfXexpected: "implementation of \'$1\' expected",
"operation successful ($1 lines compiled; $2 sec total) [SuccessX]", errNoSymbolToBorrowFromFound: "no symbol to borrow from found",
"line too long [LineTooLong]", errDiscardValue: "value returned by statement has to be discarded",
"\'$1\' is declared but not used [XDeclaredButNotUsed]", errInvalidDiscard: "statement returns no value that can be discarded",
"conversion to base object is not needed [ConvToBaseNotNeeded]", errIllegalConvFromXtoY: "conversion from $1 to $2 is invalid",
"conversion from $1 to itself is pointless [ConvFromXtoItselfNotNeeded]", errCannotBindXTwice: "cannot bind parameter \'$1\' twice",
"expression evaluates always to \'$1\' [ExprAlwaysX]", errInvalidOrderInArrayConstructor: "invalid order in array constructor",
"quit() called [QuitCalled]", "$1 [Processing]", errInvalidOrderInEnumX: "invalid order in enum \'$1\'",
"generated code listing: [CodeBegin]", "end of listing [CodeEnd]", errEnumXHasHoles: "enum \'$1\' has holes",
"used config file \'$1\' [Conf]", errExceptExpected: "\'except\' or \'finally\' expected",
"added path: '$1' [Path]", errInvalidTry: "after catch all \'except\' or \'finally\' no section may follow",
"$1 [User]"] errOptionExpected: "option expected, but found \'$1\'",
errXisNoLabel: "\'$1\' is not a label",
errNotAllCasesCovered: "not all cases are covered",
errUnkownSubstitionVar: "unknown substitution variable: \'$1\'",
errComplexStmtRequiresInd: "complex statement requires indentation",
errXisNotCallable: "\'$1\' is not callable",
errNoPragmasAllowedForX: "no pragmas allowed for $1",
errNoGenericParamsAllowedForX: "no generic parameters allowed for $1",
errInvalidParamKindX: "invalid param kind: \'$1\'",
errDefaultArgumentInvalid: "default argument invalid",
errNamedParamHasToBeIdent: "named parameter has to be an identifier",
errNoReturnTypeForX: "no return type for $1 allowed",
errConvNeedsOneArg: "a type conversion needs exactly one argument",
errInvalidPragmaX: "invalid pragma: $1",
errXNotAllowedHere: "$1 not allowed here",
errInvalidControlFlowX: "invalid control flow: $1",
errATypeHasNoValue: "a type has no value",
errXisNoType: "invalid type: \'$1\'",
errCircumNeedsPointer: "\'^\' needs a pointer or reference type",
errInvalidExpression: "invalid expression",
errInvalidExpressionX: "invalid expression: \'$1\'",
errEnumHasNoValueX: "enum has no value \'$1\'",
errNamedExprExpected: "named expression expected",
errNamedExprNotAllowed: "named expression not allowed here",
errXExpectsOneTypeParam: "\'$1\' expects one type parameter",
errArrayExpectsTwoTypeParams: "array expects two type parameters",
errInvalidVisibilityX: "invalid visibility: \'$1\'",
errInitHereNotAllowed: "initialization not allowed here",
errXCannotBeAssignedTo: "\'$1\' cannot be assigned to",
errIteratorNotAllowed: "iterators can only be defined at the module\'s top level",
errXNeedsReturnType: "$1 needs a return type",
errInvalidCommandX: "invalid command: \'$1\'",
errXOnlyAtModuleScope: "\'$1\' is only allowed at top level",
errXNeedsParamObjectType: "'$1' needs a parameter that has an object type",
errTemplateInstantiationTooNested: "template/macro instantiation too nested",
errInstantiationFrom: "instantiation from here",
errInvalidIndexValueForTuple: "invalid index value for tuple subscript",
errCommandExpectsFilename: "command expects a filename argument",
errXExpected: "\'$1\' expected",
errInvalidSectionStart: "invalid section start",
errGridTableNotImplemented: "grid table is not implemented",
errGeneralParseError: "general parse error",
errNewSectionExpected: "new section expected",
errWhitespaceExpected: "whitespace expected, got \'$1\'",
errXisNoValidIndexFile: "\'$1\' is no valid index file",
errCannotRenderX: "cannot render reStructuredText element \'$1\'",
errVarVarTypeNotAllowed: "type \'var var\' is not allowed",
errIsExpectsTwoArguments: "\'is\' expects two arguments",
errIsExpectsObjectTypes: "\'is\' expects object types",
errXcanNeverBeOfThisSubtype: "\'$1\' can never be of this subtype",
errTooManyIterations: "interpretation requires too many iterations",
errCannotInterpretNodeX: "cannot interpret node kind \'$1\'",
errFieldXNotFound: "field \'$1\' cannot be found",
errInvalidConversionFromTypeX: "invalid conversion from type \'$1\'",
errAssertionFailed: "assertion failed",
errCannotGenerateCodeForX: "cannot generate code for \'$1\'",
errXRequiresOneArgument: "$1 requires one parameter",
errUnhandledExceptionX: "unhandled exception: $1",
errCyclicTree: "macro returned a cyclic abstract syntax tree",
errXisNoMacroOrTemplate: "\'$1\' is no macro or template",
errXhasSideEffects: "\'$1\' can have side effects",
errIteratorExpected: "iterator within for loop context expected",
errUser: "$1",
warnCannotOpenFile: "cannot open \'$1\' [CannotOpenFile]",
warnOctalEscape: "octal escape sequences do not exist; leading zero is ignored [OctalEscape]",
warnXIsNeverRead: "\'$1\' is never read [XIsNeverRead]",
warnXmightNotBeenInit: "\'$1\' might not have been initialized [XmightNotBeenInit]",
warnCannotWriteMO2: "cannot write file \'$1\' [CannotWriteMO2]",
warnCannotReadMO2: "cannot read file \'$1\' [CannotReadMO2]",
warnDeprecated: "\'$1\' is deprecated [Deprecated]",
warnSmallLshouldNotBeUsed: "\'l\' should not be used as an identifier; may look like \'1\' (one) [SmallLshouldNotBeUsed]",
warnUnknownMagic: "unknown magic \'$1\' might crash the compiler [UnknownMagic]",
warnRedefinitionOfLabel: "redefinition of label \'$1\' [RedefinitionOfLabel]",
warnUnknownSubstitutionX: "unknown substitution \'$1\' [UnknownSubstitutionX]",
warnLanguageXNotSupported: "language \'$1\' not supported [LanguageXNotSupported]",
warnCommentXIgnored: "comment \'$1\' ignored [CommentXIgnored]",
warnXisPassedToProcVar: "\'$1\' is passed to a procvar; deprecated [XisPassedToProcVar]",
warnUser: "$1 [User]",
hintSuccess: "operation successful [Success]",
hintSuccessX: "operation successful ($1 lines compiled; $2 sec total) [SuccessX]",
hintLineTooLong: "line too long [LineTooLong]",
hintXDeclaredButNotUsed: "\'$1\' is declared but not used [XDeclaredButNotUsed]",
hintConvToBaseNotNeeded: "conversion to base object is not needed [ConvToBaseNotNeeded]",
hintConvFromXtoItselfNotNeeded: "conversion from $1 to itself is pointless [ConvFromXtoItselfNotNeeded]",
hintExprAlwaysX: "expression evaluates always to \'$1\' [ExprAlwaysX]",
hintQuitCalled: "quit() called [QuitCalled]",
hintProcessing: "$1 [Processing]",
hintCodeBegin: "generated code listing: [CodeBegin]",
hintCodeEnd: "end of listing [CodeEnd]",
hintConf: "used config file \'$1\' [Conf]",
hintPath: "added path: '$1' [Path]",
hintUser: "$1 [User]"]
const const
WarningsToStr*: array[0..14, string] = ["CannotOpenFile", "OctalEscape", WarningsToStr*: array[0..14, string] = ["CannotOpenFile", "OctalEscape",
@ -353,7 +444,7 @@ proc checkpoint(info: TLineInfo, filename: string, line: int): bool =
(ChangeFileExt(extractFilename(filenames[info.fileIndex]), "") == (ChangeFileExt(extractFilename(filenames[info.fileIndex]), "") ==
filename) filename)
var checkPoints: seq[TLineInfo] = @ [] var checkPoints: seq[TLineInfo] = @[]
proc addCheckpoint(info: TLineInfo) = proc addCheckpoint(info: TLineInfo) =
var length: int var length: int

View file

@ -141,7 +141,7 @@ proc parseTypeDesc(p: var TParser, definition: PNode = nil): PNode
proc parseEmit(p: var TParser, definition: PNode): PNode = proc parseEmit(p: var TParser, definition: PNode): PNode =
getTok(p) # skip 'emit' getTok(p) # skip 'emit'
result = nil result = ast.emptyNode
if p.tok.xkind != pxCurlyDirRi: if p.tok.xkind != pxCurlyDirRi:
case p.context case p.context
of conExpr: of conExpr:
@ -159,7 +159,7 @@ proc parseEmit(p: var TParser, definition: PNode): PNode =
eat(p, pxCurlyDirRi) eat(p, pxCurlyDirRi)
proc parseCommand(p: var TParser, definition: PNode = nil): PNode = proc parseCommand(p: var TParser, definition: PNode = nil): PNode =
result = nil result = ast.emptyNode
getTok(p) getTok(p)
if p.tok.ident.id == getIdent("discard").id: if p.tok.ident.id == getIdent("discard").id:
result = newNodeP(nkDiscardStmt, p) result = newNodeP(nkDiscardStmt, p)
@ -170,8 +170,8 @@ proc parseCommand(p: var TParser, definition: PNode = nil): PNode =
getTok(p) getTok(p)
eat(p, pxCurlyDirRi) eat(p, pxCurlyDirRi)
result = parseExpr(p) result = parseExpr(p)
if result.kind == nkEmpty: InternalError("emptyNode modified")
result.kind = nkCurly result.kind = nkCurly
assert(sonsNotNil(result))
elif p.tok.ident.id == getIdent("cast").id: elif p.tok.ident.id == getIdent("cast").id:
getTok(p) getTok(p)
eat(p, pxCurlyDirRi) eat(p, pxCurlyDirRi)
@ -181,7 +181,7 @@ proc parseCommand(p: var TParser, definition: PNode = nil): PNode =
addSon(result, a.sons[0]) addSon(result, a.sons[0])
addSon(result, a.sons[1]) addSon(result, a.sons[1])
else: else:
parMessage(p, errInvalidDirectiveX, $(p.tok)) parMessage(p, errInvalidDirectiveX, $p.tok)
result = a result = a
elif p.tok.ident.id == getIdent("emit").id: elif p.tok.ident.id == getIdent("emit").id:
result = parseEmit(p, definition) result = parseEmit(p, definition)
@ -216,12 +216,12 @@ proc parseCommand(p: var TParser, definition: PNode = nil): PNode =
getTok(p) getTok(p)
eat(p, pxCurlyDirRi) eat(p, pxCurlyDirRi)
else: else:
parMessage(p, errInvalidDirectiveX, $(p.tok)) parMessage(p, errInvalidDirectiveX, $p.tok)
while true: while true:
getTok(p) getTok(p)
if (p.tok.xkind == pxCurlyDirRi) or (p.tok.xkind == pxEof): break if p.tok.xkind == pxCurlyDirRi or p.tok.xkind == pxEof: break
eat(p, pxCurlyDirRi) eat(p, pxCurlyDirRi)
result = nil result = ast.emptyNode
proc getPrecedence(kind: TTokKind): int = proc getPrecedence(kind: TTokKind): int =
case kind case kind
@ -295,7 +295,7 @@ proc qualifiedIdent(p: var TParser): PNode =
result = createIdentNodeP(p.tok.ident, p) result = createIdentNodeP(p.tok.ident, p)
else: else:
parMessage(p, errIdentifierExpected, $p.tok) parMessage(p, errIdentifierExpected, $p.tok)
return nil return ast.emptyNode
getTok(p) getTok(p)
skipCom(p, result) skipCom(p, result)
if p.tok.xkind == pxDot: if p.tok.xkind == pxDot:
@ -390,15 +390,15 @@ proc identOrLiteral(p: var TParser): PNode =
else: else:
parMessage(p, errExprExpected, $(p.tok)) parMessage(p, errExprExpected, $(p.tok))
getTok(p) # we must consume a token here to prevend endless loops! getTok(p) # we must consume a token here to prevend endless loops!
result = nil result = ast.emptyNode
if result != nil: skipCom(p, result) if result.kind != nkEmpty: skipCom(p, result)
proc primary(p: var TParser): PNode = proc primary(p: var TParser): PNode =
# prefix operator? # prefix operator?
if (p.tok.xkind == pxNot) or (p.tok.xkind == pxMinus) or if (p.tok.xkind == pxNot) or (p.tok.xkind == pxMinus) or
(p.tok.xkind == pxPlus): (p.tok.xkind == pxPlus):
result = newNodeP(nkPrefix, p) result = newNodeP(nkPrefix, p)
var a = newIdentNodeP(getIdent($(p.tok)), p) var a = newIdentNodeP(getIdent($p.tok), p)
addSon(result, a) addSon(result, a)
getTok(p) getTok(p)
skipCom(p, a) skipCom(p, a)
@ -406,7 +406,7 @@ proc primary(p: var TParser): PNode =
return return
elif p.tok.xkind == pxAt: elif p.tok.xkind == pxAt:
result = newNodeP(nkAddr, p) result = newNodeP(nkAddr, p)
var a = newIdentNodeP(getIdent($(p.tok)), p) var a = newIdentNodeP(getIdent($p.tok), p)
getTok(p) getTok(p)
if p.tok.xkind == pxBracketLe: if p.tok.xkind == pxBracketLe:
result = newNodeP(nkPrefix, p) result = newNodeP(nkPrefix, p)
@ -433,7 +433,7 @@ proc primary(p: var TParser): PNode =
addSon(result, createIdentNodeP(p.tok.ident, p)) addSon(result, createIdentNodeP(p.tok.ident, p))
getTok(p) getTok(p)
else: else:
parMessage(p, errIdentifierExpected, $(p.tok)) parMessage(p, errIdentifierExpected, $p.tok)
of pxHat: of pxHat:
var a = result var a = result
result = newNodeP(nkDerefExpr, p) result = newNodeP(nkDerefExpr, p)
@ -490,7 +490,6 @@ proc lowestExprAux(p: var TParser, v: var PNode, limit: int): TTokKind =
proc fixExpr(n: PNode): PNode = proc fixExpr(n: PNode): PNode =
result = n result = n
if n == nil: return
case n.kind case n.kind
of nkInfix: of nkInfix:
if n.sons[1].kind == nkBracket: n.sons[1].kind = nkCurly if n.sons[1].kind == nkBracket: n.sons[1].kind = nkCurly
@ -559,7 +558,7 @@ proc parseUsesStmt(p: var TParser): PNode =
skipCom(p, a) skipCom(p, a)
else: else:
break break
if sonsLen(result) == 0: result = nil if sonsLen(result) == 0: result = ast.emptyNode
proc parseIncludeDir(p: var TParser): PNode = proc parseIncludeDir(p: var TParser): PNode =
result = newNodeP(nkIncludeStmt, p) result = newNodeP(nkIncludeStmt, p)
@ -568,7 +567,7 @@ proc parseIncludeDir(p: var TParser): PNode =
while true: while true:
case p.tok.xkind case p.tok.xkind
of pxSymbol, pxDot, pxDotDot, pxSlash: of pxSymbol, pxDot, pxDotDot, pxSlash:
filename = filename & $(p.tok) add(filename, $p.tok)
getTok(p) getTok(p)
of pxStrLit: of pxStrLit:
filename = p.tok.literal filename = p.tok.literal
@ -577,10 +576,10 @@ proc parseIncludeDir(p: var TParser): PNode =
of pxCurlyDirRi: of pxCurlyDirRi:
break break
else: else:
parMessage(p, errIdentifierExpected, $(p.tok)) parMessage(p, errIdentifierExpected, $p.tok)
break break
addSon(result, newStrNodeP(nkStrLit, changeFileExt(filename, "nim"), p)) addSon(result, newStrNodeP(nkStrLit, changeFileExt(filename, "nim"), p))
if filename == "config.inc": result = nil if filename == "config.inc": result = ast.emptyNode
proc definedExprAux(p: var TParser): PNode = proc definedExprAux(p: var TParser): PNode =
result = newNodeP(nkCall, p) result = newNodeP(nkCall, p)
@ -590,7 +589,6 @@ proc definedExprAux(p: var TParser): PNode =
getTok(p) getTok(p)
proc isHandledDirective(p: TParser): bool = proc isHandledDirective(p: TParser): bool =
result = false
if p.tok.xkind in {pxCurlyDirLe, pxStarDirLe}: if p.tok.xkind in {pxCurlyDirLe, pxStarDirLe}:
case toLower(p.tok.ident.s) case toLower(p.tok.ident.s)
of "else", "endif": result = false of "else", "endif": result = false
@ -657,7 +655,7 @@ proc parseIfDir(p: var TParser, endMarker: TTokKind): PNode =
parseIfDirAux(p, result) parseIfDirAux(p, result)
proc parseDirective(p: var TParser): PNode = proc parseDirective(p: var TParser): PNode =
result = nil result = ast.emptyNode
if not (p.tok.xkind in {pxCurlyDirLe, pxStarDirLe}): return if not (p.tok.xkind in {pxCurlyDirLe, pxStarDirLe}): return
var endMarker = succ(p.tok.xkind) var endMarker = succ(p.tok.xkind)
if p.tok.ident != nil: if p.tok.ident != nil:
@ -680,7 +678,7 @@ proc parseRaise(p: var TParser): PNode =
getTok(p) getTok(p)
skipCom(p, result) skipCom(p, result)
if p.tok.xkind != pxSemicolon: addSon(result, parseExpr(p)) if p.tok.xkind != pxSemicolon: addSon(result, parseExpr(p))
else: addSon(result, nil) else: addSon(result, ast.emptyNode)
proc parseIf(p: var TParser): PNode = proc parseIf(p: var TParser): PNode =
result = newNodeP(nkIfStmt, p) result = newNodeP(nkIfStmt, p)
@ -721,14 +719,14 @@ proc parseRepeat(p: var TParser): PNode =
skipCom(p, result) skipCom(p, result)
addSon(result, newIdentNodeP(getIdent("true"), p)) addSon(result, newIdentNodeP(getIdent("true"), p))
var s = newNodeP(nkStmtList, p) var s = newNodeP(nkStmtList, p)
while (p.tok.xkind != pxEof) and (p.tok.xkind != pxUntil): while p.tok.xkind != pxEof and p.tok.xkind != pxUntil:
addSon(s, parseStmt(p)) addSon(s, parseStmt(p))
eat(p, pxUntil) eat(p, pxUntil)
var a = newNodeP(nkIfStmt, p) var a = newNodeP(nkIfStmt, p)
skipCom(p, a) skipCom(p, a)
var b = newNodeP(nkElifBranch, p) var b = newNodeP(nkElifBranch, p)
var c = newNodeP(nkBreakStmt, p) var c = newNodeP(nkBreakStmt, p)
addSon(c, nil) addSon(c, ast.emptyNode)
addSon(b, parseExpr(p)) addSon(b, parseExpr(p))
skipCom(p, a) skipCom(p, a)
addSon(b, c) addSon(b, c)
@ -809,7 +807,7 @@ proc parseFor(p: var TParser): PNode =
getTok(p) getTok(p)
eat(p, pxAsgn) eat(p, pxAsgn)
var a = parseExpr(p) var a = parseExpr(p)
var b: PNode = nil var b = ast.emptyNode
var c = newNodeP(nkCall, p) var c = newNodeP(nkCall, p)
if p.tok.xkind == pxTo: if p.tok.xkind == pxTo:
addSon(c, newIdentNodeP(getIdent("countup"), p)) addSon(c, newIdentNodeP(getIdent("countup"), p))
@ -829,9 +827,9 @@ proc parseFor(p: var TParser): PNode =
addSon(result, parseStmt(p)) addSon(result, parseStmt(p))
proc parseParam(p: var TParser): PNode = proc parseParam(p: var TParser): PNode =
var a, v: PNode var a: PNode
result = newNodeP(nkIdentDefs, p) result = newNodeP(nkIdentDefs, p)
v = nil var v = ast.emptyNode
case p.tok.xkind case p.tok.xkind
of pxConst: of pxConst:
getTok(p) getTok(p)
@ -848,7 +846,7 @@ proc parseParam(p: var TParser): PNode =
of pxSymbol: a = createIdentNodeP(p.tok.ident, p) of pxSymbol: a = createIdentNodeP(p.tok.ident, p)
of pxColon, pxEof, pxParRi, pxEquals: break of pxColon, pxEof, pxParRi, pxEquals: break
else: else:
parMessage(p, errIdentifierExpected, $(p.tok)) parMessage(p, errIdentifierExpected, $p.tok)
return return
getTok(p) # skip identifier getTok(p) # skip identifier
skipCom(p, a) skipCom(p, a)
@ -859,24 +857,24 @@ proc parseParam(p: var TParser): PNode =
if p.tok.xkind == pxColon: if p.tok.xkind == pxColon:
getTok(p) getTok(p)
skipCom(p, result) skipCom(p, result)
if v != nil: addSon(v, parseTypeDesc(p)) if v.kind != nkEmpty: addSon(v, parseTypeDesc(p))
else: v = parseTypeDesc(p) else: v = parseTypeDesc(p)
addSon(result, v) addSon(result, v)
else: else:
addSon(result, nil) addSon(result, ast.emptyNode)
if p.tok.xkind != pxEquals: if p.tok.xkind != pxEquals:
parMessage(p, errColonOrEqualsExpected, $(p.tok)) parMessage(p, errColonOrEqualsExpected, $p.tok)
if p.tok.xkind == pxEquals: if p.tok.xkind == pxEquals:
getTok(p) getTok(p)
skipCom(p, result) skipCom(p, result)
addSon(result, parseExpr(p)) addSon(result, parseExpr(p))
else: else:
addSon(result, nil) addSon(result, ast.emptyNode)
proc parseParamList(p: var TParser): PNode = proc parseParamList(p: var TParser): PNode =
var a: PNode var a: PNode
result = newNodeP(nkFormalParams, p) result = newNodeP(nkFormalParams, p)
addSon(result, nil) # return type addSon(result, ast.emptyNode) # return type
if p.tok.xkind == pxParLe: if p.tok.xkind == pxParLe:
p.inParamList = true p.inParamList = true
getTok(p) getTok(p)
@ -903,7 +901,7 @@ proc parseParamList(p: var TParser): PNode =
result.sons[0] = parseTypeDesc(p) result.sons[0] = parseTypeDesc(p)
proc parseCallingConvention(p: var TParser): PNode = proc parseCallingConvention(p: var TParser): PNode =
result = nil result = ast.emptyNode
if p.tok.xkind == pxSymbol: if p.tok.xkind == pxSymbol:
case toLower(p.tok.ident.s) case toLower(p.tok.ident.s)
of "stdcall", "cdecl", "safecall", "syscall", "inline", "fastcall": of "stdcall", "cdecl", "safecall", "syscall", "inline", "fastcall":
@ -935,7 +933,7 @@ proc parseRoutineSpecifiers(p: var TParser, noBody: var bool): PNode =
of "importc": of "importc":
# This is a fake for platform module. There is no ``importc`` # This is a fake for platform module. There is no ``importc``
# directive in Pascal. # directive in Pascal.
if result == nil: result = newNodeP(nkPragma, p) if result.kind == nkEmpty: result = newNodeP(nkPragma, p)
addSon(result, newIdentNodeP(getIdent("importc"), p)) addSon(result, newIdentNodeP(getIdent("importc"), p))
noBody = true noBody = true
getTok(p) getTok(p)
@ -943,7 +941,7 @@ proc parseRoutineSpecifiers(p: var TParser, noBody: var bool): PNode =
of "noconv": of "noconv":
# This is a fake for platform module. There is no ``noconv`` # This is a fake for platform module. There is no ``noconv``
# directive in Pascal. # directive in Pascal.
if result == nil: result = newNodeP(nkPragma, p) if result.kind == nkEmpty: result = newNodeP(nkPragma, p)
addSon(result, newIdentNodeP(getIdent("noconv"), p)) addSon(result, newIdentNodeP(getIdent("noconv"), p))
noBody = true noBody = true
getTok(p) getTok(p)
@ -951,17 +949,17 @@ proc parseRoutineSpecifiers(p: var TParser, noBody: var bool): PNode =
of "procvar": of "procvar":
# This is a fake for the Nimrod compiler. There is no ``procvar`` # This is a fake for the Nimrod compiler. There is no ``procvar``
# directive in Pascal. # directive in Pascal.
if result == nil: result = newNodeP(nkPragma, p) if result.kind == nkEmpty: result = newNodeP(nkPragma, p)
addSon(result, newIdentNodeP(getIdent("procvar"), p)) addSon(result, newIdentNodeP(getIdent("procvar"), p))
getTok(p) getTok(p)
opt(p, pxSemicolon) opt(p, pxSemicolon)
of "varargs": of "varargs":
if result == nil: result = newNodeP(nkPragma, p) if result.kind == nkEmpty: result = newNodeP(nkPragma, p)
addSon(result, newIdentNodeP(getIdent("varargs"), p)) addSon(result, newIdentNodeP(getIdent("varargs"), p))
getTok(p) getTok(p)
opt(p, pxSemicolon) opt(p, pxSemicolon)
of "external": of "external":
if result == nil: result = newNodeP(nkPragma, p) if result.kind == nkEmpty: result = newNodeP(nkPragma, p)
getTok(p) getTok(p)
noBody = true noBody = true
e = newNodeP(nkExprColonExpr, p) e = newNodeP(nkExprColonExpr, p)
@ -981,8 +979,8 @@ proc parseRoutineSpecifiers(p: var TParser, noBody: var bool): PNode =
opt(p, pxSemicolon) opt(p, pxSemicolon)
else: else:
e = parseCallingConvention(p) e = parseCallingConvention(p)
if e == nil: break if e.kind == nkEmpty: break
if result == nil: result = newNodeP(nkPragma, p) if result.kind == nkEmpty: result = newNodeP(nkPragma, p)
addSon(result, e.sons[0]) addSon(result, e.sons[0])
proc parseRoutineType(p: var TParser): PNode = proc parseRoutineType(p: var TParser): PNode =
@ -999,7 +997,7 @@ proc parseEnum(p: var TParser): PNode =
result = newNodeP(nkEnumTy, p) result = newNodeP(nkEnumTy, p)
getTok(p) getTok(p)
skipCom(p, result) skipCom(p, result)
addSon(result, nil) # it does not inherit from any enumeration addSon(result, ast.emptyNode) # it does not inherit from any enumeration
while true: while true:
case p.tok.xkind case p.tok.xkind
of pxEof, pxParRi: break of pxEof, pxParRi: break
@ -1061,7 +1059,7 @@ proc parseIdentColonEquals(p: var TParser,
skipCom(p, result) skipCom(p, result)
addSon(result, parseTypeDesc(p)) addSon(result, parseTypeDesc(p))
else: else:
addSon(result, nil) addSon(result, ast.emptyNode)
if p.tok.xkind != pxEquals: if p.tok.xkind != pxEquals:
parMessage(p, errColonOrEqualsExpected, $(p.tok)) parMessage(p, errColonOrEqualsExpected, $(p.tok))
if p.tok.xkind == pxEquals: if p.tok.xkind == pxEquals:
@ -1069,20 +1067,20 @@ proc parseIdentColonEquals(p: var TParser,
skipCom(p, result) skipCom(p, result)
addSon(result, parseExpr(p)) addSon(result, parseExpr(p))
else: else:
addSon(result, nil) addSon(result, ast.emptyNode)
if p.tok.xkind == pxSemicolon: if p.tok.xkind == pxSemicolon:
getTok(p) getTok(p)
skipCom(p, result) skipCom(p, result)
proc parseRecordCase(p: var TParser): PNode = proc parseRecordCase(p: var TParser): PNode =
var a, b, c: PNode var b, c: PNode
result = newNodeP(nkRecCase, p) result = newNodeP(nkRecCase, p)
getTok(p) getTok(p)
a = newNodeP(nkIdentDefs, p) var a = newNodeP(nkIdentDefs, p)
addSon(a, rawIdent(p)) addSon(a, rawIdent(p))
eat(p, pxColon) eat(p, pxColon)
addSon(a, parseTypeDesc(p)) addSon(a, parseTypeDesc(p))
addSon(a, nil) addSon(a, ast.emptyNode)
addSon(result, a) addSon(result, a)
eat(p, pxOf) eat(p, pxOf)
skipCom(p, result) skipCom(p, result)
@ -1116,9 +1114,9 @@ proc parseRecordCase(p: var TParser): PNode =
if b.kind == nkElse: break if b.kind == nkElse: break
proc parseRecordPart(p: var TParser): PNode = proc parseRecordPart(p: var TParser): PNode =
result = nil result = ast.emptyNode
while (p.tok.xkind != pxEof) and (p.tok.xkind != pxEnd): while (p.tok.xkind != pxEof) and (p.tok.xkind != pxEnd):
if result == nil: result = newNodeP(nkRecList, p) if result.kind == nkEmpty: result = newNodeP(nkRecList, p)
case p.tok.xkind case p.tok.xkind
of pxSymbol: of pxSymbol:
addSon(result, parseIdentColonEquals(p, rawIdent)) addSon(result, parseIdentColonEquals(p, rawIdent))
@ -1129,7 +1127,7 @@ proc parseRecordPart(p: var TParser): PNode =
of pxComment: of pxComment:
skipCom(p, lastSon(result)) skipCom(p, lastSon(result))
else: else:
parMessage(p, errIdentifierExpected, $(p.tok)) parMessage(p, errIdentifierExpected, $p.tok)
break break
proc exSymbol(n: var PNode) = proc exSymbol(n: var PNode) =
@ -1146,7 +1144,6 @@ proc exSymbol(n: var PNode) =
else: internalError(n.info, "exSymbol(): " & $n.kind) else: internalError(n.info, "exSymbol(): " & $n.kind)
proc fixRecordDef(n: var PNode) = proc fixRecordDef(n: var PNode) =
if n == nil: return
case n.kind case n.kind
of nkRecCase: of nkRecCase:
fixRecordDef(n.sons[0]) fixRecordDef(n.sons[0])
@ -1157,7 +1154,7 @@ proc fixRecordDef(n: var PNode) =
for i in countup(0, sonsLen(n) - 1): fixRecordDef(n.sons[i]) for i in countup(0, sonsLen(n) - 1): fixRecordDef(n.sons[i])
of nkIdentDefs: of nkIdentDefs:
for i in countup(0, sonsLen(n) - 3): exSymbol(n.sons[i]) for i in countup(0, sonsLen(n) - 3): exSymbol(n.sons[i])
of nkNilLit: nil of nkNilLit, nkEmpty: nil
else: internalError(n.info, "fixRecordDef(): " & $n.kind) else: internalError(n.info, "fixRecordDef(): " & $n.kind)
proc addPragmaToIdent(ident: var PNode, pragma: PNode) = proc addPragmaToIdent(ident: var PNode, pragma: PNode) =
@ -1202,7 +1199,7 @@ proc parseRecordOrObject(p: var TParser, kind: TNodeKind,
definition: PNode): PNode = definition: PNode): PNode =
result = newNodeP(kind, p) result = newNodeP(kind, p)
getTok(p) getTok(p)
addSon(result, nil) addSon(result, ast.emptyNode)
if p.tok.xkind == pxParLe: if p.tok.xkind == pxParLe:
var a = newNodeP(nkOfInherit, p) var a = newNodeP(nkOfInherit, p)
getTok(p) getTok(p)
@ -1210,7 +1207,7 @@ proc parseRecordOrObject(p: var TParser, kind: TNodeKind,
addSon(result, a) addSon(result, a)
eat(p, pxParRi) eat(p, pxParRi)
else: else:
addSon(result, nil) addSon(result, ast.emptyNode)
parseRecordBody(p, result, definition) parseRecordBody(p, result, definition)
proc parseTypeDesc(p: var TParser, definition: PNode = nil): PNode = proc parseTypeDesc(p: var TParser, definition: PNode = nil): PNode =
@ -1234,8 +1231,8 @@ proc parseTypeDesc(p: var TParser, definition: PNode = nil): PNode =
else: addSon(result, a.sons[i]) else: addSon(result, a.sons[i])
else: else:
result = newNodeP(nkObjectTy, p) result = newNodeP(nkObjectTy, p)
addSon(result, nil) addSon(result, ast.emptyNode)
addSon(result, nil) addSon(result, ast.emptyNode)
parseRecordBody(p, result, definition) parseRecordBody(p, result, definition)
if definition != nil: if definition != nil:
addPragmaToIdent(definition.sons[0], newIdentNodeP(getIdent("final"), p)) addPragmaToIdent(definition.sons[0], newIdentNodeP(getIdent("final"), p))
@ -1288,13 +1285,13 @@ proc parseTypeDesc(p: var TParser, definition: PNode = nil): PNode =
proc parseTypeDef(p: var TParser): PNode = proc parseTypeDef(p: var TParser): PNode =
result = newNodeP(nkTypeDef, p) result = newNodeP(nkTypeDef, p)
addSon(result, identVis(p)) addSon(result, identVis(p))
addSon(result, nil) # generic params addSon(result, ast.emptyNode) # generic params
if p.tok.xkind == pxEquals: if p.tok.xkind == pxEquals:
getTok(p) getTok(p)
skipCom(p, result) skipCom(p, result)
addSon(result, parseTypeDesc(p, result)) addSon(result, parseTypeDesc(p, result))
else: else:
addSon(result, nil) addSon(result, ast.emptyNode)
if p.tok.xkind == pxSemicolon: if p.tok.xkind == pxSemicolon:
getTok(p) getTok(p)
skipCom(p, result) skipCom(p, result)
@ -1314,7 +1311,7 @@ proc parseConstant(p: var TParser): PNode =
skipCom(p, result) skipCom(p, result)
addSon(result, parseTypeDesc(p)) addSon(result, parseTypeDesc(p))
else: else:
addSon(result, nil) addSon(result, ast.emptyNode)
if p.tok.xkind != pxEquals: if p.tok.xkind != pxEquals:
parMessage(p, errColonOrEqualsExpected, $(p.tok)) parMessage(p, errColonOrEqualsExpected, $(p.tok))
if p.tok.xkind == pxEquals: if p.tok.xkind == pxEquals:
@ -1322,7 +1319,7 @@ proc parseConstant(p: var TParser): PNode =
skipCom(p, result) skipCom(p, result)
addSon(result, parseExpr(p)) addSon(result, parseExpr(p))
else: else:
addSon(result, nil) addSon(result, ast.emptyNode)
if p.tok.xkind == pxSemicolon: if p.tok.xkind == pxSemicolon:
getTok(p) getTok(p)
skipCom(p, result) skipCom(p, result)
@ -1349,12 +1346,12 @@ proc parseRoutine(p: var TParser): PNode =
skipCom(p, result) skipCom(p, result)
expectIdent(p) expectIdent(p)
addSon(result, identVis(p)) addSon(result, identVis(p))
addSon(result, nil) # generic parameters addSon(result, ast.emptyNode) # generic parameters
addSon(result, parseParamList(p)) addSon(result, parseParamList(p))
opt(p, pxSemicolon) opt(p, pxSemicolon)
addSon(result, parseRoutineSpecifiers(p, noBody)) addSon(result, parseRoutineSpecifiers(p, noBody))
if (p.section == seInterface) or noBody: if (p.section == seInterface) or noBody:
addSon(result, nil) addSon(result, ast.emptyNode)
else: else:
var stmts = newNodeP(nkStmtList, p) var stmts = newNodeP(nkStmtList, p)
while true: while true:
@ -1408,8 +1405,7 @@ proc exSymbols(n: PNode) =
of nkTypeSection: of nkTypeSection:
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):
exSymbol(n.sons[i].sons[0]) exSymbol(n.sons[i].sons[0])
if (n.sons[i].sons[2] != nil) and if n.sons[i].sons[2].kind == nkObjectTy:
(n.sons[i].sons[2].kind == nkObjectTy):
fixRecordDef(n.sons[i].sons[2]) fixRecordDef(n.sons[i].sons[2])
else: nil else: nil
@ -1425,13 +1421,15 @@ proc parseBegin(p: var TParser, result: PNode) =
break break
of pxSemicolon: getTok(p) of pxSemicolon: getTok(p)
of pxEof: parMessage(p, errExprExpected) of pxEof: parMessage(p, errExprExpected)
else: addSonIfNotNil(result, parseStmt(p)) else:
var a = parseStmt(p)
if a.kind != nkEmpty: addSon(result, a)
if sonsLen(result) == 0: addSon(result, newNodeP(nkNilLit, p)) if sonsLen(result) == 0: addSon(result, newNodeP(nkNilLit, p))
proc parseStmt(p: var TParser): PNode = proc parseStmt(p: var TParser): PNode =
var oldcontext = p.context var oldcontext = p.context
p.context = conStmt p.context = conStmt
result = nil result = ast.emptyNode
case p.tok.xkind case p.tok.xkind
of pxBegin: of pxBegin:
result = newNodeP(nkStmtList, p) result = newNodeP(nkStmtList, p)
@ -1475,23 +1473,23 @@ proc parseStmt(p: var TParser): PNode =
result = newNodeP(nkBreakStmt, p) result = newNodeP(nkBreakStmt, p)
getTok(p) getTok(p)
skipCom(p, result) skipCom(p, result)
addSon(result, nil) addSon(result, ast.emptyNode)
elif p.tok.ident.id == getIdent("continue").id: elif p.tok.ident.id == getIdent("continue").id:
result = newNodeP(nkContinueStmt, p) result = newNodeP(nkContinueStmt, p)
getTok(p) getTok(p)
skipCom(p, result) skipCom(p, result)
addSon(result, nil) addSon(result, ast.emptyNode)
elif p.tok.ident.id == getIdent("exit").id: elif p.tok.ident.id == getIdent("exit").id:
result = newNodeP(nkReturnStmt, p) result = newNodeP(nkReturnStmt, p)
getTok(p) getTok(p)
skipCom(p, result) skipCom(p, result)
addSon(result, nil) addSon(result, ast.emptyNode)
else: else:
result = parseExprStmt(p) result = parseExprStmt(p)
of pxDot: getTok(p) # BUGFIX for ``end.`` in main program of pxDot: getTok(p) # BUGFIX for ``end.`` in main program
else: result = parseExprStmt(p) else: result = parseExprStmt(p)
opt(p, pxSemicolon) opt(p, pxSemicolon)
if result != nil: skipCom(p, result) if result.kind != nkEmpty: skipCom(p, result)
p.context = oldcontext p.context = oldcontext
proc parseUnit(p: var TParser): PNode = proc parseUnit(p: var TParser): PNode =

View file

@ -104,7 +104,7 @@ proc processTopLevelStmtCached(n: PNode, a: var TPassContextArray) =
if not isNil(gPasses[i].openCached): m = gPasses[i].process(a[i], m) if not isNil(gPasses[i].openCached): m = gPasses[i].process(a[i], m)
proc closePassesCached(a: var TPassContextArray) = proc closePassesCached(a: var TPassContextArray) =
var m: PNode = nil var m = ast.emptyNode
for i in countup(0, gPassesLen - 1): for i in countup(0, gPassesLen - 1):
if not isNil(gPasses[i].openCached) and not isNil(gPasses[i].close): if not isNil(gPasses[i].openCached) and not isNil(gPasses[i].close):
m = gPasses[i].close(a[i], m) m = gPasses[i].close(a[i], m)
@ -114,7 +114,6 @@ proc processModule(module: PSym, filename: string, stream: PLLStream,
rd: PRodReader) = rd: PRodReader) =
var var
p: TParsers p: TParsers
n: PNode
a: TPassContextArray a: TPassContextArray
s: PLLStream s: PLLStream
if rd == nil: if rd == nil:
@ -129,8 +128,8 @@ proc processModule(module: PSym, filename: string, stream: PLLStream,
while true: while true:
openParsers(p, filename, s) openParsers(p, filename, s)
while true: while true:
n = parseTopLevelStmt(p) var n = parseTopLevelStmt(p)
if n == nil: break if n.kind == nkEmpty: break
processTopLevelStmt(n, a) processTopLevelStmt(n, a)
closeParsers(p) closeParsers(p)
if s.kind != llsStdIn: break if s.kind != llsStdIn: break
@ -139,7 +138,7 @@ proc processModule(module: PSym, filename: string, stream: PLLStream,
IDsynchronizationPoint(1000) IDsynchronizationPoint(1000)
else: else:
openPassesCached(a, module, filename, rd) openPassesCached(a, module, filename, rd)
n = loadInitSection(rd) #MessageOut('init section' + renderTree(n)); var n = loadInitSection(rd) #MessageOut('init section' + renderTree(n));
for i in countup(0, sonsLen(n) - 1): processTopLevelStmtCached(n.sons[i], a) for i in countup(0, sonsLen(n) - 1): processTopLevelStmtCached(n.sons[i], a)
closePassesCached(a) closePassesCached(a)

View file

@ -28,8 +28,8 @@ proc ParseAll*(p: var TParser): PNode
proc openParser*(p: var TParser, filename: string, inputstream: PLLStream) proc openParser*(p: var TParser, filename: string, inputstream: PLLStream)
proc closeParser*(p: var TParser) proc closeParser*(p: var TParser)
proc parseTopLevelStmt*(p: var TParser): PNode proc parseTopLevelStmt*(p: var TParser): PNode
# implements an iterator. Returns the next top-level statement or nil if end # implements an iterator. Returns the next top-level statement or
# of stream. # emtyNode if end of stream.
# helpers for the other parsers # helpers for the other parsers
proc getPrecedence*(tok: PToken): int proc getPrecedence*(tok: PToken): int
@ -94,7 +94,7 @@ proc optInd(p: var TParser, n: PNode) =
skipInd(p) skipInd(p)
proc expectIdentOrKeyw(p: TParser) = proc expectIdentOrKeyw(p: TParser) =
if (p.tok.tokType != tkSymbol) and not isKeyword(p.tok.tokType): if p.tok.tokType != tkSymbol and not isKeyword(p.tok.tokType):
lexMessage(p.lex^, errIdentifierExpected, tokToStr(p.tok)) lexMessage(p.lex^, errIdentifierExpected, tokToStr(p.tok))
proc ExpectIdent(p: TParser) = proc ExpectIdent(p: TParser) =
@ -217,18 +217,17 @@ proc parseSymbol(p: var TParser): PNode =
addSon(result, newIdentNodeP(id, p)) addSon(result, newIdentNodeP(id, p))
else: else:
parMessage(p, errIdentifierExpected, tokToStr(p.tok)) parMessage(p, errIdentifierExpected, tokToStr(p.tok))
result = nil result = ast.emptyNode
eat(p, tkAccent) eat(p, tkAccent)
else: else:
parMessage(p, errIdentifierExpected, tokToStr(p.tok)) parMessage(p, errIdentifierExpected, tokToStr(p.tok))
result = nil result = ast.emptyNode
proc accExpr(p: var TParser): PNode = proc accExpr(p: var TParser): PNode =
var x, y: PNode
result = newNodeP(nkAccQuoted, p) result = newNodeP(nkAccQuoted, p)
getTok(p) # skip ` getTok(p) # skip `
x = nil var x = ast.emptyNode
y = nil var y = ast.emptyNode
case p.tok.tokType case p.tok.tokType
of tkSymbol, tkOpr, tokKeywordLow..tokKeywordHigh: of tkSymbol, tkOpr, tokKeywordLow..tokKeywordHigh:
x = newIdentNodeP(p.tok.ident, p) x = newIdentNodeP(p.tok.ident, p)
@ -255,9 +254,9 @@ proc optExpr(p: var TParser): PNode =
(p.tok.tokType != tkDotDot): (p.tok.tokType != tkDotDot):
result = parseExpr(p) result = parseExpr(p)
else: else:
result = nil result = ast.emptyNode
proc dotdotExpr(p: var TParser, first: PNode = nil): PNode = proc dotdotExpr(p: var TParser, first: PNode): PNode =
result = newNodeP(nkRange, p) result = newNodeP(nkRange, p)
addSon(result, first) addSon(result, first)
getTok(p) getTok(p)
@ -266,20 +265,19 @@ proc dotdotExpr(p: var TParser, first: PNode = nil): PNode =
proc indexExpr(p: var TParser): PNode = proc indexExpr(p: var TParser): PNode =
# indexExpr ::= '..' [expr] | expr ['=' expr | '..' expr] # indexExpr ::= '..' [expr] | expr ['=' expr | '..' expr]
var a, b: PNode
if p.tok.tokType == tkDotDot: if p.tok.tokType == tkDotDot:
result = dotdotExpr(p) result = dotdotExpr(p, ast.emptyNode)
else: else:
a = parseExpr(p) var a = parseExpr(p)
case p.tok.tokType case p.tok.tokType
of tkEquals: of tkEquals:
result = newNodeP(nkExprEqExpr, p) result = newNodeP(nkExprEqExpr, p)
addSon(result, a) addSon(result, a)
getTok(p) getTok(p)
if p.tok.tokType == tkDotDot: if p.tok.tokType == tkDotDot:
addSon(result, dotdotExpr(p)) addSon(result, dotdotExpr(p, ast.emptyNode))
else: else:
b = parseExpr(p) var b = parseExpr(p)
if p.tok.tokType == tkDotDot: b = dotdotExpr(p, b) if p.tok.tokType == tkDotDot: b = dotdotExpr(p, b)
addSon(result, b) addSon(result, b)
of tkDotDot: of tkDotDot:
@ -305,7 +303,8 @@ proc exprColonEqExpr(p: var TParser, kind: TNodeKind, tok: TTokType): PNode =
var a = parseExpr(p) var a = parseExpr(p)
if p.tok.tokType == tok: if p.tok.tokType == tok:
result = newNodeP(kind, p) result = newNodeP(kind, p)
getTok(p) #optInd(p, result); getTok(p)
#optInd(p, result)
addSon(result, a) addSon(result, a)
addSon(result, parseExpr(p)) addSon(result, parseExpr(p))
else: else:
@ -481,14 +480,13 @@ proc identOrLiteral(p: var TParser): PNode =
else: else:
parMessage(p, errExprExpected, tokToStr(p.tok)) parMessage(p, errExprExpected, tokToStr(p.tok))
getTok(p) # we must consume a token here to prevend endless loops! getTok(p) # we must consume a token here to prevend endless loops!
result = nil result = ast.emptyNode
proc primary(p: var TParser): PNode = proc primary(p: var TParser): PNode =
var a: PNode
# prefix operator? # prefix operator?
if (p.tok.tokType == tkNot) or (p.tok.tokType == tkOpr): if (p.tok.tokType == tkNot) or (p.tok.tokType == tkOpr):
result = newNodeP(nkPrefix, p) result = newNodeP(nkPrefix, p)
a = newIdentNodeP(p.tok.ident, p) var a = newIdentNodeP(p.tok.ident, p)
addSon(result, a) addSon(result, a)
getTok(p) getTok(p)
optInd(p, a) optInd(p, a)
@ -504,12 +502,12 @@ proc primary(p: var TParser): PNode =
while true: while true:
case p.tok.tokType case p.tok.tokType
of tkParLe: of tkParLe:
a = result var a = result
result = newNodeP(nkCall, p) result = newNodeP(nkCall, p)
addSon(result, a) addSon(result, a)
exprColonEqExprListAux(p, nkExprEqExpr, tkParRi, tkEquals, result) exprColonEqExprListAux(p, nkExprEqExpr, tkParRi, tkEquals, result)
of tkDot: of tkDot:
a = result var a = result
result = newNodeP(nkDotExpr, p) result = newNodeP(nkDotExpr, p)
addSon(result, a) addSon(result, a)
getTok(p) # skip '.' getTok(p) # skip '.'
@ -517,7 +515,7 @@ proc primary(p: var TParser): PNode =
addSon(result, parseSymbol(p)) addSon(result, parseSymbol(p))
result = parseGStrLit(p, result) result = parseGStrLit(p, result)
of tkHat: of tkHat:
a = result var a = result
result = newNodeP(nkDerefExpr, p) result = newNodeP(nkDerefExpr, p)
addSon(result, a) addSon(result, a)
getTok(p) getTok(p)
@ -549,30 +547,28 @@ proc lowestExpr(p: var TParser): PNode =
discard lowestExprAux(p, result, - 1) discard lowestExprAux(p, result, - 1)
proc parseIfExpr(p: var TParser): PNode = proc parseIfExpr(p: var TParser): PNode =
var branch: PNode
result = newNodeP(nkIfExpr, p) result = newNodeP(nkIfExpr, p)
while true: while true:
getTok(p) # skip `if`, `elif` getTok(p) # skip `if`, `elif`
branch = newNodeP(nkElifExpr, p) var branch = newNodeP(nkElifExpr, p)
addSon(branch, parseExpr(p)) addSon(branch, parseExpr(p))
eat(p, tkColon) eat(p, tkColon)
addSon(branch, parseExpr(p)) addSon(branch, parseExpr(p))
addSon(result, branch) addSon(result, branch)
if p.tok.tokType != tkElif: break if p.tok.tokType != tkElif: break
branch = newNodeP(nkElseExpr, p) var branch = newNodeP(nkElseExpr, p)
eat(p, tkElse) eat(p, tkElse)
eat(p, tkColon) eat(p, tkColon)
addSon(branch, parseExpr(p)) addSon(branch, parseExpr(p))
addSon(result, branch) addSon(result, branch)
proc parsePragma(p: var TParser): PNode = proc parsePragma(p: var TParser): PNode =
var a: PNode
result = newNodeP(nkPragma, p) result = newNodeP(nkPragma, p)
getTok(p) getTok(p)
optInd(p, result) optInd(p, result)
while (p.tok.tokType != tkCurlyDotRi) and (p.tok.tokType != tkCurlyRi) and while (p.tok.tokType != tkCurlyDotRi) and (p.tok.tokType != tkCurlyRi) and
(p.tok.tokType != tkEof) and (p.tok.tokType != tkSad): (p.tok.tokType != tkEof) and (p.tok.tokType != tkSad):
a = exprColonEqExpr(p, nkExprColonExpr, tkColon) var a = exprColonEqExpr(p, nkExprColonExpr, tkColon)
addSon(result, a) addSon(result, a)
if p.tok.tokType == tkComma: if p.tok.tokType == tkComma:
getTok(p) getTok(p)
@ -583,8 +579,7 @@ proc parsePragma(p: var TParser): PNode =
proc identVis(p: var TParser): PNode = proc identVis(p: var TParser): PNode =
# identifier with visability # identifier with visability
var a: PNode var a = parseSymbol(p)
a = parseSymbol(p)
if p.tok.tokType == tkOpr: if p.tok.tokType == tkOpr:
result = newNodeP(nkPostfix, p) result = newNodeP(nkPostfix, p)
addSon(result, newIdentNodeP(p.tok.ident, p)) addSon(result, newIdentNodeP(p.tok.ident, p))
@ -594,8 +589,7 @@ proc identVis(p: var TParser): PNode =
result = a result = a
proc identWithPragma(p: var TParser): PNode = proc identWithPragma(p: var TParser): PNode =
var a: PNode var a = identVis(p)
a = identVis(p)
if p.tok.tokType == tkCurlyDotLe: if p.tok.tokType == tkCurlyDotLe:
result = newNodeP(nkPragmaExpr, p) result = newNodeP(nkPragmaExpr, p)
addSon(result, a) addSon(result, a)
@ -617,7 +611,7 @@ proc parseIdentColonEquals(p: var TParser, flags: TDeclaredIdentFlags): PNode =
of tkSymbol, tkAccent: of tkSymbol, tkAccent:
if withPragma in flags: a = identWithPragma(p) if withPragma in flags: a = identWithPragma(p)
else: a = parseSymbol(p) else: a = parseSymbol(p)
if a == nil: return if a.kind == nkEmpty: return
else: break else: break
addSon(result, a) addSon(result, a)
if p.tok.tokType != tkComma: break if p.tok.tokType != tkComma: break
@ -628,7 +622,7 @@ proc parseIdentColonEquals(p: var TParser, flags: TDeclaredIdentFlags): PNode =
optInd(p, result) optInd(p, result)
addSon(result, parseTypeDesc(p)) addSon(result, parseTypeDesc(p))
else: else:
addSon(result, nil) addSon(result, ast.emptyNode)
if (p.tok.tokType != tkEquals) and not (withBothOptional in flags): if (p.tok.tokType != tkEquals) and not (withBothOptional in flags):
parMessage(p, errColonOrEqualsExpected, tokToStr(p.tok)) parMessage(p, errColonOrEqualsExpected, tokToStr(p.tok))
if p.tok.tokType == tkEquals: if p.tok.tokType == tkEquals:
@ -636,16 +630,15 @@ proc parseIdentColonEquals(p: var TParser, flags: TDeclaredIdentFlags): PNode =
optInd(p, result) optInd(p, result)
addSon(result, parseExpr(p)) addSon(result, parseExpr(p))
else: else:
addSon(result, nil) addSon(result, ast.emptyNode)
proc parseTuple(p: var TParser): PNode = proc parseTuple(p: var TParser): PNode =
var a: PNode
result = newNodeP(nkTupleTy, p) result = newNodeP(nkTupleTy, p)
getTok(p) getTok(p)
eat(p, tkBracketLe) eat(p, tkBracketLe)
optInd(p, result) optInd(p, result)
while (p.tok.tokType == tkSymbol) or (p.tok.tokType == tkAccent): while (p.tok.tokType == tkSymbol) or (p.tok.tokType == tkAccent):
a = parseIdentColonEquals(p, {}) var a = parseIdentColonEquals(p, {})
addSon(result, a) addSon(result, a)
if p.tok.tokType != tkComma: break if p.tok.tokType != tkComma: break
getTok(p) getTok(p)
@ -656,7 +649,7 @@ proc parseTuple(p: var TParser): PNode =
proc parseParamList(p: var TParser): PNode = proc parseParamList(p: var TParser): PNode =
var a: PNode var a: PNode
result = newNodeP(nkFormalParams, p) result = newNodeP(nkFormalParams, p)
addSon(result, nil) # return type addSon(result, ast.emptyNode) # return type
if p.tok.tokType == tkParLe: if p.tok.tokType == tkParLe:
getTok(p) getTok(p)
optInd(p, result) optInd(p, result)
@ -689,11 +682,11 @@ proc parseProcExpr(p: var TParser, isExpr: bool): PNode =
getTok(p) getTok(p)
params = parseParamList(p) params = parseParamList(p)
if p.tok.tokType == tkCurlyDotLe: pragmas = parsePragma(p) if p.tok.tokType == tkCurlyDotLe: pragmas = parsePragma(p)
else: pragmas = nil else: pragmas = ast.emptyNode
if (p.tok.tokType == tkEquals) and isExpr: if (p.tok.tokType == tkEquals) and isExpr:
result = newNodeI(nkLambda, info) result = newNodeI(nkLambda, info)
addSon(result, nil) # no name part addSon(result, ast.emptyNode) # no name part
addSon(result, nil) # no generic parameters addSon(result, ast.emptyNode) # no generic parameters
addSon(result, params) addSon(result, params)
addSon(result, pragmas) addSon(result, pragmas)
getTok(p) getTok(p)
@ -744,12 +737,11 @@ proc isExprStart(p: TParser): bool =
else: result = false else: result = false
proc parseExprStmt(p: var TParser): PNode = proc parseExprStmt(p: var TParser): PNode =
var a, b, e: PNode var a = lowestExpr(p)
a = lowestExpr(p)
if p.tok.tokType == tkEquals: if p.tok.tokType == tkEquals:
getTok(p) getTok(p)
optInd(p, result) optInd(p, result)
b = parseExpr(p) var b = parseExpr(p)
result = newNodeI(nkAsgn, a.info) result = newNodeI(nkAsgn, a.info)
addSon(result, a) addSon(result, a)
addSon(result, b) addSon(result, b)
@ -759,7 +751,7 @@ proc parseExprStmt(p: var TParser): PNode =
addSon(result, a) addSon(result, a)
while true: while true:
if not isExprStart(p): break if not isExprStart(p): break
e = parseExpr(p) var e = parseExpr(p)
addSon(result, e) addSon(result, e)
if p.tok.tokType != tkComma: break if p.tok.tokType != tkComma: break
getTok(p) getTok(p)
@ -778,6 +770,7 @@ proc parseExprStmt(p: var TParser): PNode =
addSon(result, parseStmt(p)) addSon(result, parseStmt(p))
while true: while true:
if p.tok.tokType == tkSad: getTok(p) if p.tok.tokType == tkSad: getTok(p)
var b: PNode
case p.tok.tokType case p.tok.tokType
of tkOf: of tkOf:
b = newNodeP(nkOfBranch, p) b = newNodeP(nkOfBranch, p)
@ -871,7 +864,7 @@ proc parseReturnOrRaise(p: var TParser, kind: TNodeKind): PNode =
getTok(p) getTok(p)
optInd(p, result) optInd(p, result)
case p.tok.tokType case p.tok.tokType
of tkEof, tkSad, tkDed: addSon(result, nil) of tkEof, tkSad, tkDed: addSon(result, ast.emptyNode)
else: addSon(result, parseExpr(p)) else: addSon(result, parseExpr(p))
proc parseYieldOrDiscard(p: var TParser, kind: TNodeKind): PNode = proc parseYieldOrDiscard(p: var TParser, kind: TNodeKind): PNode =
@ -885,15 +878,14 @@ proc parseBreakOrContinue(p: var TParser, kind: TNodeKind): PNode =
getTok(p) getTok(p)
optInd(p, result) optInd(p, result)
case p.tok.tokType case p.tok.tokType
of tkEof, tkSad, tkDed: addSon(result, nil) of tkEof, tkSad, tkDed: addSon(result, ast.emptyNode)
else: addSon(result, parseSymbol(p)) else: addSon(result, parseSymbol(p))
proc parseIfOrWhen(p: var TParser, kind: TNodeKind): PNode = proc parseIfOrWhen(p: var TParser, kind: TNodeKind): PNode =
var branch: PNode
result = newNodeP(kind, p) result = newNodeP(kind, p)
while true: while true:
getTok(p) # skip `if`, `when`, `elif` getTok(p) # skip `if`, `when`, `elif`
branch = newNodeP(nkElifBranch, p) var branch = newNodeP(nkElifBranch, p)
optInd(p, branch) optInd(p, branch)
addSon(branch, parseExpr(p)) addSon(branch, parseExpr(p))
eat(p, tkColon) eat(p, tkColon)
@ -903,7 +895,7 @@ proc parseIfOrWhen(p: var TParser, kind: TNodeKind): PNode =
addSon(result, branch) addSon(result, branch)
if p.tok.tokType != tkElif: break if p.tok.tokType != tkElif: break
if p.tok.tokType == tkElse: if p.tok.tokType == tkElse:
branch = newNodeP(nkElse, p) var branch = newNodeP(nkElse, p)
eat(p, tkElse) eat(p, tkElse)
eat(p, tkColon) eat(p, tkColon)
skipComment(p, branch) skipComment(p, branch)
@ -954,13 +946,12 @@ proc parseCase(p: var TParser): PNode =
if b.kind == nkElse: break if b.kind == nkElse: break
proc parseTry(p: var TParser): PNode = proc parseTry(p: var TParser): PNode =
var b: PNode
result = newNodeP(nkTryStmt, p) result = newNodeP(nkTryStmt, p)
getTok(p) getTok(p)
eat(p, tkColon) eat(p, tkColon)
skipComment(p, result) skipComment(p, result)
addSon(result, parseStmt(p)) addSon(result, parseStmt(p))
b = nil var b: PNode = nil
while true: while true:
if p.tok.tokType == tkSad: getTok(p) if p.tok.tokType == tkSad: getTok(p)
case p.tok.tokType case p.tok.tokType
@ -979,11 +970,10 @@ proc parseTry(p: var TParser): PNode =
if b == nil: parMessage(p, errTokenExpected, "except") if b == nil: parMessage(p, errTokenExpected, "except")
proc parseFor(p: var TParser): PNode = proc parseFor(p: var TParser): PNode =
var a: PNode
result = newNodeP(nkForStmt, p) result = newNodeP(nkForStmt, p)
getTok(p) getTok(p)
optInd(p, result) optInd(p, result)
a = parseSymbol(p) var a = parseSymbol(p)
addSon(result, a) addSon(result, a)
while p.tok.tokType == tkComma: while p.tok.tokType == tkComma:
getTok(p) getTok(p)
@ -1001,7 +991,7 @@ proc parseBlock(p: var TParser): PNode =
getTok(p) getTok(p)
optInd(p, result) optInd(p, result)
case p.tok.tokType case p.tok.tokType
of tkEof, tkSad, tkDed, tkColon: addSon(result, nil) of tkEof, tkSad, tkDed, tkColon: addSon(result, ast.emptyNode)
else: addSon(result, parseSymbol(p)) else: addSon(result, parseSymbol(p))
eat(p, tkColon) eat(p, tkColon)
skipComment(p, result) skipComment(p, result)
@ -1012,7 +1002,7 @@ proc parseAsm(p: var TParser): PNode =
getTok(p) getTok(p)
optInd(p, result) optInd(p, result)
if p.tok.tokType == tkCurlyDotLe: addSon(result, parsePragma(p)) if p.tok.tokType == tkCurlyDotLe: addSon(result, parsePragma(p))
else: addSon(result, nil) else: addSon(result, ast.emptyNode)
case p.tok.tokType case p.tok.tokType
of tkStrLit: addSon(result, newStrNodeP(nkStrLit, p.tok.literal, p)) of tkStrLit: addSon(result, newStrNodeP(nkStrLit, p.tok.literal, p))
of tkRStrLit: addSon(result, newStrNodeP(nkRStrLit, p.tok.literal, p)) of tkRStrLit: addSon(result, newStrNodeP(nkRStrLit, p.tok.literal, p))
@ -1020,17 +1010,16 @@ proc parseAsm(p: var TParser): PNode =
newStrNodeP(nkTripleStrLit, p.tok.literal, p)) newStrNodeP(nkTripleStrLit, p.tok.literal, p))
else: else:
parMessage(p, errStringLiteralExpected) parMessage(p, errStringLiteralExpected)
addSon(result, nil) addSon(result, ast.emptyNode)
return return
getTok(p) getTok(p)
proc parseGenericParamList(p: var TParser): PNode = proc parseGenericParamList(p: var TParser): PNode =
var a: PNode
result = newNodeP(nkGenericParams, p) result = newNodeP(nkGenericParams, p)
getTok(p) getTok(p)
optInd(p, result) optInd(p, result)
while (p.tok.tokType == tkSymbol) or (p.tok.tokType == tkAccent): while (p.tok.tokType == tkSymbol) or (p.tok.tokType == tkAccent):
a = parseIdentColonEquals(p, {withBothOptional}) var a = parseIdentColonEquals(p, {withBothOptional})
addSon(result, a) addSon(result, a)
if p.tok.tokType != tkComma: break if p.tok.tokType != tkComma: break
getTok(p) getTok(p)
@ -1044,16 +1033,16 @@ proc parseRoutine(p: var TParser, kind: TNodeKind): PNode =
optInd(p, result) optInd(p, result)
addSon(result, identVis(p)) addSon(result, identVis(p))
if p.tok.tokType == tkBracketLe: addSon(result, parseGenericParamList(p)) if p.tok.tokType == tkBracketLe: addSon(result, parseGenericParamList(p))
else: addSon(result, nil) else: addSon(result, ast.emptyNode)
addSon(result, parseParamList(p)) addSon(result, parseParamList(p))
if p.tok.tokType == tkCurlyDotLe: addSon(result, parsePragma(p)) if p.tok.tokType == tkCurlyDotLe: addSon(result, parsePragma(p))
else: addSon(result, nil) else: addSon(result, ast.emptyNode)
if p.tok.tokType == tkEquals: if p.tok.tokType == tkEquals:
getTok(p) getTok(p)
skipComment(p, result) skipComment(p, result)
addSon(result, parseStmt(p)) addSon(result, parseStmt(p))
else: else:
addSon(result, nil) addSon(result, ast.emptyNode)
indAndComment(p, result) # XXX: document this in the grammar! indAndComment(p, result) # XXX: document this in the grammar!
proc newCommentStmt(p: var TParser): PNode = proc newCommentStmt(p: var TParser): PNode =
@ -1065,13 +1054,12 @@ type
proc parseSection(p: var TParser, kind: TNodeKind, proc parseSection(p: var TParser, kind: TNodeKind,
defparser: TDefParser): PNode = defparser: TDefParser): PNode =
var a: PNode
result = newNodeP(kind, p) result = newNodeP(kind, p)
getTok(p) getTok(p)
skipComment(p, result) skipComment(p, result)
case p.tok.tokType case p.tok.tokType
of tkInd: of tkInd:
pushInd(p.lex^ , p.tok.indent) pushInd(p.lex^, p.tok.indent)
getTok(p) getTok(p)
skipComment(p, result) skipComment(p, result)
while true: while true:
@ -1079,7 +1067,7 @@ proc parseSection(p: var TParser, kind: TNodeKind,
of tkSad: of tkSad:
getTok(p) getTok(p)
of tkSymbol, tkAccent: of tkSymbol, tkAccent:
a = defparser(p) var a = defparser(p)
skipComment(p, a) skipComment(p, a)
addSon(result, a) addSon(result, a)
of tkDed: of tkDed:
@ -1088,13 +1076,13 @@ proc parseSection(p: var TParser, kind: TNodeKind,
of tkEof: of tkEof:
break # BUGFIX break # BUGFIX
of tkComment: of tkComment:
a = newCommentStmt(p) var a = newCommentStmt(p)
skipComment(p, a) skipComment(p, a)
addSon(result, a) addSon(result, a)
else: else:
parMessage(p, errIdentifierExpected, tokToStr(p.tok)) parMessage(p, errIdentifierExpected, tokToStr(p.tok))
break break
popInd(p.lex^ ) popInd(p.lex^)
of tkSymbol, tkAccent, tkParLe: of tkSymbol, tkAccent, tkParLe:
# tkParLe is allowed for ``var (x, y) = ...`` tuple parsing # tkParLe is allowed for ``var (x, y) = ...`` tuple parsing
addSon(result, defparser(p)) addSon(result, defparser(p))
@ -1108,7 +1096,7 @@ proc parseConstant(p: var TParser): PNode =
optInd(p, result) optInd(p, result)
addSon(result, parseTypeDesc(p)) addSon(result, parseTypeDesc(p))
else: else:
addSon(result, nil) addSon(result, ast.emptyNode)
eat(p, tkEquals) eat(p, tkEquals)
optInd(p, result) optInd(p, result)
addSon(result, parseExpr(p)) addSon(result, parseExpr(p))
@ -1126,7 +1114,7 @@ proc parseEnum(p: var TParser): PNode =
addSon(a, parseTypeDesc(p)) addSon(a, parseTypeDesc(p))
addSon(result, a) addSon(result, a)
else: else:
addSon(result, nil) addSon(result, ast.emptyNode)
optInd(p, result) optInd(p, result)
while true: while true:
case p.tok.tokType case p.tok.tokType
@ -1148,11 +1136,10 @@ proc parseEnum(p: var TParser): PNode =
proc parseObjectPart(p: var TParser): PNode proc parseObjectPart(p: var TParser): PNode
proc parseObjectWhen(p: var TParser): PNode = proc parseObjectWhen(p: var TParser): PNode =
var branch: PNode
result = newNodeP(nkRecWhen, p) result = newNodeP(nkRecWhen, p)
while true: while true:
getTok(p) # skip `when`, `elif` getTok(p) # skip `when`, `elif`
branch = newNodeP(nkElifBranch, p) var branch = newNodeP(nkElifBranch, p)
optInd(p, branch) optInd(p, branch)
addSon(branch, parseExpr(p)) addSon(branch, parseExpr(p))
eat(p, tkColon) eat(p, tkColon)
@ -1162,7 +1149,7 @@ proc parseObjectWhen(p: var TParser): PNode =
addSon(result, branch) addSon(result, branch)
if p.tok.tokType != tkElif: break if p.tok.tokType != tkElif: break
if p.tok.tokType == tkElse: if p.tok.tokType == tkElse:
branch = newNodeP(nkElse, p) var branch = newNodeP(nkElse, p)
eat(p, tkElse) eat(p, tkElse)
eat(p, tkColon) eat(p, tkColon)
skipComment(p, branch) skipComment(p, branch)
@ -1170,18 +1157,18 @@ proc parseObjectWhen(p: var TParser): PNode =
addSon(result, branch) addSon(result, branch)
proc parseObjectCase(p: var TParser): PNode = proc parseObjectCase(p: var TParser): PNode =
var a, b: PNode
result = newNodeP(nkRecCase, p) result = newNodeP(nkRecCase, p)
getTok(p) getTok(p)
a = newNodeP(nkIdentDefs, p) var a = newNodeP(nkIdentDefs, p)
addSon(a, identWithPragma(p)) addSon(a, identWithPragma(p))
eat(p, tkColon) eat(p, tkColon)
addSon(a, parseTypeDesc(p)) addSon(a, parseTypeDesc(p))
addSon(a, nil) addSon(a, ast.emptyNode)
addSon(result, a) addSon(result, a)
skipComment(p, result) skipComment(p, result)
while true: while true:
if p.tok.tokType == tkSad: getTok(p) if p.tok.tokType == tkSad: getTok(p)
var b: PNode
case p.tok.tokType case p.tok.tokType
of tkOf: of tkOf:
b = newNodeP(nkOfBranch, p) b = newNodeP(nkOfBranch, p)
@ -1200,7 +1187,7 @@ proc parseObjectPart(p: var TParser): PNode =
case p.tok.tokType case p.tok.tokType
of tkInd: of tkInd:
result = newNodeP(nkRecList, p) result = newNodeP(nkRecList, p)
pushInd(p.lex^ , p.tok.indent) pushInd(p.lex^, p.tok.indent)
getTok(p) getTok(p)
skipComment(p, result) skipComment(p, result)
while true: while true:
@ -1228,21 +1215,20 @@ proc parseObjectPart(p: var TParser): PNode =
of tkNil: of tkNil:
result = newNodeP(nkNilLit, p) result = newNodeP(nkNilLit, p)
getTok(p) getTok(p)
else: result = nil else: result = ast.emptyNode
proc parseObject(p: var TParser): PNode = proc parseObject(p: var TParser): PNode =
var a: PNode
result = newNodeP(nkObjectTy, p) result = newNodeP(nkObjectTy, p)
getTok(p) getTok(p)
if p.tok.tokType == tkCurlyDotLe: addSon(result, parsePragma(p)) if p.tok.tokType == tkCurlyDotLe: addSon(result, parsePragma(p))
else: addSon(result, nil) else: addSon(result, ast.emptyNode)
if p.tok.tokType == tkOf: if p.tok.tokType == tkOf:
a = newNodeP(nkOfInherit, p) var a = newNodeP(nkOfInherit, p)
getTok(p) getTok(p)
addSon(a, parseTypeDesc(p)) addSon(a, parseTypeDesc(p))
addSon(result, a) addSon(result, a)
else: else:
addSon(result, nil) addSon(result, ast.emptyNode)
skipComment(p, result) skipComment(p, result)
addSon(result, parseObjectPart(p)) addSon(result, parseObjectPart(p))
@ -1253,14 +1239,14 @@ proc parseDistinct(p: var TParser): PNode =
addSon(result, parseTypeDesc(p)) addSon(result, parseTypeDesc(p))
proc parseTypeDef(p: var TParser): PNode = proc parseTypeDef(p: var TParser): PNode =
var a: PNode
result = newNodeP(nkTypeDef, p) result = newNodeP(nkTypeDef, p)
addSon(result, identWithPragma(p)) addSon(result, identWithPragma(p))
if p.tok.tokType == tkBracketLe: addSon(result, parseGenericParamList(p)) if p.tok.tokType == tkBracketLe: addSon(result, parseGenericParamList(p))
else: addSon(result, nil) else: addSon(result, ast.emptyNode)
if p.tok.tokType == tkEquals: if p.tok.tokType == tkEquals:
getTok(p) getTok(p)
optInd(p, result) optInd(p, result)
var a: PNode
case p.tok.tokType case p.tok.tokType
of tkObject: a = parseObject(p) of tkObject: a = parseObject(p)
of tkEnum: a = parseEnum(p) of tkEnum: a = parseEnum(p)
@ -1268,21 +1254,20 @@ proc parseTypeDef(p: var TParser): PNode =
else: a = parseTypeDesc(p) else: a = parseTypeDesc(p)
addSon(result, a) addSon(result, a)
else: else:
addSon(result, nil) addSon(result, ast.emptyNode)
indAndComment(p, result) # special extension! indAndComment(p, result) # special extension!
proc parseVarTuple(p: var TParser): PNode = proc parseVarTuple(p: var TParser): PNode =
var a: PNode
result = newNodeP(nkVarTuple, p) result = newNodeP(nkVarTuple, p)
getTok(p) # skip '(' getTok(p) # skip '('
optInd(p, result) optInd(p, result)
while (p.tok.tokType == tkSymbol) or (p.tok.tokType == tkAccent): while (p.tok.tokType == tkSymbol) or (p.tok.tokType == tkAccent):
a = identWithPragma(p) var a = identWithPragma(p)
addSon(result, a) addSon(result, a)
if p.tok.tokType != tkComma: break if p.tok.tokType != tkComma: break
getTok(p) getTok(p)
optInd(p, a) optInd(p, a)
addSon(result, nil) # no type desc addSon(result, ast.emptyNode) # no type desc
optPar(p) optPar(p)
eat(p, tkParRi) eat(p, tkParRi)
eat(p, tkEquals) eat(p, tkEquals)
@ -1309,8 +1294,8 @@ proc simpleStmt(p: var TParser): PNode =
of tkComment: result = newCommentStmt(p) of tkComment: result = newCommentStmt(p)
else: else:
if isExprStart(p): result = parseExprStmt(p) if isExprStart(p): result = parseExprStmt(p)
else: result = nil else: result = ast.emptyNode
if result != nil: skipComment(p, result) if result.kind != nkEmpty: skipComment(p, result)
proc complexOrSimpleStmt(p: var TParser): PNode = proc complexOrSimpleStmt(p: var TParser): PNode =
case p.tok.tokType case p.tok.tokType
@ -1334,10 +1319,9 @@ proc complexOrSimpleStmt(p: var TParser): PNode =
else: result = simpleStmt(p) else: result = simpleStmt(p)
proc parseStmt(p: var TParser): PNode = proc parseStmt(p: var TParser): PNode =
var a: PNode
if p.tok.tokType == tkInd: if p.tok.tokType == tkInd:
result = newNodeP(nkStmtList, p) result = newNodeP(nkStmtList, p)
pushInd(p.lex^ , p.tok.indent) pushInd(p.lex^, p.tok.indent)
getTok(p) getTok(p)
while true: while true:
case p.tok.tokType case p.tok.tokType
@ -1347,8 +1331,8 @@ proc parseStmt(p: var TParser): PNode =
getTok(p) getTok(p)
break break
else: else:
a = complexOrSimpleStmt(p) var a = complexOrSimpleStmt(p)
if a == nil: break if a.kind == nkEmpty: break
addSon(result, a) addSon(result, a)
popInd(p.lex^ ) popInd(p.lex^ )
else: else:
@ -1357,14 +1341,13 @@ proc parseStmt(p: var TParser): PNode =
of tkIf, tkWhile, tkCase, tkTry, tkFor, tkBlock, tkAsm, tkProc, tkIterator, of tkIf, tkWhile, tkCase, tkTry, tkFor, tkBlock, tkAsm, tkProc, tkIterator,
tkMacro, tkType, tkConst, tkWhen, tkVar: tkMacro, tkType, tkConst, tkWhen, tkVar:
parMessage(p, errComplexStmtRequiresInd) parMessage(p, errComplexStmtRequiresInd)
result = nil result = ast.emptyNode
else: else:
result = simpleStmt(p) result = simpleStmt(p)
if result == nil: parMessage(p, errExprExpected, tokToStr(p.tok)) if result.kind == nkEmpty: parMessage(p, errExprExpected, tokToStr(p.tok))
if p.tok.tokType == tkSad: getTok(p) if p.tok.tokType == tkSad: getTok(p)
proc parseAll(p: var TParser): PNode = proc parseAll(p: var TParser): PNode =
var a: PNode
result = newNodeP(nkStmtList, p) result = newNodeP(nkStmtList, p)
while true: while true:
case p.tok.tokType case p.tok.tokType
@ -1372,20 +1355,20 @@ proc parseAll(p: var TParser): PNode =
of tkDed, tkInd: parMessage(p, errInvalidIndentation) of tkDed, tkInd: parMessage(p, errInvalidIndentation)
of tkEof: break of tkEof: break
else: else:
a = complexOrSimpleStmt(p) var a = complexOrSimpleStmt(p)
if a == nil: parMessage(p, errExprExpected, tokToStr(p.tok)) if a.kind == nkEmpty: parMessage(p, errExprExpected, tokToStr(p.tok))
addSon(result, a) addSon(result, a)
proc parseTopLevelStmt(p: var TParser): PNode = proc parseTopLevelStmt(p: var TParser): PNode =
result = nil result = ast.emptyNode
while true: while true:
case p.tok.tokType case p.tok.tokType
of tkSad: getTok(p) of tkSad: getTok(p)
of tkDed, tkInd: of tkDed, tkInd:
parMessage(p, errInvalidIndentation) parMessage(p, errInvalidIndentation)
break getTok(p)
of tkEof: break of tkEof: break
else: else:
result = complexOrSimpleStmt(p) result = complexOrSimpleStmt(p)
if result == nil: parMessage(p, errExprExpected, tokToStr(p.tok)) if result.kind == nkEmpty: parMessage(p, errExprExpected, tokToStr(p.tok))
break break

View file

@ -323,13 +323,13 @@ proc lsons(n: PNode, start: int = 0, theEnd: int = - 1): int =
proc lsub(n: PNode): int = proc lsub(n: PNode): int =
# computes the length of a tree # computes the length of a tree
if n == nil: return 0
if n.comment != nil: return maxLineLen + 1 if n.comment != nil: return maxLineLen + 1
case n.kind case n.kind
of nkEmpty: result = 0
of nkTripleStrLit: of nkTripleStrLit:
if containsNL(n.strVal): result = maxLineLen + 1 if containsNL(n.strVal): result = maxLineLen + 1
else: result = len(atom(n)) else: result = len(atom(n))
of nkEmpty..pred(nkTripleStrLit), succ(nkTripleStrLit)..nkNilLit: of succ(nkEmpty)..pred(nkTripleStrLit), succ(nkTripleStrLit)..nkNilLit:
result = len(atom(n)) result = len(atom(n))
of nkCall, nkBracketExpr, nkConv: result = lsub(n.sons[0]) + lcomma(n, 1) + 2 of nkCall, nkBracketExpr, nkConv: result = lsub(n.sons[0]) + lcomma(n, 1) + 2
of nkHiddenStdConv, nkHiddenSubConv, nkHiddenCallConv: result = lsub(n[1]) of nkHiddenStdConv, nkHiddenSubConv, nkHiddenCallConv: result = lsub(n[1])
@ -348,8 +348,8 @@ proc lsub(n: PNode): int =
of nkConstDef, nkIdentDefs: of nkConstDef, nkIdentDefs:
result = lcomma(n, 0, - 3) result = lcomma(n, 0, - 3)
var L = sonsLen(n) var L = sonsLen(n)
if n.sons[L - 2] != nil: result = result + lsub(n.sons[L - 2]) + 2 if n.sons[L - 2].kind != nkEmpty: result = result + lsub(n.sons[L - 2]) + 2
if n.sons[L - 1] != nil: result = result + lsub(n.sons[L - 1]) + 3 if n.sons[L - 1].kind != nkEmpty: result = result + lsub(n.sons[L - 1]) + 3
of nkVarTuple: result = lcomma(n, 0, - 3) + len("() = ") + lsub(lastSon(n)) of nkVarTuple: result = lcomma(n, 0, - 3) + len("() = ") + lsub(lastSon(n))
of nkChckRangeF: result = len("chckRangeF") + 2 + lcomma(n) of nkChckRangeF: result = len("chckRangeF") + 2 + lcomma(n)
of nkChckRange64: result = len("chckRange64") + 2 + lcomma(n) of nkChckRange64: result = len("chckRange64") + 2 + lcomma(n)
@ -401,7 +401,7 @@ proc lsub(n: PNode): int =
of nkGenericParams: result = lcomma(n) + 2 of nkGenericParams: result = lcomma(n) + 2
of nkFormalParams: of nkFormalParams:
result = lcomma(n, 1) + 2 result = lcomma(n, 1) + 2
if n.sons[0] != nil: result = result + lsub(n.sons[0]) + 2 if n.sons[0].kind != nkEmpty: result = result + lsub(n.sons[0]) + 2
of nkExceptBranch: of nkExceptBranch:
result = lcomma(n, 0, -2) + lsub(lastSon(n)) + len("except_:_") result = lcomma(n, 0, -2) + lsub(lastSon(n)) + len("except_:_")
else: result = maxLineLen + 1 else: result = maxLineLen + 1
@ -430,7 +430,6 @@ proc gsub(g: var TSrcGen, n: PNode) =
proc hasCom(n: PNode): bool = proc hasCom(n: PNode): bool =
result = false result = false
if n == nil: return
if n.comment != nil: return true if n.comment != nil: return true
case n.kind case n.kind
of nkEmpty..nkNilLit: nil of nkEmpty..nkNilLit: nil
@ -496,7 +495,7 @@ proc longMode(n: PNode, start: int = 0, theEnd: int = - 1): bool =
break break
proc gstmts(g: var TSrcGen, n: PNode, c: TContext) = proc gstmts(g: var TSrcGen, n: PNode, c: TContext) =
if n == nil: return if n.kind == nkEmpty: return
if (n.kind == nkStmtList) or (n.kind == nkStmtListExpr): if (n.kind == nkStmtList) or (n.kind == nkStmtListExpr):
indentNL(g) indentNL(g)
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):
@ -598,7 +597,7 @@ proc gproc(g: var TSrcGen, n: PNode) =
gsub(g, n.sons[2]) gsub(g, n.sons[2])
gsub(g, n.sons[3]) gsub(g, n.sons[3])
if not (renderNoBody in g.flags): if not (renderNoBody in g.flags):
if n.sons[4] != nil: if n.sons[4].kind != nkEmpty:
put(g, tkSpaces, Space) put(g, tkSpaces, Space)
putWithSpace(g, tkEquals, "=") putWithSpace(g, tkEquals, "=")
indentNL(g) indentNL(g)
@ -615,7 +614,7 @@ proc gproc(g: var TSrcGen, n: PNode) =
proc gblock(g: var TSrcGen, n: PNode) = proc gblock(g: var TSrcGen, n: PNode) =
var c: TContext var c: TContext
initContext(c) initContext(c)
if n.sons[0] != nil: if n.sons[0].kind != nkEmpty:
putWithSpace(g, tkBlock, "block") putWithSpace(g, tkBlock, "block")
gsub(g, n.sons[0]) gsub(g, n.sons[0])
else: else:
@ -656,11 +655,11 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
var var
L: int L: int
a: TContext a: TContext
if n == nil: return
if n.comment != nil: pushCom(g, n) if n.comment != nil: pushCom(g, n)
case n.kind # atoms: case n.kind # atoms:
of nkTripleStrLit: putRawStr(g, tkTripleStrLit, n.strVal) of nkTripleStrLit: putRawStr(g, tkTripleStrLit, n.strVal)
of nkEmpty, nkType: put(g, tkInvalid, atom(n)) of nkEmpty: nil
of nkType: put(g, tkInvalid, atom(n))
of nkSym, nkIdent: gident(g, n) of nkSym, nkIdent: gident(g, n)
of nkIntLit: put(g, tkIntLit, atom(n)) of nkIntLit: put(g, tkIntLit, atom(n))
of nkInt8Lit: put(g, tkInt8Lit, atom(n)) of nkInt8Lit: put(g, tkInt8Lit, atom(n))
@ -765,7 +764,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
of nkCheckedFieldExpr, nkHiddenAddr, nkHiddenDeref: of nkCheckedFieldExpr, nkHiddenAddr, nkHiddenDeref:
gsub(g, n.sons[0]) gsub(g, n.sons[0])
of nkLambda: of nkLambda:
assert(n.sons[genericParamsPos] == nil) assert(n.sons[genericParamsPos].kind == nkEmpty)
putWithSpace(g, tkLambda, "lambda") putWithSpace(g, tkLambda, "lambda")
gsub(g, n.sons[paramsPos]) gsub(g, n.sons[paramsPos])
gsub(g, n.sons[pragmasPos]) gsub(g, n.sons[pragmasPos])
@ -775,10 +774,10 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
of nkConstDef, nkIdentDefs: of nkConstDef, nkIdentDefs:
gcomma(g, n, 0, - 3) gcomma(g, n, 0, - 3)
var L = sonsLen(n) var L = sonsLen(n)
if n.sons[L - 2] != nil: if n.sons[L - 2].kind != nkEmpty:
putWithSpace(g, tkColon, ":") putWithSpace(g, tkColon, ":")
gsub(g, n.sons[L - 2]) gsub(g, n.sons[L - 2])
if n.sons[L - 1] != nil: if n.sons[L - 1].kind != nkEmpty:
put(g, tkSpaces, Space) put(g, tkSpaces, Space)
putWithSpace(g, tkEquals, "=") putWithSpace(g, tkEquals, "=")
gsub(g, n.sons[L - 1], c) gsub(g, n.sons[L - 1], c)
@ -855,7 +854,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
gsub(g, n.sons[0]) gsub(g, n.sons[0])
gsub(g, n.sons[1]) gsub(g, n.sons[1])
put(g, tkSpaces, Space) put(g, tkSpaces, Space)
if n.sons[2] != nil: if n.sons[2].kind != nkEmpty:
putWithSpace(g, tkEquals, "=") putWithSpace(g, tkEquals, "=")
gsub(g, n.sons[2]) gsub(g, n.sons[2])
of nkObjectTy: of nkObjectTy:
@ -1029,7 +1028,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
put(g, tkParLe, "(") put(g, tkParLe, "(")
gcomma(g, n, 1) gcomma(g, n, 1)
put(g, tkParRi, ")") put(g, tkParRi, ")")
if n.sons[0] != nil: if n.sons[0].kind != nkEmpty:
putWithSpace(g, tkColon, ":") putWithSpace(g, tkColon, ":")
gsub(g, n.sons[0]) gsub(g, n.sons[0])
of nkTupleTy: of nkTupleTy:
@ -1055,10 +1054,9 @@ proc renderModule(n: PNode, filename: string, renderFlags: TRenderFlags = {}) =
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):
gsub(g, n.sons[i]) gsub(g, n.sons[i])
optNL(g) optNL(g)
if n.sons[i] != nil: case n.sons[i].kind
case n.sons[i].kind of nkTypeSection, nkConstSection, nkVarSection, nkCommentStmt: putNL(g)
of nkTypeSection, nkConstSection, nkVarSection, nkCommentStmt: putNL(g) else: nil
else: nil
gcoms(g) gcoms(g)
if open(f, filename, fmWrite): if open(f, filename, fmWrite):
write(f, g.buf) write(f, g.buf)

View file

@ -175,7 +175,6 @@ proc findIdent(L: TLexer, indent: int): bool =
for i in countdown(len(L.indentStack) - 1, 0): for i in countdown(len(L.indentStack) - 1, 0):
if L.indentStack[i] == indent: if L.indentStack[i] == indent:
return true return true
result = false
proc tokToStr(tok: PToken): string = proc tokToStr(tok: PToken): string =
case tok.tokType case tok.tokType
@ -574,7 +573,7 @@ proc getSymbol(L: var TLexer, tok: var TToken) =
of '_': of '_':
if buf[pos+1] notin SymChars: if buf[pos+1] notin SymChars:
lexMessage(L, errInvalidToken, "_") lexMessage(L, errInvalidToken, "_")
return break
else: break else: break
Inc(pos) Inc(pos)
h = h +% h shl 3 h = h +% h shl 3
@ -587,11 +586,6 @@ proc getSymbol(L: var TLexer, tok: var TToken) =
tok.tokType = tkSymbol tok.tokType = tkSymbol
else: else:
tok.tokType = TTokType(tok.ident.id + ord(tkSymbol)) tok.tokType = TTokType(tok.ident.id + ord(tkSymbol))
when false:
if buf[pos] == '\"':
getString(L, tok, true)
if tok.tokType == tkRStrLit: tok.tokType = tkCallRStrLit
else: tok.tokType = tkCallTripleStrLit
proc getOperator(L: var TLexer, tok: var TToken) = proc getOperator(L: var TLexer, tok: var TToken) =
var pos = L.bufpos var pos = L.bufpos

View file

@ -133,7 +133,7 @@ proc semRangeAux(c: PContext, n: PNode, prev: PType): PType =
{tyInt..tyInt64, tyEnum, tyBool, tyChar, tyFloat..tyFloat128}): {tyInt..tyInt64, tyEnum, tyBool, tyChar, tyFloat..tyFloat128}):
liMessage(n.info, errOrdinalTypeExpected) liMessage(n.info, errOrdinalTypeExpected)
if enumHasWholes(a.typ): if enumHasWholes(a.typ):
liMessage(n.info, errEnumXHasWholes, a.typ.sym.name.s) liMessage(n.info, errEnumXHasHoles, a.typ.sym.name.s)
if not leValue(a, b): liMessage(n.Info, errRangeIsEmpty) if not leValue(a, b): liMessage(n.Info, errRangeIsEmpty)
addSon(result.n, a) addSon(result.n, a)
addSon(result.n, b) addSon(result.n, b)
@ -160,7 +160,7 @@ proc semArray(c: PContext, n: PNode, prev: PType): PType =
if not isOrdinalType(indx): if not isOrdinalType(indx):
liMessage(n.sons[1].info, errOrdinalTypeExpected) liMessage(n.sons[1].info, errOrdinalTypeExpected)
if enumHasWholes(indx): if enumHasWholes(indx):
liMessage(n.sons[1].info, errEnumXHasWholes, indx.sym.name.s) liMessage(n.sons[1].info, errEnumXHasHoles, indx.sym.name.s)
base = semTypeNode(c, n.sons[2], nil) base = semTypeNode(c, n.sons[2], nil)
addSon(result, base) addSon(result, base)
else: else:

View file

@ -1,7 +1,7 @@
# #
# #
# The Nimrod Compiler # The Nimrod Compiler
# (c) Copyright 2010 Andreas Rumpf # (c) Copyright 2011 Andreas Rumpf
# #
# See the file "copying.txt", included in this # See the file "copying.txt", included in this
# distribution, for details about the copyright. # distribution, for details about the copyright.
@ -59,6 +59,7 @@ proc parseAll(p: var TParsers): PNode =
result = pbraces.parseAll(p.parser) result = pbraces.parseAll(p.parser)
of skinEndX: of skinEndX:
InternalError("parser to implement") InternalError("parser to implement")
result = ast.emptyNode
# skinEndX: result := pendx.parseAll(p.parser); # skinEndX: result := pendx.parseAll(p.parser);
proc parseTopLevelStmt(p: var TParsers): PNode = proc parseTopLevelStmt(p: var TParsers): PNode =
@ -69,6 +70,7 @@ proc parseTopLevelStmt(p: var TParsers): PNode =
result = pbraces.parseTopLevelStmt(p.parser) result = pbraces.parseTopLevelStmt(p.parser)
of skinEndX: of skinEndX:
InternalError("parser to implement") InternalError("parser to implement")
result = ast.emptyNode
#skinEndX: result := pendx.parseTopLevelStmt(p.parser); #skinEndX: result := pendx.parseTopLevelStmt(p.parser);
proc UTF8_BOM(s: string): int = proc UTF8_BOM(s: string): int =
@ -84,6 +86,7 @@ proc containsShebang(s: string, i: int): bool =
result = s[j] == '/' result = s[j] == '/'
proc parsePipe(filename: string, inputStream: PLLStream): PNode = proc parsePipe(filename: string, inputStream: PLLStream): PNode =
result = ast.emptyNode
var s = LLStreamOpen(filename, fmRead) var s = LLStreamOpen(filename, fmRead)
if s != nil: if s != nil:
var line = LLStreamReadLine(s) var line = LLStreamReadLine(s)
@ -143,7 +146,7 @@ proc applyFilter(p: var TParsers, n: PNode, filename: string,
proc evalPipe(p: var TParsers, n: PNode, filename: string, proc evalPipe(p: var TParsers, n: PNode, filename: string,
start: PLLStream): PLLStream = start: PLLStream): PLLStream =
result = start result = start
if n == nil: return if n.kind == nkEmpty: return
if (n.kind == nkInfix) and (n.sons[0].kind == nkIdent) and if (n.kind == nkInfix) and (n.sons[0].kind == nkIdent) and
IdentEq(n.sons[0].ident, "|"): IdentEq(n.sons[0].ident, "|"):
for i in countup(1, 2): for i in countup(1, 2):

View file

@ -1,3 +1,8 @@
- ban ``nil`` from the AST. This might also fix bugs concerning macros.
TODO:
* semantic checking (keep in mind incremental parsing!)
* code generators
- thread support: threadvar on Windows seems broken; - thread support: threadvar on Windows seems broken;
add --deadlock_prevention:on|off switch add --deadlock_prevention:on|off switch
- built-in serialization - built-in serialization
@ -68,7 +73,6 @@ Low priority
- fast assignment optimization for TPeg - fast assignment optimization for TPeg
- better error messages for used keywords as identifiers - better error messages for used keywords as identifiers
- case statement branches should support constant sets - case statement branches should support constant sets
- ban ``nil`` from the AST. This might also fix bugs concerning macros.
Library Library