mirror of
https://github.com/nim-lang/Nim.git
synced 2026-01-05 04:27:44 +00:00
first steps to the expr/stmt unification
This commit is contained in:
@@ -861,15 +861,14 @@ proc genIfExpr(p: BProc, n: PNode, d: var TLoc) =
|
||||
Lend = getLabel(p)
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
it = n.sons[i]
|
||||
case it.kind
|
||||
of nkElifExpr:
|
||||
if it.len == 2:
|
||||
initLocExpr(p, it.sons[0], a)
|
||||
Lelse = getLabel(p)
|
||||
lineF(p, cpsStmts, "if (!$1) goto $2;$n", [rdLoc(a), Lelse])
|
||||
expr(p, it.sons[1], tmp)
|
||||
lineF(p, cpsStmts, "goto $1;$n", [Lend])
|
||||
fixLabel(p, Lelse)
|
||||
of nkElseExpr:
|
||||
elif it.len == 1:
|
||||
expr(p, it.sons[0], tmp)
|
||||
else: internalError(n.info, "genIfExpr()")
|
||||
fixLabel(p, Lend)
|
||||
|
||||
@@ -231,8 +231,7 @@ proc genIfStmt(p: BProc, n: PNode) =
|
||||
var Lend = getLabel(p)
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
var it = n.sons[i]
|
||||
case it.kind
|
||||
of nkElifBranch:
|
||||
if it.len == 2:
|
||||
initLocExpr(p, it.sons[0], a)
|
||||
Lelse = getLabel(p)
|
||||
inc(p.labels)
|
||||
@@ -243,7 +242,7 @@ proc genIfStmt(p: BProc, n: PNode) =
|
||||
if sonsLen(n) > 1:
|
||||
lineFF(p, cpsStmts, "goto $1;$n", "br label %$1$n", [Lend])
|
||||
fixLabel(p, Lelse)
|
||||
of nkElse:
|
||||
elif it.len == 1:
|
||||
genSimpleBlock(p, it.sons[0])
|
||||
else: internalError(n.info, "genIfStmt()")
|
||||
if sonsLen(n) > 1: fixLabel(p, Lend)
|
||||
|
||||
@@ -315,9 +315,7 @@ proc indexExprList(p: var TParser, first: PNode, k: TNodeKind,
|
||||
optPar(p)
|
||||
eat(p, endToken)
|
||||
|
||||
proc exprColonEqExpr(p: var TParser): PNode =
|
||||
#| exprColonEqExpr = expr (':'|'=' expr)?
|
||||
var a = parseExpr(p)
|
||||
proc colonOrEquals(p: var TParser, a: PNode): PNode =
|
||||
if p.tok.tokType == tkColon:
|
||||
result = newNodeP(nkExprColonExpr, p)
|
||||
getTok(p)
|
||||
@@ -333,6 +331,11 @@ proc exprColonEqExpr(p: var TParser): PNode =
|
||||
else:
|
||||
result = a
|
||||
|
||||
proc exprColonEqExpr(p: var TParser): PNode =
|
||||
#| exprColonEqExpr = expr (':'|'=' expr)?
|
||||
var a = parseExpr(p)
|
||||
result = colonOrEquals(p, a)
|
||||
|
||||
proc exprList(p: var TParser, endTok: TTokType, result: PNode) =
|
||||
#| exprList = expr ^+ comma
|
||||
getTok(p)
|
||||
@@ -443,9 +446,76 @@ proc parseGStrLit(p: var TParser, a: PNode): PNode =
|
||||
getTok(p)
|
||||
else:
|
||||
result = a
|
||||
|
||||
proc identOrLiteral(p: var TParser): PNode =
|
||||
#| generalizedLit ::= GENERALIZED_STR_LIT | GENERALIZED_TRIPLESTR_LIT
|
||||
|
||||
type
|
||||
TPrimaryMode = enum pmNormal, pmTypeDesc, pmTypeDef, pmSkipSuffix
|
||||
|
||||
proc complexOrSimpleStmt(p: var TParser): PNode
|
||||
proc simpleExpr(p: var TParser, mode = pmNormal): PNode
|
||||
|
||||
proc semiStmtList(p: var TParser, result: PNode) =
|
||||
if p.tok.tokType == tkSemicolon:
|
||||
# '(;' enforces 'stmt' context:
|
||||
getTok(p)
|
||||
optInd(p, result)
|
||||
result.add(complexOrSimpleStmt(p))
|
||||
while p.tok.tokType == tkSemicolon:
|
||||
getTok(p)
|
||||
optInd(p, result)
|
||||
result.add(complexOrSimpleStmt(p))
|
||||
result.kind = nkStmtListExpr
|
||||
|
||||
proc parsePar(p: var TParser): PNode =
|
||||
#| parKeyw = 'discard' | 'include' | 'if' | 'while' | 'case' | 'try'
|
||||
#| | 'finally' | 'except' | 'for' | 'block' | 'const' | 'let'
|
||||
#| | 'when' | 'var' | 'bind' | 'mixin'
|
||||
#| par = '(' optInd (&parKeyw complexOrSimpleStmt ^+ ';'
|
||||
#| | simpleExpr ('=' expr (';' complexOrSimpleStmt ^+ ';' )? )?
|
||||
#| | (':' expr)? (',' (exprColonEqExpr comma?)*)? )?
|
||||
#| optPar ')'
|
||||
#
|
||||
# unfortunately it's ambiguous: (expr: expr) vs (exprStmt); however a
|
||||
# leading ';' could be used to enforce a 'stmt' context ...
|
||||
result = newNodeP(nkPar, p)
|
||||
getTok(p)
|
||||
optInd(p, result)
|
||||
if p.tok.tokType in {tkDiscard, tkInclude, tkIf, tkWhile, tkCase,
|
||||
tkTry, tkFinally, tkExcept, tkFor, tkBlock,
|
||||
tkConst, tkLet, tkWhen, tkVar, tkBind,
|
||||
tkMixin, tkSemicolon}:
|
||||
semiStmtList(p, result)
|
||||
elif p.tok.tokType != tkParRi:
|
||||
var a = simpleExpr(p)
|
||||
if p.tok.tokType == tkEquals:
|
||||
# special case: allow assignments
|
||||
getTok(p)
|
||||
optInd(p, result)
|
||||
let b = parseExpr(p)
|
||||
let asgn = newNodeI(nkAsgn, a.info, 2)
|
||||
asgn.sons[0] = a
|
||||
asgn.sons[1] = b
|
||||
result.add(asgn)
|
||||
elif p.tok.tokType == tkSemicolon:
|
||||
# stmt context:
|
||||
result.add(a)
|
||||
semiStmtList(p, result)
|
||||
else:
|
||||
a = colonOrEquals(p, a)
|
||||
result.add(a)
|
||||
if p.tok.tokType == tkComma:
|
||||
getTok(p)
|
||||
skipComment(p, a)
|
||||
while p.tok.tokType != tkParRi and p.tok.tokType != tkEof:
|
||||
var a = exprColonEqExpr(p)
|
||||
addSon(result, a)
|
||||
if p.tok.tokType != tkComma: break
|
||||
getTok(p)
|
||||
skipComment(p, a)
|
||||
optPar(p)
|
||||
eat(p, tkParRi)
|
||||
|
||||
proc identOrLiteral(p: var TParser, mode: TPrimaryMode): PNode =
|
||||
#| generalizedLit = GENERALIZED_STR_LIT | GENERALIZED_TRIPLESTR_LIT
|
||||
#| identOrLiteral = generalizedLit | symbol
|
||||
#| | INT_LIT | INT8_LIT | INT16_LIT | INT32_LIT | INT64_LIT
|
||||
#| | UINT_LIT | UINT8_LIT | UINT16_LIT | UINT32_LIT | UINT64_LIT
|
||||
@@ -453,7 +523,7 @@ proc identOrLiteral(p: var TParser): PNode =
|
||||
#| | STR_LIT | RSTR_LIT | TRIPLESTR_LIT
|
||||
#| | CHAR_LIT
|
||||
#| | NIL
|
||||
#| | tupleConstr | arrayConstr | setOrTableConstr
|
||||
#| | par | arrayConstr | setOrTableConstr
|
||||
#| | castExpr
|
||||
#| tupleConstr = '(' optInd (exprColonEqExpr comma?)* optPar ')'
|
||||
#| arrayConstr = '[' optInd (exprColonEqExpr comma?)* optPar ']'
|
||||
@@ -537,7 +607,10 @@ proc identOrLiteral(p: var TParser): PNode =
|
||||
getTok(p)
|
||||
of tkParLe:
|
||||
# () constructor
|
||||
result = exprColonEqExprList(p, nkPar, tkParRi)
|
||||
if mode in {pmTypeDesc, pmTypeDef}:
|
||||
result = exprColonEqExprList(p, nkPar, tkParRi)
|
||||
else:
|
||||
result = parsePar(p)
|
||||
of tkCurlyLe:
|
||||
# {} constructor
|
||||
result = setOrTableConstr(p)
|
||||
@@ -583,9 +656,6 @@ proc primarySuffix(p: var TParser, r: PNode): PNode =
|
||||
result = indexExprList(p, result, nkCurlyExpr, tkCurlyRi)
|
||||
else: break
|
||||
|
||||
type
|
||||
TPrimaryMode = enum pmNormal, pmTypeDesc, pmTypeDef, pmSkipSuffix
|
||||
|
||||
proc primary(p: var TParser, mode: TPrimaryMode): PNode
|
||||
|
||||
proc simpleExprAux(p: var TParser, limit: int, mode: TPrimaryMode): PNode =
|
||||
@@ -926,7 +996,7 @@ proc primary(p: var TParser, mode: TPrimaryMode): PNode =
|
||||
optInd(p, result)
|
||||
addSon(result, primary(p, pmNormal))
|
||||
else:
|
||||
result = identOrLiteral(p)
|
||||
result = identOrLiteral(p, mode)
|
||||
if mode != pmSkipSuffix:
|
||||
result = primarySuffix(p, result)
|
||||
|
||||
|
||||
@@ -58,10 +58,13 @@ proc fitNode(c: PContext, formal: PType, arg: PNode): PNode =
|
||||
result = copyNode(arg)
|
||||
result.typ = formal
|
||||
|
||||
var CommonTypeBegin = PType(kind: tyExpr)
|
||||
|
||||
proc commonType*(x, y: PType): PType =
|
||||
# new type relation that is used for array constructors,
|
||||
# if expressions, etc.:
|
||||
if x == nil: return y
|
||||
if x == nil: return x
|
||||
if y == nil: return y
|
||||
var a = skipTypes(x, {tyGenericInst})
|
||||
var b = skipTypes(y, {tyGenericInst})
|
||||
result = x
|
||||
|
||||
@@ -1458,26 +1458,73 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
|
||||
of mQuoteAst: result = semQuoteAst(c, n)
|
||||
else: result = semDirectOp(c, n, flags)
|
||||
|
||||
proc semIfExpr(c: PContext, n: PNode): PNode =
|
||||
result = n
|
||||
checkMinSonsLen(n, 2)
|
||||
var typ: PType = nil
|
||||
proc semWhen(c: PContext, n: PNode, semCheck = true): PNode =
|
||||
# If semCheck is set to false, ``when`` will return the verbatim AST of
|
||||
# the correct branch. Otherwise the AST will be passed through semStmt.
|
||||
result = nil
|
||||
|
||||
template setResult(e: expr) =
|
||||
if semCheck: result = semStmt(c, e) # do not open a new scope!
|
||||
else: result = e
|
||||
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
var it = n.sons[i]
|
||||
case it.kind
|
||||
of nkElifExpr:
|
||||
of nkElifBranch, nkElifExpr:
|
||||
checkSonsLen(it, 2)
|
||||
it.sons[0] = forceBool(c, semExprWithType(c, it.sons[0]))
|
||||
it.sons[1] = semExprWithType(c, it.sons[1])
|
||||
if typ == nil: typ = it.sons[1].typ
|
||||
else: it.sons[1] = fitNode(c, typ, it.sons[1])
|
||||
of nkElseExpr:
|
||||
var e = semConstExpr(c, it.sons[0])
|
||||
if e.kind != nkIntLit: InternalError(n.info, "semWhen")
|
||||
elif e.intVal != 0 and result == nil:
|
||||
setResult(it.sons[1])
|
||||
of nkElse, nkElseExpr:
|
||||
checkSonsLen(it, 1)
|
||||
it.sons[0] = semExprWithType(c, it.sons[0])
|
||||
if typ != nil: it.sons[0] = fitNode(c, typ, it.sons[0])
|
||||
else: InternalError(it.info, "semIfExpr")
|
||||
if result == nil:
|
||||
setResult(it.sons[0])
|
||||
else: illFormedAst(n)
|
||||
result.typ = typ
|
||||
if result == nil:
|
||||
result = newNodeI(nkNilLit, n.info)
|
||||
# The ``when`` statement implements the mechanism for platform dependent
|
||||
# code. Thus we try to ensure here consistent ID allocation after the
|
||||
# ``when`` statement.
|
||||
IDsynchronizationPoint(200)
|
||||
|
||||
|
||||
proc semExprBranch(c: PContext, n: PNode): PNode =
|
||||
result = semExpr(c, n)
|
||||
if result.typ != nil:
|
||||
# XXX tyGenericInst here?
|
||||
semProcvarCheck(c, result)
|
||||
if result.typ.kind == tyVar: result = newDeref(result)
|
||||
semDestructorCheck(c, result, {})
|
||||
|
||||
proc semIf(c: PContext, n: PNode): PNode =
|
||||
result = n
|
||||
var typ = CommonTypeBegin
|
||||
var hasElse = false
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
var it = n.sons[i]
|
||||
if it.len == 2:
|
||||
it.sons[0] = forceBool(c, semExprWithType(c, it.sons[0]))
|
||||
openScope(c.tab)
|
||||
it.sons[1] = semExprBranch(c, it.sons[1])
|
||||
typ = commonType(typ, it.sons[1].typ)
|
||||
closeScope(c.tab)
|
||||
elif it.len == 1:
|
||||
hasElse = true
|
||||
openScope(c.tab)
|
||||
it.sons[0] = semExprBranch(c, it.sons[0])
|
||||
typ = commonType(typ, it.sons[0].typ)
|
||||
closeScope(c.tab)
|
||||
else: illFormedAst(it)
|
||||
if isEmptyType(typ) or not hasElse:
|
||||
for it in n: discardCheck(it.lastSon)
|
||||
result.kind = nkIfStmt
|
||||
else:
|
||||
for it in n:
|
||||
let j = it.len-1
|
||||
it.sons[j] = fitNode(c, typ, it.sons[j])
|
||||
result.kind = nkIfExpr
|
||||
result.typ = typ
|
||||
|
||||
proc semSetConstr(c: PContext, n: PNode): PNode =
|
||||
result = newNodeI(nkCurly, n.info)
|
||||
@@ -1739,7 +1786,6 @@ proc fixImmediateParams(n: PNode): PNode =
|
||||
# the planned overload resolution reforms
|
||||
for i in 1 .. <safeLen(n):
|
||||
if n[i].kind == nkDo: n.sons[i] = n[i][bodyPos]
|
||||
|
||||
result = n
|
||||
|
||||
proc semExport(c: PContext, n: PNode): PNode =
|
||||
@@ -1910,7 +1956,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||
checkSonsLen(n, 1)
|
||||
n.sons[0] = semExpr(c, n.sons[0], flags)
|
||||
of nkCast: result = semCast(c, n)
|
||||
of nkIfExpr: result = semIfExpr(c, n)
|
||||
of nkIfExpr, nkIfStmt: result = semIf(c, n)
|
||||
of nkStmtListExpr: result = semStmtListExpr(c, n)
|
||||
of nkBlockExpr: result = semBlockExpr(c, n)
|
||||
of nkHiddenStdConv, nkHiddenSubConv, nkConv, nkHiddenCallConv:
|
||||
@@ -1936,7 +1982,6 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||
of nkLetSection: result = semVarOrLet(c, n, skLet)
|
||||
of nkConstSection: result = semConst(c, n)
|
||||
of nkTypeSection: result = SemTypeSection(c, n)
|
||||
of nkIfStmt: result = SemIf(c, n)
|
||||
of nkDiscardStmt: result = semDiscard(c, n)
|
||||
of nkWhileStmt: result = semWhile(c, n)
|
||||
of nkTryStmt: result = semTry(c, n)
|
||||
|
||||
@@ -378,18 +378,17 @@ proc getConstIfExpr(c: PSym, n: PNode): PNode =
|
||||
result = nil
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
var it = n.sons[i]
|
||||
case it.kind
|
||||
of nkElifExpr:
|
||||
if it.len == 2:
|
||||
var e = getConstExpr(c, it.sons[0])
|
||||
if e == nil: return nil
|
||||
if getOrdValue(e) != 0:
|
||||
if result == nil:
|
||||
result = getConstExpr(c, it.sons[1])
|
||||
if result == nil: return
|
||||
of nkElseExpr:
|
||||
elif it.len == 1:
|
||||
if result == nil: result = getConstExpr(c, it.sons[0])
|
||||
else: internalError(it.info, "getConstIfExpr()")
|
||||
|
||||
|
||||
proc partialAndExpr(c: PSym, n: PNode): PNode =
|
||||
# partial evaluation
|
||||
result = n
|
||||
|
||||
@@ -12,52 +12,6 @@
|
||||
|
||||
proc semCommand(c: PContext, n: PNode): PNode =
|
||||
result = semExprNoType(c, n)
|
||||
|
||||
proc semWhen(c: PContext, n: PNode, semCheck = true): PNode =
|
||||
# If semCheck is set to false, ``when`` will return the verbatim AST of
|
||||
# the correct branch. Otherwise the AST will be passed through semStmt.
|
||||
result = nil
|
||||
|
||||
template setResult(e: expr) =
|
||||
if semCheck: result = semStmt(c, e) # do not open a new scope!
|
||||
else: result = e
|
||||
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
var it = n.sons[i]
|
||||
case it.kind
|
||||
of nkElifBranch, nkElifExpr:
|
||||
checkSonsLen(it, 2)
|
||||
var e = semConstExpr(c, it.sons[0])
|
||||
if e.kind != nkIntLit: InternalError(n.info, "semWhen")
|
||||
elif e.intVal != 0 and result == nil:
|
||||
setResult(it.sons[1])
|
||||
of nkElse, nkElseExpr:
|
||||
checkSonsLen(it, 1)
|
||||
if result == nil:
|
||||
setResult(it.sons[0])
|
||||
else: illFormedAst(n)
|
||||
if result == nil:
|
||||
result = newNodeI(nkNilLit, n.info)
|
||||
# The ``when`` statement implements the mechanism for platform dependent
|
||||
# code. Thus we try to ensure here consistent ID allocation after the
|
||||
# ``when`` statement.
|
||||
IDsynchronizationPoint(200)
|
||||
|
||||
proc semIf(c: PContext, n: PNode): PNode =
|
||||
result = n
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
var it = n.sons[i]
|
||||
case it.kind
|
||||
of nkElifBranch:
|
||||
checkSonsLen(it, 2)
|
||||
it.sons[0] = forceBool(c, semExprWithType(c, it.sons[0]))
|
||||
openScope(c.tab)
|
||||
it.sons[1] = semStmt(c, it.sons[1])
|
||||
closeScope(c.tab)
|
||||
of nkElse:
|
||||
if sonsLen(it) == 1: it.sons[0] = semStmtScope(c, it.sons[0])
|
||||
else: illFormedAst(it)
|
||||
else: illFormedAst(n)
|
||||
|
||||
proc semDiscard(c: PContext, n: PNode): PNode =
|
||||
result = n
|
||||
|
||||
10
todo.txt
10
todo.txt
@@ -10,18 +10,16 @@ version 0.9.2
|
||||
- parser/grammar:
|
||||
* check that of branches can only receive even simpler expressions, don't
|
||||
allow 'of (var x = 23; nkIdent)'
|
||||
* allow (var x = 12; for i in ... ; x) construct
|
||||
* try except as an expression
|
||||
* document (var x = 12; for i in ... ; x) construct
|
||||
- make use of commonType relation in expressions
|
||||
- further expr/stmt unification:
|
||||
- nkIfStmt vs nkIfExpr
|
||||
- start with JS backend and support exprs everywhere
|
||||
- then enhance C backend
|
||||
- OR: do the temp stuff in transf
|
||||
- rewrite nkCaseExpr handling
|
||||
- try except as an expression
|
||||
|
||||
Bugs
|
||||
====
|
||||
|
||||
- new parser breaks docgen
|
||||
- docgen: sometimes effects are listed twice
|
||||
- 'result' is not properly cleaned for NRVO
|
||||
- instantiated generics are listed in error messages
|
||||
|
||||
Reference in New Issue
Block a user