command syntax is allowed in expressions
This commit is contained in:
parent
6fd008f23e
commit
79f59d18f1
4 changed files with 90 additions and 47 deletions
|
|
@ -34,6 +34,7 @@ type
|
||||||
firstTok: bool
|
firstTok: bool
|
||||||
lex*: TLexer # the lexer that is used for parsing
|
lex*: TLexer # the lexer that is used for parsing
|
||||||
tok*: TToken # the current token
|
tok*: TToken # the current token
|
||||||
|
inPragma: int
|
||||||
|
|
||||||
proc parseAll*(p: var TParser): PNode
|
proc parseAll*(p: var TParser): PNode
|
||||||
proc openParser*(p: var TParser, filename: string, inputstream: PLLStream)
|
proc openParser*(p: var TParser, filename: string, inputstream: PLLStream)
|
||||||
|
|
@ -518,14 +519,14 @@ proc parsePar(p: var TParser): PNode =
|
||||||
eat(p, tkParRi)
|
eat(p, tkParRi)
|
||||||
|
|
||||||
proc identOrLiteral(p: var TParser, mode: TPrimaryMode): PNode =
|
proc identOrLiteral(p: var TParser, mode: TPrimaryMode): PNode =
|
||||||
#| generalizedLit = GENERALIZED_STR_LIT | GENERALIZED_TRIPLESTR_LIT
|
#| literal = | INT_LIT | INT8_LIT | INT16_LIT | INT32_LIT | INT64_LIT
|
||||||
#| identOrLiteral = generalizedLit | symbol
|
|
||||||
#| | INT_LIT | INT8_LIT | INT16_LIT | INT32_LIT | INT64_LIT
|
|
||||||
#| | UINT_LIT | UINT8_LIT | UINT16_LIT | UINT32_LIT | UINT64_LIT
|
#| | UINT_LIT | UINT8_LIT | UINT16_LIT | UINT32_LIT | UINT64_LIT
|
||||||
#| | FLOAT_LIT | FLOAT32_LIT | FLOAT64_LIT
|
#| | FLOAT_LIT | FLOAT32_LIT | FLOAT64_LIT
|
||||||
#| | STR_LIT | RSTR_LIT | TRIPLESTR_LIT
|
#| | STR_LIT | RSTR_LIT | TRIPLESTR_LIT
|
||||||
#| | CHAR_LIT
|
#| | CHAR_LIT
|
||||||
#| | NIL
|
#| | NIL
|
||||||
|
#| generalizedLit = GENERALIZED_STR_LIT | GENERALIZED_TRIPLESTR_LIT
|
||||||
|
#| identOrLiteral = generalizedLit | symbol | literal
|
||||||
#| | par | arrayConstr | setOrTableConstr
|
#| | par | arrayConstr | setOrTableConstr
|
||||||
#| | castExpr
|
#| | castExpr
|
||||||
#| tupleConstr = '(' optInd (exprColonEqExpr comma?)* optPar ')'
|
#| tupleConstr = '(' optInd (exprColonEqExpr comma?)* optPar ')'
|
||||||
|
|
@ -634,12 +635,15 @@ proc namedParams(p: var TParser, callee: PNode,
|
||||||
addSon(result, a)
|
addSon(result, a)
|
||||||
exprColonEqExprListAux(p, endTok, result)
|
exprColonEqExprListAux(p, endTok, result)
|
||||||
|
|
||||||
|
proc parseMacroColon(p: var TParser, x: PNode): PNode
|
||||||
proc primarySuffix(p: var TParser, r: PNode): PNode =
|
proc primarySuffix(p: var TParser, r: PNode): PNode =
|
||||||
#| primarySuffix = '(' (exprColonEqExpr comma?)* ')' doBlocks?
|
#| primarySuffix = '(' (exprColonEqExpr comma?)* ')' doBlocks?
|
||||||
#| | doBlocks
|
#| | doBlocks
|
||||||
#| | '.' optInd ('type' | 'addr' | symbol) generalizedLit?
|
#| | '.' optInd ('type' | 'addr' | symbol) generalizedLit?
|
||||||
#| | '[' optInd indexExprList optPar ']'
|
#| | '[' optInd indexExprList optPar ']'
|
||||||
#| | '{' optInd indexExprList optPar '}'
|
#| | '{' optInd indexExprList optPar '}'
|
||||||
|
#| | &( '`'|IDENT|literal|'cast') expr ^+ ',' # command syntax
|
||||||
|
#| (doBlock | macroColon)?
|
||||||
result = r
|
result = r
|
||||||
while p.tok.indent < 0:
|
while p.tok.indent < 0:
|
||||||
case p.tok.tokType
|
case p.tok.tokType
|
||||||
|
|
@ -661,7 +665,26 @@ proc primarySuffix(p: var TParser, r: PNode): PNode =
|
||||||
result = namedParams(p, result, nkBracketExpr, tkBracketRi)
|
result = namedParams(p, result, nkBracketExpr, tkBracketRi)
|
||||||
of tkCurlyLe:
|
of tkCurlyLe:
|
||||||
result = namedParams(p, result, nkCurlyExpr, tkCurlyRi)
|
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 primary(p: var TParser, mode: TPrimaryMode): PNode
|
||||||
|
|
||||||
|
|
@ -713,6 +736,7 @@ proc parseIfExpr(p: var TParser, kind: TNodeKind): PNode =
|
||||||
proc parsePragma(p: var TParser): PNode =
|
proc parsePragma(p: var TParser): PNode =
|
||||||
#| pragma = '{.' optInd (exprColonExpr comma?)* optPar ('.}' | '}')
|
#| pragma = '{.' optInd (exprColonExpr comma?)* optPar ('.}' | '}')
|
||||||
result = newNodeP(nkPragma, p)
|
result = newNodeP(nkPragma, p)
|
||||||
|
inc p.inPragma
|
||||||
getTok(p)
|
getTok(p)
|
||||||
optInd(p, result)
|
optInd(p, result)
|
||||||
while p.tok.tokType notin {tkCurlyDotRi, tkCurlyRi, tkEof}:
|
while p.tok.tokType notin {tkCurlyDotRi, tkCurlyRi, tkEof}:
|
||||||
|
|
@ -724,6 +748,7 @@ proc parsePragma(p: var TParser): PNode =
|
||||||
optPar(p)
|
optPar(p)
|
||||||
if p.tok.tokType in {tkCurlyDotRi, tkCurlyRi}: getTok(p)
|
if p.tok.tokType in {tkCurlyDotRi, tkCurlyRi}: getTok(p)
|
||||||
else: parMessage(p, errTokenExpected, ".}")
|
else: parMessage(p, errTokenExpected, ".}")
|
||||||
|
dec p.inPragma
|
||||||
|
|
||||||
proc identVis(p: var TParser): PNode =
|
proc identVis(p: var TParser): PNode =
|
||||||
#| identVis = symbol opr? # postfix position
|
#| identVis = symbol opr? # postfix position
|
||||||
|
|
@ -1031,39 +1056,12 @@ proc makeCall(n: PNode): PNode =
|
||||||
result = newNodeI(nkCall, n.info)
|
result = newNodeI(nkCall, n.info)
|
||||||
result.add n
|
result.add n
|
||||||
|
|
||||||
proc parseExprStmt(p: var TParser): PNode =
|
proc parseMacroColon(p: var TParser, x: PNode): PNode =
|
||||||
#| exprStmt = simpleExpr
|
#| macroColon = ':' stmt? ( IND{=} 'of' exprList ':' stmt
|
||||||
#| (( '=' optInd expr )
|
|
||||||
#| / ( expr ^+ comma
|
|
||||||
#| doBlocks
|
|
||||||
#| / ':' stmt? ( IND{=} 'of' exprList ':' stmt
|
|
||||||
#| | IND{=} 'elif' expr ':' stmt
|
#| | IND{=} 'elif' expr ':' stmt
|
||||||
#| | IND{=} 'except' exprList ':' stmt
|
#| | IND{=} 'except' exprList ':' stmt
|
||||||
#| | IND{=} 'else' ':' stmt )*
|
#| | IND{=} 'else' ':' stmt )*
|
||||||
#| ))?
|
result = x
|
||||||
var a = simpleExpr(p)
|
|
||||||
if p.tok.tokType == tkEquals:
|
|
||||||
getTok(p)
|
|
||||||
optInd(p, result)
|
|
||||||
var b = parseExpr(p)
|
|
||||||
result = newNodeI(nkAsgn, a.info)
|
|
||||||
addSon(result, a)
|
|
||||||
addSon(result, b)
|
|
||||||
else:
|
|
||||||
if p.tok.indent < 0 and isExprStart(p):
|
|
||||||
result = newNode(nkCommand, a.info, @[a])
|
|
||||||
while true:
|
|
||||||
var e = parseExpr(p)
|
|
||||||
addSon(result, e)
|
|
||||||
if p.tok.tokType != tkComma: break
|
|
||||||
getTok(p)
|
|
||||||
optInd(p, result)
|
|
||||||
else:
|
|
||||||
result = a
|
|
||||||
if p.tok.tokType == tkDo and p.tok.indent < 0:
|
|
||||||
result = makeCall(result)
|
|
||||||
parseDoBlocks(p, result)
|
|
||||||
return result
|
|
||||||
if p.tok.tokType == tkColon and p.tok.indent < 0:
|
if p.tok.tokType == tkColon and p.tok.indent < 0:
|
||||||
result = makeCall(result)
|
result = makeCall(result)
|
||||||
getTok(p)
|
getTok(p)
|
||||||
|
|
@ -1096,6 +1094,38 @@ proc parseExprStmt(p: var TParser): PNode =
|
||||||
addSon(result, b)
|
addSon(result, b)
|
||||||
if b.kind == nkElse: break
|
if b.kind == nkElse: break
|
||||||
|
|
||||||
|
proc parseExprStmt(p: var TParser): PNode =
|
||||||
|
#| exprStmt = simpleExpr
|
||||||
|
#| (( '=' optInd expr )
|
||||||
|
#| / ( expr ^+ comma
|
||||||
|
#| doBlocks
|
||||||
|
#| / macroColon
|
||||||
|
#| ))?
|
||||||
|
var a = simpleExpr(p)
|
||||||
|
if p.tok.tokType == tkEquals:
|
||||||
|
getTok(p)
|
||||||
|
optInd(p, result)
|
||||||
|
var b = parseExpr(p)
|
||||||
|
result = newNodeI(nkAsgn, a.info)
|
||||||
|
addSon(result, a)
|
||||||
|
addSon(result, b)
|
||||||
|
else:
|
||||||
|
if p.tok.indent < 0 and isExprStart(p):
|
||||||
|
result = newNode(nkCommand, a.info, @[a])
|
||||||
|
while true:
|
||||||
|
var e = parseExpr(p)
|
||||||
|
addSon(result, e)
|
||||||
|
if p.tok.tokType != tkComma: break
|
||||||
|
getTok(p)
|
||||||
|
optInd(p, result)
|
||||||
|
else:
|
||||||
|
result = a
|
||||||
|
if p.tok.tokType == tkDo and p.tok.indent < 0:
|
||||||
|
result = makeCall(result)
|
||||||
|
parseDoBlocks(p, result)
|
||||||
|
return result
|
||||||
|
result = parseMacroColon(p, result)
|
||||||
|
|
||||||
proc parseModuleName(p: var TParser, kind: TNodeKind): PNode =
|
proc parseModuleName(p: var TParser, kind: TNodeKind): PNode =
|
||||||
result = parseExpr(p)
|
result = parseExpr(p)
|
||||||
when false:
|
when false:
|
||||||
|
|
|
||||||
12
tests/parser/tcommand_as_expr.nim
Normal file
12
tests/parser/tcommand_as_expr.nim
Normal 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
|
||||||
|
|
||||||
|
|
@ -28,8 +28,8 @@ Changes affecting backwards compatibility
|
||||||
require an error code to be passed to them. This error code can be retrieved
|
require an error code to be passed to them. This error code can be retrieved
|
||||||
using the new ``OSLastError`` proc.
|
using the new ``OSLastError`` proc.
|
||||||
- ``os.parentDir`` now returns "" if there is no parent dir.
|
- ``os.parentDir`` now returns "" if there is no parent dir.
|
||||||
- In CGI scripts stacktraces are shown user only if cgi.setStackTraceStdout
|
- In CGI scripts stacktraces are shown to the user only
|
||||||
is used.
|
if ``cgi.setStackTraceStdout`` is used.
|
||||||
- The symbol binding rules for clean templates changed: ``bind`` for any
|
- 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
|
symbol that's not a parameter is now the default. ``mixin`` can be used
|
||||||
to require instantiation scope for a symbol.
|
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
|
- Added a new ``delegator pragma`` for handling calls to missing procs and
|
||||||
fields at compile-time.
|
fields at compile-time.
|
||||||
- The overload resolution now supports ``static[T]`` params that must be
|
- 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.
|
- Support for user-defined type classes has been added.
|
||||||
|
- The *command syntax* is supported in a lot more contexts.
|
||||||
|
|
||||||
|
|
||||||
Tools improvements
|
Tools improvements
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue