mirror of
https://github.com/nim-lang/Nim.git
synced 2026-01-05 20:47:53 +00:00
Merge branch 'master' of github.com:Araq/Nimrod
This commit is contained in:
@@ -415,7 +415,7 @@ type
|
||||
mDefined, mDefinedInScope, mCompiles,
|
||||
mLow, mHigh, mSizeOf, mTypeTrait, mIs, mOf,
|
||||
mEcho, mShallowCopy, mSlurp, mStaticExec,
|
||||
mParseExprToAst, mParseStmtToAst, mExpandToAst,
|
||||
mParseExprToAst, mParseStmtToAst, mExpandToAst, mQuoteAst,
|
||||
mUnaryLt, mSucc,
|
||||
mPred, mInc, mDec, mOrd, mNew, mNewFinalize, mNewSeq, mLengthOpenArray,
|
||||
mLengthStr, mLengthArray, mLengthSeq, mIncl, mExcl, mCard, mChr, mGCref,
|
||||
@@ -723,6 +723,7 @@ const
|
||||
|
||||
nkLambdaKinds* = {nkLambda, nkDo}
|
||||
nkSymChoices* = {nkClosedSymChoice, nkOpenSymChoice}
|
||||
nkStrKinds* = {nkStrLit..nkTripleStrLit}
|
||||
|
||||
skLocalVars* = {skVar, skLet, skForVar, skParam}
|
||||
|
||||
|
||||
@@ -898,7 +898,7 @@ proc evalIsOp*(n: PNode): PNode =
|
||||
result.typ = n.typ
|
||||
|
||||
proc expectString(n: PNode) =
|
||||
if n.kind notin {nkStrLit, nkRStrLit, nkTripleStrLit}:
|
||||
if n.kind notin nkStrKinds:
|
||||
GlobalError(n.info, errStringLiteralExpected)
|
||||
|
||||
proc evalSlurp*(e: PNode, module: PSym): PNode =
|
||||
|
||||
@@ -457,6 +457,9 @@ proc newLineInfo*(filename: string, line, col: int): TLineInfo {.inline.} =
|
||||
fileInfos.add(newFileInfo("", "command line"))
|
||||
var gCmdLineInfo* = newLineInfo(int32(0), 1, 1)
|
||||
|
||||
fileInfos.add(newFileInfo("", "compilation artifact"))
|
||||
var gCodegenLineInfo* = newLineInfo(int32(1), 1, 1)
|
||||
|
||||
proc raiseRecoverableError*(msg: string) {.noinline, noreturn.} =
|
||||
raise newException(ERecoverableError, msg)
|
||||
|
||||
|
||||
@@ -45,6 +45,7 @@ proc instGenericContainer(c: PContext, n: PNode, header: PType): PType
|
||||
proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode
|
||||
proc fixImmediateParams(n: PNode): PNode
|
||||
proc activate(c: PContext, n: PNode)
|
||||
proc semQuoteAst(c: PContext, n: PNode): PNode
|
||||
|
||||
proc typeMismatch(n: PNode, formal, actual: PType) =
|
||||
if formal.kind != tyError and actual.kind != tyError:
|
||||
|
||||
@@ -1241,25 +1241,100 @@ proc expectMacroOrTemplateCall(c: PContext, n: PNode): PSym =
|
||||
LocalError(n.info, errXisNoMacroOrTemplate, n.renderTree)
|
||||
result = errorSym(c, n)
|
||||
|
||||
proc expectString(c: PContext, n: PNode): string =
|
||||
var n = semConstExpr(c, n)
|
||||
if n.kind in nkStrKinds:
|
||||
return n.strVal
|
||||
else:
|
||||
LocalError(n.info, errStringLiteralExpected)
|
||||
|
||||
proc getMagicSym(magic: TMagic): PSym =
|
||||
result = newSym(skProc, getIdent($magic), GetCurrOwner(), gCodegenLineInfo)
|
||||
result.magic = magic
|
||||
|
||||
proc newAnonSym(kind: TSymKind, info: TLineInfo,
|
||||
owner = getCurrOwner()): PSym =
|
||||
result = newSym(kind, idAnon, owner, info)
|
||||
result.flags = { sfGenSym }
|
||||
|
||||
proc semExpandToAst(c: PContext, n: PNode): PNode =
|
||||
var macroCall = n[1]
|
||||
var expandedSym = expectMacroOrTemplateCall(c, macroCall)
|
||||
|
||||
macroCall.sons[0] = newSymNode(expandedSym, macroCall.info)
|
||||
markUsed(n, expandedSym)
|
||||
|
||||
for i in countup(1, macroCall.len-1):
|
||||
macroCall.sons[i] = semExprWithType(c, macroCall[i], {})
|
||||
|
||||
# Preserve the magic symbol in order to be handled in evals.nim
|
||||
InternalAssert n.sons[0].sym.magic == mExpandToAst
|
||||
n.typ = getSysSym("PNimrodNode").typ # expandedSym.getReturnType
|
||||
result = n
|
||||
|
||||
proc semExpandToAst(c: PContext, n: PNode, magicSym: PSym,
|
||||
flags: TExprFlags): PNode =
|
||||
flags: TExprFlags = {}): PNode =
|
||||
if sonsLen(n) == 2:
|
||||
var macroCall = n[1]
|
||||
var expandedSym = expectMacroOrTemplateCall(c, macroCall)
|
||||
|
||||
macroCall.sons[0] = newSymNode(expandedSym, macroCall.info)
|
||||
markUsed(n, expandedSym)
|
||||
|
||||
for i in countup(1, macroCall.len-1):
|
||||
macroCall.sons[i] = semExprWithType(c, macroCall[i], {})
|
||||
|
||||
# Preserve the magic symbol in order to be handled in evals.nim
|
||||
n.sons[0] = newSymNode(magicSym, n.info)
|
||||
n.typ = getSysSym("PNimrodNode").typ # expandedSym.getReturnType
|
||||
result = n
|
||||
result = semExpandToAst(c, n)
|
||||
else:
|
||||
result = semDirectOp(c, n, flags)
|
||||
|
||||
proc processQuotations(n: var PNode, op: string,
|
||||
quotes: var seq[PNode],
|
||||
ids: var seq[PNode]) =
|
||||
template returnQuote(q) =
|
||||
quotes.add q
|
||||
n = newIdentNode(getIdent($quotes.len), n.info)
|
||||
ids.add n
|
||||
return
|
||||
|
||||
if n.kind == nkPrefix:
|
||||
checkSonsLen(n, 2)
|
||||
if n[0].kind == nkIdent:
|
||||
var examinedOp = n[0].ident.s
|
||||
if examinedOp == op:
|
||||
returnQuote n[1]
|
||||
elif examinedOp.startsWith(op):
|
||||
n.sons[0] = newIdentNode(getIdent(examinedOp.substr(op.len)), n.info)
|
||||
elif n.kind == nkAccQuoted and op == "``":
|
||||
returnQuote n[0]
|
||||
|
||||
if not n.isAtom:
|
||||
for i in 0 .. <n.len:
|
||||
processQuotations(n.sons[i], op, quotes, ids)
|
||||
|
||||
proc semQuoteAst(c: PContext, n: PNode): PNode =
|
||||
InternalAssert n.len == 2 or n.len == 3
|
||||
# We transform the do block into a template with a param for
|
||||
# each interpolation. We'll pass this template to getAst.
|
||||
var
|
||||
doBlk = n{-1}
|
||||
op = if n.len == 3: expectString(c, n[1]) else: "``"
|
||||
quotes = newSeq[PNode](1)
|
||||
# the quotes will be added to a nkCall statement
|
||||
# leave some room for the callee symbol
|
||||
ids = newSeq[PNode]()
|
||||
# this will store the generated param names
|
||||
|
||||
internalAssert doBlk.kind == nkDo
|
||||
processQuotations(doBlk.sons[bodyPos], op, quotes, ids)
|
||||
|
||||
doBlk.sons[namePos] = newAnonSym(skTemplate, n.info).newSymNode
|
||||
if ids.len > 0:
|
||||
doBlk[paramsPos].sons.setLen(2)
|
||||
doBlk[paramsPos].sons[0] = getSysSym("stmt").newSymNode # return type
|
||||
ids.add getSysSym("expr").newSymNode # params type
|
||||
ids.add emptyNode # no default value
|
||||
doBlk[paramsPos].sons[1] = newNode(nkIdentDefs, n.info, ids)
|
||||
|
||||
var tmpl = semTemplateDef(c, doBlk)
|
||||
quotes[0] = tmpl[namePos]
|
||||
result = newNode(nkCall, n.info, @[
|
||||
getMagicSym(mExpandToAst).newSymNode,
|
||||
newNode(nkCall, n.info, quotes)])
|
||||
result = semExpandToAst(c, result)
|
||||
|
||||
proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||
# watch out, hacks ahead:
|
||||
let oldErrorCount = msgs.gErrorCounter
|
||||
@@ -1335,6 +1410,7 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
|
||||
of mEcho: result = semEcho(c, setMs(n, s))
|
||||
of mShallowCopy: result = semShallowCopy(c, n, flags)
|
||||
of mExpandToAst: result = semExpandToAst(c, n, s, flags)
|
||||
of mQuoteAst: result = semQuoteAst(c, n)
|
||||
else: result = semDirectOp(c, n, flags)
|
||||
|
||||
proc semIfExpr(c: PContext, n: PNode): PNode =
|
||||
|
||||
@@ -234,6 +234,35 @@ proc getAst*(macroOrTemplate: expr): PNimrodNode {.magic: "ExpandToAst".}
|
||||
## macro FooMacro() =
|
||||
## var ast = getAst(BarTemplate())
|
||||
|
||||
proc quote*(bl: stmt, op = "``"): PNimrodNode {.magic: "QuoteAst".}
|
||||
## Quasi-quoting operator.
|
||||
## Accepts an expression or a block and returns the AST that represents it.
|
||||
## Within the quoted AST, you are able to interpolate PNimrodNode expressions
|
||||
## from the surrounding scope. If no operator is given, quoting is done using
|
||||
## backticks. Otherwise, the given operator must be used as a prefix operator
|
||||
## for any interpolated expression. The original meaning of the interpolation
|
||||
## operator may be obtained by escaping it (by prefixing it with itself):
|
||||
## e.g. `@` is escaped as `@@`, `@@` is escaped as `@@@` and so on.
|
||||
##
|
||||
## Example:
|
||||
##
|
||||
## macro check(ex: expr): stmt =
|
||||
## # this is a simplified version of the check macro from the
|
||||
## # unittest module.
|
||||
##
|
||||
## # If there is a failed check, we want to make it easy for
|
||||
## # the user to jump to the faulty line in the code, so we
|
||||
## # get the line info here:
|
||||
## var info = ex.lineinfo
|
||||
##
|
||||
## # We will also display the code string of the failed check:
|
||||
## var expString = ex.toStrLit
|
||||
##
|
||||
## # Finally we compose the code to implement the check:
|
||||
## result = quote do:
|
||||
## if not `ex`:
|
||||
## echo `info` & ": Check failed: " & `expString`
|
||||
|
||||
template emit*(e: expr[string]): stmt =
|
||||
## accepts a single string argument and treats it as nimrod code
|
||||
## that should be inserted verbatim in the program
|
||||
|
||||
@@ -364,6 +364,10 @@ proc newSeq*[T](s: var seq[T], len: int) {.magic: "NewSeq", noSideEffect.}
|
||||
## This is equivalent to ``s = @[]; setlen(s, len)``, but more
|
||||
## efficient since no reallocation is needed.
|
||||
|
||||
proc newSeq*[T](len = 0): seq[T] =
|
||||
## creates a new sequence of type ``seq[T]`` with length ``len``.
|
||||
newSeq(result, len)
|
||||
|
||||
proc len*[TOpenArray: openArray|varargs](x: TOpenArray): int {.
|
||||
magic: "LengthOpenArray", noSideEffect.}
|
||||
proc len*(x: string): int {.magic: "LengthStr", noSideEffect.}
|
||||
|
||||
@@ -16,6 +16,7 @@ Library Additions
|
||||
-----------------
|
||||
|
||||
- Added ``system.onRaise`` to support a condition system.
|
||||
- Added ``macros.quote`` for AST quasi-quoting.
|
||||
|
||||
|
||||
Changes affecting backwards compatibility
|
||||
|
||||
Reference in New Issue
Block a user