hnimast

User-friendly wrapper for nim ast


Keywords
ast, macro
License
Apache-2.0
Install
nimble install hnimast

Documentation

readme

Statically typed wrapper for nim ast at compile (NimNode) and rutime (PNode). Another take on solving problem of node[0][0][1][0]. Mostly concerned with processing of types and procedure declarations.

Installation

Links

Description

Provides logical structure for objects/fields - you can set/get type, check if field is a switch for case statement or not. Visit eachField in the object, map object to some code structure.

import hnimast, hnimast/obj_field_macros
import hpprint

let node = """
type Type = object
  hello: float
""".parsePNodeStr()

var obj = parseObject(node, parsePPragma)

echo "# ~~~~ make object exported ~~~~ #"

obj.exported = true
echo obj.toNNode()


echo "# ~~~~ internal structure of object ~~~~ #"
pprint obj
# ~~~~ make object exported ~~~~ #
Type* = object
  hello: float

# ~~~~ internal structure of object ~~~~ #
Object[ast.PNode, Pragma[ast.PNode]]
  exported:   true
  annotation:
    Option[Pragma[ast.PNode]]
      val: Pragma[ast.PNode](kind: oakCaseOfBranch, elements: [])
      has: false
  name:
    NType[ast.PNode]
      kind:      ntkIdent
      head:      "Type"
      genParams: []
  flds:
    - ObjectField[ast.PNode, Pragma[ast.PNode]]
        annotation:
          Option[Pragma[ast.PNode]]
            val:
              Pragma[ast.PNode]
                kind:     oakCaseOfBranch
                elements: []
            has: false
        value:      Option[ast.PNode](val: <nil tree>)
        exported:   false
        isTuple:    false
        name:       "hello"
        fldType:
          NType[ast.PNode]
            kind:      ntkIdent
            head:      "float"
            genParams: []
        isKind:     false
  • working with enums
    • parseEnumImpl - parse as enum implementation. Tested on alias, symbol, value, enum-as-generic-parameter, typedesc[Enum] etc.
    • getEnumPref - for NEP-conforming enums (prefixEnumValueName) get prefix
    • getEnumNames - get list of all enum names
    • enumNames - macro. Generate seq[string] of names for all enums.
  • working with object declarations
    • ObjectBranch, Object and ObjectField types - wrappers on top of nim object declarations. Supports arbitrarily named case fields, annotations for objects etc. Currently does not cover all possible cases.
    • eachField - visit each field in object
    • eachField - recursively generate case expression for each possible and use insert result of callback for each field. For use case example see tests/tHnimAst.nim
    • can be conveted to and from NimNode
    • eachCase - generate case statement for object’s kind fields
    • eachParallelCase - generate case statement for two object’s kind fields.
    • eachPath
  • working with object values
    • ObjTree - ‘stringly typed’ representation of object value. mainly used in hpprint, but due to dependency reasons type definitions is still here.

Contribution & development

If you have any question about implementation, API etc. you can join my discord server and ask there.

Right now not all possible ast combinations are covered, more testing is necessary.

Ideas:

  • [ ] Genereate wrappers for sourcetrail code indexer software library using libclang wrapper. Most groundwork has already been done - it should be relatively simple to assemble all pieces together.
  • [ ] Generate graphviz graph of object dependencies using graphviz wrapper - basically the same as sourcetrail DB, just easier to implement as it does not require working with C++ bindings.
  • [ ] Having more ‘typed’ representation of of object opens possibilities for things like refactoring, building graphs of object dependencies (which one uses another as field etc). Right now I don’t have any concrete ideas, but something like this might be easier to implement when we know logical structure of an object.