command syntax is allowed in expressions

This commit is contained in:
Araq
2014-01-20 08:29:02 +01:00
parent 6fd008f23e
commit 79f59d18f1
4 changed files with 90 additions and 47 deletions

View File

@@ -34,6 +34,7 @@ type
firstTok: bool
lex*: TLexer # the lexer that is used for parsing
tok*: TToken # the current token
inPragma: int
proc parseAll*(p: var TParser): PNode
proc openParser*(p: var TParser, filename: string, inputstream: PLLStream)
@@ -518,14 +519,14 @@ proc parsePar(p: var TParser): PNode =
eat(p, tkParRi)
proc identOrLiteral(p: var TParser, mode: TPrimaryMode): PNode =
#| literal = | INT_LIT | INT8_LIT | INT16_LIT | INT32_LIT | INT64_LIT
#| | UINT_LIT | UINT8_LIT | UINT16_LIT | UINT32_LIT | UINT64_LIT
#| | FLOAT_LIT | FLOAT32_LIT | FLOAT64_LIT
#| | STR_LIT | RSTR_LIT | TRIPLESTR_LIT
#| | CHAR_LIT
#| | NIL
#| 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
#| | FLOAT_LIT | FLOAT32_LIT | FLOAT64_LIT
#| | STR_LIT | RSTR_LIT | TRIPLESTR_LIT
#| | CHAR_LIT
#| | NIL
#| identOrLiteral = generalizedLit | symbol | literal
#| | par | arrayConstr | setOrTableConstr
#| | castExpr
#| tupleConstr = '(' optInd (exprColonEqExpr comma?)* optPar ')'
@@ -634,12 +635,15 @@ proc namedParams(p: var TParser, callee: PNode,
addSon(result, a)
exprColonEqExprListAux(p, endTok, result)
proc parseMacroColon(p: var TParser, x: PNode): PNode
proc primarySuffix(p: var TParser, r: PNode): PNode =
#| primarySuffix = '(' (exprColonEqExpr comma?)* ')' doBlocks?
#| | doBlocks
#| | '.' optInd ('type' | 'addr' | symbol) generalizedLit?
#| | '[' optInd indexExprList optPar ']'
#| | '{' optInd indexExprList optPar '}'
#| | &( '`'|IDENT|literal|'cast') expr ^+ ',' # command syntax
#| (doBlock | macroColon)?
result = r
while p.tok.indent < 0:
case p.tok.tokType
@@ -661,8 +665,27 @@ proc primarySuffix(p: var TParser, r: PNode): PNode =
result = namedParams(p, result, nkBracketExpr, tkBracketRi)
of tkCurlyLe:
result = namedParams(p, result, nkCurlyExpr, tkCurlyRi)
else: break
of tkSymbol, tkAccent, tkIntLit..tkCharLit, tkNil, tkCast:
if p.inPragma == 0:
# actually parsing {.push hints:off.} as {.push(hints:off).} is a sweet
# solution, but pragmas.nim can't handle that
let a = result
result = newNodeP(nkCommand, p)
addSon(result, a)
while p.tok.tokType != tkEof:
let a = parseExpr(p)
addSon(result, a)
if p.tok.tokType != tkComma: break
getTok(p)
optInd(p, a)
if p.tok.tokType == tkDo:
parseDoBlocks(p, result)
else:
result = parseMacroColon(p, result)
break
else:
break
proc primary(p: var TParser, mode: TPrimaryMode): PNode
proc simpleExprAux(p: var TParser, limit: int, mode: TPrimaryMode): PNode =
@@ -713,6 +736,7 @@ proc parseIfExpr(p: var TParser, kind: TNodeKind): PNode =
proc parsePragma(p: var TParser): PNode =
#| pragma = '{.' optInd (exprColonExpr comma?)* optPar ('.}' | '}')
result = newNodeP(nkPragma, p)
inc p.inPragma
getTok(p)
optInd(p, result)
while p.tok.tokType notin {tkCurlyDotRi, tkCurlyRi, tkEof}:
@@ -724,6 +748,7 @@ proc parsePragma(p: var TParser): PNode =
optPar(p)
if p.tok.tokType in {tkCurlyDotRi, tkCurlyRi}: getTok(p)
else: parMessage(p, errTokenExpected, ".}")
dec p.inPragma
proc identVis(p: var TParser): PNode =
#| identVis = symbol opr? # postfix position
@@ -1031,15 +1056,50 @@ proc makeCall(n: PNode): PNode =
result = newNodeI(nkCall, n.info)
result.add n
proc parseMacroColon(p: var TParser, x: PNode): PNode =
#| macroColon = ':' stmt? ( IND{=} 'of' exprList ':' stmt
#| | IND{=} 'elif' expr ':' stmt
#| | IND{=} 'except' exprList ':' stmt
#| | IND{=} 'else' ':' stmt )*
result = x
if p.tok.tokType == tkColon and p.tok.indent < 0:
result = makeCall(result)
getTok(p)
skipComment(p, result)
if p.tok.tokType notin {tkOf, tkElif, tkElse, tkExcept}:
let body = parseStmt(p)
addSon(result, newProcNode(nkDo, body.info, body))
while sameInd(p):
var b: PNode
case p.tok.tokType
of tkOf:
b = newNodeP(nkOfBranch, p)
exprList(p, tkColon, b)
of tkElif:
b = newNodeP(nkElifBranch, p)
getTok(p)
optInd(p, b)
addSon(b, parseExpr(p))
eat(p, tkColon)
of tkExcept:
b = newNodeP(nkExceptBranch, p)
exprList(p, tkColon, b)
skipComment(p, b)
of tkElse:
b = newNodeP(nkElse, p)
getTok(p)
eat(p, tkColon)
else: break
addSon(b, parseStmt(p))
addSon(result, b)
if b.kind == nkElse: break
proc parseExprStmt(p: var TParser): PNode =
#| exprStmt = simpleExpr
#| (( '=' optInd expr )
#| / ( expr ^+ comma
#| doBlocks
#| / ':' stmt? ( IND{=} 'of' exprList ':' stmt
#| | IND{=} 'elif' expr ':' stmt
#| | IND{=} 'except' exprList ':' stmt
#| | IND{=} 'else' ':' stmt )*
#| / macroColon
#| ))?
var a = simpleExpr(p)
if p.tok.tokType == tkEquals:
@@ -1064,37 +1124,7 @@ proc parseExprStmt(p: var TParser): PNode =
result = makeCall(result)
parseDoBlocks(p, result)
return result
if p.tok.tokType == tkColon and p.tok.indent < 0:
result = makeCall(result)
getTok(p)
skipComment(p, result)
if p.tok.tokType notin {tkOf, tkElif, tkElse, tkExcept}:
let body = parseStmt(p)
addSon(result, newProcNode(nkDo, body.info, body))
while sameInd(p):
var b: PNode
case p.tok.tokType
of tkOf:
b = newNodeP(nkOfBranch, p)
exprList(p, tkColon, b)
of tkElif:
b = newNodeP(nkElifBranch, p)
getTok(p)
optInd(p, b)
addSon(b, parseExpr(p))
eat(p, tkColon)
of tkExcept:
b = newNodeP(nkExceptBranch, p)
exprList(p, tkColon, b)
skipComment(p, b)
of tkElse:
b = newNodeP(nkElse, p)
getTok(p)
eat(p, tkColon)
else: break
addSon(b, parseStmt(p))
addSon(result, b)
if b.kind == nkElse: break
result = parseMacroColon(p, result)
proc parseModuleName(p: var TParser, kind: TNodeKind): PNode =
result = parseExpr(p)

View File

@@ -0,0 +1,12 @@
discard """
output: "12"
"""
proc foo(x: int): int = x-1
proc foo(x, y: int): int = x-y
let x = foo 7.foo, # comment here
foo(1, foo 8)
# 12 = 6 - -6
echo x

View File

@@ -28,8 +28,8 @@ Changes affecting backwards compatibility
require an error code to be passed to them. This error code can be retrieved
using the new ``OSLastError`` proc.
- ``os.parentDir`` now returns "" if there is no parent dir.
- In CGI scripts stacktraces are shown user only if cgi.setStackTraceStdout
is used.
- In CGI scripts stacktraces are shown to the user only
if ``cgi.setStackTraceStdout`` is used.
- The symbol binding rules for clean templates changed: ``bind`` for any
symbol that's not a parameter is now the default. ``mixin`` can be used
to require instantiation scope for a symbol.
@@ -71,8 +71,9 @@ Language Additions
- Added a new ``delegator pragma`` for handling calls to missing procs and
fields at compile-time.
- The overload resolution now supports ``static[T]`` params that must be
evaluatable at compile-time.
evaluable at compile-time.
- Support for user-defined type classes has been added.
- The *command syntax* is supported in a lot more contexts.
Tools improvements