lift parameter-less do block to lambdas
This commit is contained in:
parent
f7b10e213b
commit
a3f19c87fb
10 changed files with 46 additions and 26 deletions
|
|
@ -452,6 +452,7 @@ type
|
||||||
nfExprCall # this is an attempt to call a regular expression
|
nfExprCall # this is an attempt to call a regular expression
|
||||||
nfIsRef # this node is a 'ref' node; used for the VM
|
nfIsRef # this node is a 'ref' node; used for the VM
|
||||||
nfPreventCg # this node should be ignored by the codegen
|
nfPreventCg # this node should be ignored by the codegen
|
||||||
|
nfBlockArg # this a stmtlist appearing in a call (e.g. a do block)
|
||||||
|
|
||||||
TNodeFlags* = set[TNodeFlag]
|
TNodeFlags* = set[TNodeFlag]
|
||||||
TTypeFlag* = enum # keep below 32 for efficiency reasons (now: 30)
|
TTypeFlag* = enum # keep below 32 for efficiency reasons (now: 30)
|
||||||
|
|
|
||||||
|
|
@ -90,11 +90,7 @@ proc evalTemplateArgs(n: PNode, s: PSym; fromHlo: bool): PNode =
|
||||||
|
|
||||||
result = newNodeI(nkArgList, n.info)
|
result = newNodeI(nkArgList, n.info)
|
||||||
for i in 1 .. givenRegularParams:
|
for i in 1 .. givenRegularParams:
|
||||||
let p = n[i]
|
result.addSon n[i]
|
||||||
if p != nil and p.kind == nkDo and s.typ.sons[i].kind in {tyStmt, tyExpr}:
|
|
||||||
result.addSon p[bodyPos]
|
|
||||||
else:
|
|
||||||
result.addSon p
|
|
||||||
|
|
||||||
# handle parameters with default values, which were
|
# handle parameters with default values, which were
|
||||||
# not supplied by the user
|
# not supplied by the user
|
||||||
|
|
|
||||||
|
|
@ -1170,13 +1170,11 @@ proc postExprBlocks(p: var TParser, x: PNode): PNode =
|
||||||
skipComment(p, result)
|
skipComment(p, result)
|
||||||
if p.tok.tokType notin {tkOf, tkElif, tkElse, tkExcept}:
|
if p.tok.tokType notin {tkOf, tkElif, tkElse, tkExcept}:
|
||||||
var stmtList = newNodeP(nkStmtList, p)
|
var stmtList = newNodeP(nkStmtList, p)
|
||||||
let body = parseStmt(p)
|
stmtList.add parseStmt(p)
|
||||||
stmtList.add body
|
# to keep backwards compatibility (see tests/vm/tstringnil)
|
||||||
|
if stmtList[0].kind == nkStmtList: stmtList = stmtList[0]
|
||||||
if stmtList.len == 1 and stmtList[0].kind == nkStmtList:
|
|
||||||
# to keep backwards compatibility (see tests/vm/tstringnil)
|
|
||||||
stmtList = stmtList[0]
|
|
||||||
|
|
||||||
|
stmtList.flags.incl nfBlockArg
|
||||||
if openingParams.kind != nkEmpty:
|
if openingParams.kind != nkEmpty:
|
||||||
result.add newProcNode(nkDo, stmtList.info, stmtList,
|
result.add newProcNode(nkDo, stmtList.info, stmtList,
|
||||||
params = openingParams, pragmas = openingPragmas)
|
params = openingParams, pragmas = openingPragmas)
|
||||||
|
|
@ -1209,7 +1207,10 @@ proc postExprBlocks(p: var TParser, x: PNode): PNode =
|
||||||
else: break
|
else: break
|
||||||
eat(p, tkColon)
|
eat(p, tkColon)
|
||||||
nextBlock.addSon parseStmt(p)
|
nextBlock.addSon parseStmt(p)
|
||||||
|
|
||||||
|
nextBlock.flags.incl nfBlockArg
|
||||||
result.add nextBlock
|
result.add nextBlock
|
||||||
|
|
||||||
if nextBlock.kind == nkElse: break
|
if nextBlock.kind == nkElse: break
|
||||||
else:
|
else:
|
||||||
if openingParams.kind != nkEmpty:
|
if openingParams.kind != nkEmpty:
|
||||||
|
|
|
||||||
|
|
@ -1652,7 +1652,11 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
else: discard
|
else: discard
|
||||||
|
|
||||||
if result.len == 1 and
|
if result.len == 1 and
|
||||||
c.inTypeClass == 0 and # concept bodies should be preserved as a stmt list
|
# concept bodies should be preserved as a stmt list:
|
||||||
|
c.inTypeClass == 0 and
|
||||||
|
# also, don't make life complicated for macros.
|
||||||
|
# they will always expect a proper stmtlist:
|
||||||
|
nfBlockArg notin n.flags and
|
||||||
result.sons[0].kind != nkDefer:
|
result.sons[0].kind != nkDefer:
|
||||||
result = result.sons[0]
|
result = result.sons[0]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1259,7 +1259,6 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||||
|
|
||||||
of tyGenericInvocation:
|
of tyGenericInvocation:
|
||||||
var x = a.skipGenericAlias
|
var x = a.skipGenericAlias
|
||||||
|
|
||||||
# XXX: This is very hacky. It should be moved back into liftTypeParam
|
# XXX: This is very hacky. It should be moved back into liftTypeParam
|
||||||
if x.kind == tyGenericInst and c.calleeSym != nil and c.calleeSym.kind == skProc:
|
if x.kind == tyGenericInst and c.calleeSym != nil and c.calleeSym.kind == skProc:
|
||||||
let inst = prepareMetatypeForSigmatch(c.c, c.bindings, c.call.info, f)
|
let inst = prepareMetatypeForSigmatch(c.c, c.bindings, c.call.info, f)
|
||||||
|
|
@ -1639,6 +1638,10 @@ proc incMatches(m: var TCandidate; r: TTypeRelation; convMatch = 1) =
|
||||||
of isEqual: inc(m.exactMatches)
|
of isEqual: inc(m.exactMatches)
|
||||||
of isNone: discard
|
of isNone: discard
|
||||||
|
|
||||||
|
template matchesVoidProc(t: PType): bool =
|
||||||
|
(t.kind == tyProc and t.len == 1 and t.sons[0] == nil) or
|
||||||
|
(t.kind == tyBuiltInTypeClass and t.sons[0].kind == tyProc)
|
||||||
|
|
||||||
proc paramTypesMatchAux(m: var TCandidate, f, a: PType,
|
proc paramTypesMatchAux(m: var TCandidate, f, a: PType,
|
||||||
argSemantized, argOrig: PNode): PNode =
|
argSemantized, argOrig: PNode): PNode =
|
||||||
var
|
var
|
||||||
|
|
@ -1775,6 +1778,14 @@ proc paramTypesMatchAux(m: var TCandidate, f, a: PType,
|
||||||
inc(m.genericMatches)
|
inc(m.genericMatches)
|
||||||
m.fauxMatch = a.kind
|
m.fauxMatch = a.kind
|
||||||
return arg
|
return arg
|
||||||
|
elif a.kind == tyVoid and f.matchesVoidProc and argOrig.kind == nkStmtList:
|
||||||
|
# lift do blocks without params to lambdas
|
||||||
|
let lifted = c.semExpr(c, newProcNode(nkDo, argOrig.info, argOrig), {})
|
||||||
|
if f.kind == tyBuiltInTypeClass:
|
||||||
|
inc m.genericMatches
|
||||||
|
put(m, f, lifted.typ)
|
||||||
|
inc m.convMatches
|
||||||
|
return implicitConv(nkHiddenStdConv, f, lifted, m, c)
|
||||||
result = userConvMatch(c, m, f, a, arg)
|
result = userConvMatch(c, m, f, a, arg)
|
||||||
# check for a base type match, which supports varargs[T] without []
|
# check for a base type match, which supports varargs[T] without []
|
||||||
# constructor in a call:
|
# constructor in a call:
|
||||||
|
|
|
||||||
|
|
@ -1599,8 +1599,7 @@ proc setupMacroParam(x: PNode, typ: PType): TFullReg =
|
||||||
putIntoReg(result, x)
|
putIntoReg(result, x)
|
||||||
else:
|
else:
|
||||||
result.kind = rkNode
|
result.kind = rkNode
|
||||||
var n = if typ.kind in {tyStmt,tyExpr} and x.kind == nkDo: x[bodyPos]
|
var n = x
|
||||||
else: x
|
|
||||||
if n.kind in {nkHiddenSubConv, nkHiddenStdConv}: n = n.sons[1]
|
if n.kind in {nkHiddenSubConv, nkHiddenStdConv}: n = n.sons[1]
|
||||||
n = n.canonValue
|
n = n.canonValue
|
||||||
n.flags.incl nfIsRef
|
n.flags.incl nfIsRef
|
||||||
|
|
|
||||||
|
|
@ -112,6 +112,12 @@ proc toJs*[T](val: T): JsObject {. importcpp: "(#)" .}
|
||||||
|
|
||||||
template toJs*(s: string): JsObject = cstring(s).toJs
|
template toJs*(s: string): JsObject = cstring(s).toJs
|
||||||
|
|
||||||
|
macro jsFromAst*(n: untyped): untyped =
|
||||||
|
result = n
|
||||||
|
if n.kind == nnkStmtList:
|
||||||
|
result = newProc(procType = nnkDo, body = result)
|
||||||
|
return quote: toJs(`result`)
|
||||||
|
|
||||||
proc `&`*(a, b: cstring): cstring {.importcpp: "(# + #)".}
|
proc `&`*(a, b: cstring): cstring {.importcpp: "(# + #)".}
|
||||||
## Concatenation operator for JavaScript strings
|
## Concatenation operator for JavaScript strings
|
||||||
|
|
||||||
|
|
@ -220,7 +226,7 @@ macro `.=`*(obj: JsObject, field: static[cstring], value: untyped): untyped =
|
||||||
|
|
||||||
macro `.()`*(obj: JsObject,
|
macro `.()`*(obj: JsObject,
|
||||||
field: static[cstring],
|
field: static[cstring],
|
||||||
args: varargs[JsObject, toJs]): JsObject =
|
args: varargs[JsObject, jsFromAst]): JsObject =
|
||||||
## Experimental "method call" operator for type JsObject.
|
## Experimental "method call" operator for type JsObject.
|
||||||
## Takes the name of a method of the JavaScript object (`field`) and calls
|
## Takes the name of a method of the JavaScript object (`field`) and calls
|
||||||
## it with `args` as arguments, returning a JsObject (which may be discarded,
|
## it with `args` as arguments, returning a JsObject (which may be discarded,
|
||||||
|
|
@ -244,7 +250,7 @@ macro `.()`*(obj: JsObject,
|
||||||
if not mangledNames.hasKey($field):
|
if not mangledNames.hasKey($field):
|
||||||
mangledNames[$field] = $mangleJsName(field)
|
mangledNames[$field] = $mangleJsName(field)
|
||||||
importString = "#." & mangledNames[$field] & "(@)"
|
importString = "#." & mangledNames[$field] & "(@)"
|
||||||
result = quote do:
|
result = quote:
|
||||||
proc helper(o: JsObject): JsObject
|
proc helper(o: JsObject): JsObject
|
||||||
{. importcpp: `importString`, gensym, discardable .}
|
{. importcpp: `importString`, gensym, discardable .}
|
||||||
helper(`obj`)
|
helper(`obj`)
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ discard """
|
||||||
import macros
|
import macros
|
||||||
|
|
||||||
macro mixer(n: typed): untyped =
|
macro mixer(n: typed): untyped =
|
||||||
expectKind(n, nnkCharLit)
|
expectKind(n[0], nnkCharLit)
|
||||||
|
|
||||||
mixer:
|
mixer:
|
||||||
echo "owh"
|
echo "owh"
|
||||||
|
|
|
||||||
|
|
@ -35,11 +35,11 @@ b.onFocusLost:
|
||||||
b.onFocusLost do:
|
b.onFocusLost do:
|
||||||
echo "lost focus 2"
|
echo "lost focus 2"
|
||||||
|
|
||||||
b.onUserEvent("UserEvent 1") do:
|
b.onUserEvent "UserEvent 1" do:
|
||||||
discard
|
discard
|
||||||
|
|
||||||
b.onUserEvent("UserEvent 2"):
|
b.onUserEvent "UserEvent 2":
|
||||||
discard
|
discard
|
||||||
|
|
||||||
b.onUserEvent("UserEvent 3", () => echo "event 2")
|
b.onUserEvent("UserEvent 3", () => echo "event 3")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
discard """
|
discard """
|
||||||
output: '''true
|
output: '''
|
||||||
|
true
|
||||||
true
|
true
|
||||||
true
|
true
|
||||||
true
|
true
|
||||||
|
|
@ -19,7 +20,8 @@ true
|
||||||
2
|
2
|
||||||
12
|
12
|
||||||
Event { name: 'click: test' }
|
Event { name: 'click: test' }
|
||||||
Event { name: 'reloaded: test' }'''
|
Event { name: 'reloaded: test' }
|
||||||
|
'''
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import macros, jsffi, jsconsole
|
import macros, jsffi, jsconsole
|
||||||
|
|
@ -306,6 +308,6 @@ block:
|
||||||
on("click") do (e: Event):
|
on("click") do (e: Event):
|
||||||
console.log e
|
console.log e
|
||||||
|
|
||||||
jslib.on("reloaded") do:
|
jslib.on "reloaded" do:
|
||||||
console.log jsarguments[0]
|
console.log jsarguments[0]
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue