command syntax is allowed in expressions

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

View file

@ -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:

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 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