簡體   English   中英

如何在 Nim 中為 kind 變體編寫輔助符

[英]How to write accesors for kind Variants in Nim

嘗試編寫訪問器以獲取具有 kind 成員的對象的值,我在宏中收到無效的縮進錯誤我不知道為什么

我想我可能會錯誤地構建宏,但是如果有更好的方法來抽象對象中的類型,那么知道它會很棒。

這是我正在工作的實現:

import macros,strutils,tables

type Types = enum Integer,Float,String,Array
type StyleName = enum X,Y,W,H,Left,Margin,Padding,Color,BorderColor

type Value=object
  case kind : Types
  of Integer: ival:int
  of Float: fval:float
  of String: sval:string
  of Array: cval:array[4,int]
proc toValue(x:float):Value=Value(kind:Float,fval:x)
proc toValue(x:int):Value=Value(kind:Integer,ival:x)
proc toValue(x:string):Value=Value(kind:String,sval:x)
proc toValue(x:array[4,int]):Value=Value(kind:Array,cval:x)

#Construct {stylename:value,...} to {stylename:Value(kind,value),...}
macro style(args: varargs[untyped]): Table[StyleName,Value] =
  #echo repr(args), args.treeRepr
  var s:seq[string]
  for arg in args:
    s.add arg[0].repr & ":" & "toValue(" & arg[1].repr & ")"
  result = parseStmt("{" & s.join(",") & "}.toTable")

變量對象“Value”的宏訪問器

macro getWithKind(style:Table[StyleName,Value], prop:StyleName, kind:Types):untyped=
  var accesor:string
  case kind.repr:
  of "Integer": accesor="ival"
  of "Float": accesor="fval"
  of "String": accesor="sval"
  of "Array": accesor="cval"
  result = parseStmt(style.repr & "[" & prop.repr & "]." & accesor)

#Transforms simple get(style,prop) call to getWithKind(style,prop,kind)
macro get(style:Table[StyleName,Value], prop:StyleName):untyped=
  result = parseStmt(style.repr & ".getWithKind(" & prop.repr & ", kind=" & style.repr & "[" & prop.repr & "].kind)")

這是我得到的輸出:是否不可能在另一個宏中調用宏?

let style1 = style(X=1,Y=2.0,Color=[0,0,0,0]) #build a table of (StyleName:Value)
echo style1  #output: {X: (kind: Integer, ival: 1), Y: (kind: Float, fval: 2.0), Color: (kind: Array, cval: [0, 0, 0, 0])}
echo style1[X].ival  # output:1
echo style1[X].kind  # output:Integer
echo style1.getWithKind(X,kind=Integer)  # output:1
echo style1.get(X)  #(should get 1), output:

C:\Users\cravs\Desktop\test.nim(109, 21) getWithKind
C:\nim-1.4.8\lib\core\macros.nim(558, 17) parseStmt
C:\Users\cravs\Desktop\test.nim(119, 12) template/generic instantiation of `get` from here
C:\nim-1.4.8\lib\core\macros.nim(557, 7) template/generic instantiation of `getWithKind` from here
C:\nim-1.4.8\lib\core\macros.nim(558, 17) Error: unhandled exception: C:\nim-1.4.8\lib\core\macros.nim(557, 11) Error: invalid indentation [ValueError]

編輯:這是另一種嘗試

macro getWithKind(style:Table[StyleName,Value], prop:StyleName, kind:Types):untyped=
  var accesor:string
  case kind.repr
  of "Integer": accesor="ival"
  of "Float": accesor="fval"
  of "String": accesor="sval"
  of "Array": accesor="cval"
  result = newDotExpr(newTree(nnkBracketExpr,style,prop), newIdentNode(accesor))
  #echo parseStmt(style.repr & "[" & prop.repr & "]." & accesor)

macro get(style:Table[StyleName,Value], prop:StyleName):untyped=
  #result = parseStmt(style.repr & ".getWithKind(" & prop.repr & ", kind=" & style.repr & "[" & prop.repr & "].kind)")
  let kind = newDotExpr(newTree(nnkBracketExpr,style,prop), newIdentNode("kind"))
  echo treeRepr kind
  quote do: 
    echo `kind` #prints Integer
    getWithKind(`style`,`prop`,kind=`kind`)


let style1 = style(X=1,Y=2.0,Color=[0,0,0,0]) #build a table of (StyleName:Value)
echo style1  #output: {X: (kind: Integer, ival: 1), Y: (kind: Float, fval: 2.0), Color: (kind: Array, cval: [0, 0, 0, 0])}
echo style1[X].ival  # output:1
echo style1[X].kind  # output:Integer
echo style1.getWithKind(X,kind=Integer)  # output:1
echo style1.get(X)  #(should get 1), output:

C:\Users\...\test.nim(127, 3) Error: undeclared field: '' for type test.Value [declared in C:\Users\...\test.nim(80, 6)]

以下是您應該如何制作宏:

import macros, strutils, tables

type Types = enum Integer, Float, String, Array
type StyleName = enum X, Y, W, H, Left, Margin, Padding, Color, BorderColor

type Value = object
  case kind: Types
  of Integer: ival: int
  of Float: fval: float
  of String: sval: string
  of Array: cval: array[4, int]

proc toValue(x: float): Value = Value(kind: Float, fval: x)
proc toValue(x: int): Value = Value(kind: Integer, ival: x)
proc toValue(x: string): Value = Value(kind: String, sval: x)
proc toValue(x: array[4, int]): Value = Value(kind: Array, cval: x)

macro style(properties: untyped): Table[StyleName, Value] =
  var table = newNimNode(nnkTableConstr)
  
  properties.expectKind nnkStmtList
  
  for property in properties:
    property.expectKind nnkCall
    property.expectLen 2
    
    property[0].expectKind nnkIdent
    property[1].expectKind nnkStmtList
    property[1].expectLen 1

    let
      name = property[0]
      value = property[1][0]

    table.add(newTree(nnkExprColonExpr, name , quote do: `value`.toValue()))

  quote do:
    `table`.toTable()

let table = style:
  X: 10.0
  Y: 20.0
  Color: "ff00ff"
  Margin: [10, 20, 30, 40]

echo table

我不知道您可以在宏中使用字符串,但它的匹配可以更好地操作 AST。 通過這種方式,您還可以驗證用戶正在輸入的內容。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM