diff options
Diffstat (limited to 'lib/macros.nim')
-rw-r--r-- | lib/macros.nim | 90 |
1 files changed, 76 insertions, 14 deletions
diff --git a/lib/macros.nim b/lib/macros.nim index f2783b637..2c71f31c8 100644 --- a/lib/macros.nim +++ b/lib/macros.nim @@ -58,12 +58,12 @@ type nnkTypeDef, nnkYieldStmt, nnkTryStmt, nnkFinally, nnkRaiseStmt, nnkReturnStmt, nnkBreakStmt, nnkContinueStmt, nnkBlockStmt, nnkDiscardStmt, nnkStmtList, nnkImportStmt, - nnkFromStmt, nnkImportAs, nnkIncludeStmt, nnkAccessStmt, - nnkCommentStmt, nnkStmtListExpr, nnkBlockExpr, nnkStmtListType, - nnkBlockType, nnkVm, nnkTypeOfExpr, nnkObjectTy, - nnkTupleTy, nnkRecList, nnkRecCase, nnkRecWhen, - nnkRefTy, nnkPtrTy, nnkVarTy, nnkProcTy, - nnkEnumTy, nnkEnumFieldDef, nnkReturnToken + nnkFromStmt, nnkImportAs, nnkIncludeStmt, nnkCommentStmt, + nnkStmtListExpr, nnkBlockExpr, nnkStmtListType, nnkBlockType, + nnkVm, nnkTypeOfExpr, nnkObjectTy, nnkTupleTy, + nnkRecList, nnkRecCase, nnkRecWhen, nnkRefTy, + nnkPtrTy, nnkVarTy, nnkProcTy, nnkEnumTy, + nnkEnumFieldDef, nnkReturnToken TNimNodeKinds* = set[TNimrodNodeKind] TNimrodTypeKind* = enum ntyNone, ntyBool, ntyChar, ntyEmpty, @@ -86,12 +86,24 @@ type #[[[end]]] type + TNimrodIdent = object of TObject + ## represents a Nimrod identifier in the AST + TNimrodNode {.final.} = object # hidden TNimrodSymbol {.final.} = object # hidden TNimrodType {.final.} = object # hidden + PNimrodType* {.compilerproc.} = ref TNimrodType + ## represents a Nimrod type in the compiler; currently this is not very + ## useful as there is no API to deal with Nimrod types. + PNimrodSymbol* {.compilerproc.} = ref TNimrodSymbol + ## represents a Nimrod *symbol* in the compiler; a *symbol* is a looked-up + ## *ident*. + PNimrodNode* {.compilerproc.} = ref TNimrodNode + ## represents a Nimrod AST node. Macros operate on this type. + expr* = PNimrodNode stmt* = PNimrodNode @@ -100,23 +112,35 @@ type # its father. How to do this without back references? proc `[]`* (n: PNimrodNode, i: int): PNimrodNode {.magic: "NChild".} + ## get `n`'s `i`'th child. + proc `[]=`* (n: PNimrodNode, i: int, child: PNimrodNode) {.magic: "NSetChild".} - ## provide access to `n`'s children + ## set `n`'s `i`'th child to `child`. -type - TNimrodIdent = object of TObject +proc `!` *(s: string): TNimrodIdent {.magic: "StrToIdent".} + ## constructs an identifier from the string `s` -converter StrToIdent*(s: string): TNimrodIdent {.magic: "StrToIdent".} proc `$`*(i: TNimrodIdent): string {.magic: "IdentToStr".} + ## converts a Nimrod identifier to a string + proc `==`* (a, b: TNimrodIdent): bool {.magic: "EqIdent".} + ## compares two Nimrod identifiers proc len*(n: PNimrodNode): int {.magic: "NLen".} + ## returns the number of children of `n`. -## returns the number of children that a node has proc add*(father, child: PNimrodNode) {.magic: "NAdd".} -proc add*(father: PNimrodNode, child: openArray[PNimrodNode]) {.magic: "NAddMultiple".} + ## adds the `child` to the `father` node + +proc add*(father: PNimrodNode, children: openArray[PNimrodNode]) {. + magic: "NAddMultiple".} + ## adds each `children` to the `father` node + proc del*(father: PNimrodNode, idx = 0, n = 1) {.magic: "NDel".} + ## deletes `n` children of `father` starting at index `idx`. + proc kind*(n: PNimrodNode): TNimrodNodeKind {.magic: "NKind".} + ## returns the `kind` of the node `n`. proc intVal*(n: PNimrodNode): biggestInt {.magic: "NIntVal".} proc floatVal*(n: PNimrodNode): biggestFloat {.magic: "NFloatVal".} @@ -133,43 +157,81 @@ proc `typ=`*(n: PNimrodNode, typ: PNimrodType) {.magic: "NSetType".} proc `strVal=`*(n: PNimrodNode, val: string) {.magic: "NSetStrVal".} proc newNimNode*(kind: TNimrodNodeKind, - n: PNimrodNode=nil): PNimrodNode {.magic: "NNewNimNode".} + n: PNimrodNode=nil): PNimrodNode {.magic: "NNewNimNode".} + proc copyNimNode*(n: PNimrodNode): PNimrodNode {.magic: "NCopyNimNode".} proc copyNimTree*(n: PNimrodNode): PNimrodNode {.magic: "NCopyNimTree".} proc error*(msg: string) {.magic: "NError".} + ## writes an error message at compile time + proc warning*(msg: string) {.magic: "NWarning".} + ## writes a warning message at compile time + proc hint*(msg: string) {.magic: "NHint".} + ## writes a hint message at compile time proc newStrLitNode*(s: string): PNimrodNode {.compileTime.} = + ## creates a string literal node from `s` result = newNimNode(nnkStrLit) result.strVal = s proc newIntLitNode*(i: biggestInt): PNimrodNode {.compileTime.} = + ## creates a int literal node from `i` result = newNimNode(nnkIntLit) result.intVal = i -proc newIntLitNode*(f: biggestFloat): PNimrodNode {.compileTime.} = +proc newFloatLitNode*(f: biggestFloat): PNimrodNode {.compileTime.} = + ## creates a float literal node from `f` result = newNimNode(nnkFloatLit) result.floatVal = f proc newIdentNode*(i: TNimrodIdent): PNimrodNode {.compileTime.} = + ## creates an identifier node from `i` result = newNimNode(nnkIdent) result.ident = i + +proc newIdentNode*(i: string): PNimrodNode {.compileTime.} = + ## creates an identifier node from `i` + result = newNimNode(nnkIdent) + result.ident = !i proc toStrLit*(n: PNimrodNode): PNimrodNode {.compileTime.} = + ## converts the AST `n` to the concrete Nimrod code and wraps that + ## in a string literal node return newStrLitNode(repr(n)) proc expectKind*(n: PNimrodNode, k: TNimrodNodeKind) {.compileTime.} = + ## checks that `n` is of kind `k`. If this is not the case, + ## compilation aborts with an error message. This is useful for writing + ## macros that check the AST that is passed to them. if n.kind != k: error("macro expects a node of kind: " & repr(k)) proc expectMinLen*(n: PNimrodNode, min: int) {.compileTime.} = + ## checks that `n` has at least `min` children. If this is not the case, + ## compilation aborts with an error message. This is useful for writing + ## macros that check its number of arguments. if n.len < min: error("macro expects a node with " & $min & " children") +proc expectLen*(n: PNimrodNode, len: int) {.compileTime.} = + ## checks that `n` has exactly `len` children. If this is not the case, + ## compilation aborts with an error message. This is useful for writing + ## macros that check its number of arguments. + if n.len != len: error("macro expects a node with " & $len & " children") + proc newCall*(theProc: TNimrodIdent, args: openArray[PNimrodNode]): PNimrodNode {.compileTime.} = ## produces a new call node. `theProc` is the proc that is called with ## the arguments ``args[0..]``. result = newNimNode(nnkCall) result.add(newIdentNode(theProc)) + result.add(args) + +proc newCall*(theProc: string, + args: openArray[PNimrodNode]): PNimrodNode {.compileTime.} = + ## produces a new call node. `theProc` is the proc that is called with + ## the arguments ``args[0..]``. + result = newNimNode(nnkCall) + result.add(newIdentNode(theProc)) result.add(args) + |