Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Plan to rewrite the generator scripts. #111

Open
planetis-m opened this issue May 5, 2024 · 2 comments
Open

Plan to rewrite the generator scripts. #111

planetis-m opened this issue May 5, 2024 · 2 comments

Comments

@planetis-m
Copy link
Owner

The scripts that are used to generate the wrapper have grown in complexity and are difficult to understand and modify. Experience has shown that trying to modify the produced nim code from a representation like, json, xml, etc, that the generators are using, leads to horrible, unmaintanable code. This is better done at the nim AST level. So to evolve the scripts, keep the maintenance cost down, make them easily extensive, the two separate tasks of parsing the C header definitions and outputting bindings, and making an idiomatic nim wrapper based on those bindings, should use two different programs. The bindings parser, can use the raylib_parser for a start, or eventually be ported to c2nim/furthark. It doesn't attempt to do any transformations and use the c types. This is necessary as upstream will not improve it to parse other headers than raylib.h correctly, it half works with rlgl.h and requires manual intervention. Another program the wrapper generator, makes use of the compiler as a library, and parses the bindings it traverses the nim ast and writes our wrapper in a file.

@planetis-m
Copy link
Owner Author

planetis-m commented May 5, 2024

mwe for the second program:

import
  compiler/[ast, parser, idents, astalgo, pathutils, condsyms, renderer,
  options, nimconf, extccomp, modulegraphs], std/[os, strutils]

# need to run ./koch checksums

proc str(n: PNode): string =
  case n.kind
  of nkStrLit..nkTripleStrLit:
    result = n.strVal
  of nkIdent:
    result = n.ident.s
  of nkSym:
    result = n.sym.name.s
  of nkOpenSymChoice, nkClosedSymChoice:
    result = n.sons[0].sym.name.s
  else:
    assert false

proc basename(n: PNode): PNode =
  case n.kind
  of nkIdent: result = n
  of nkPragmaExpr:
    result = basename(n[0])
  of nkPostfix, nkPrefix:
    result = basename(n[1])
  of nkAccQuoted:
    result = basename(n[0])
  else:
    assert false

proc eqIdent(a: string; b: string): bool =
  result = cmpIgnoreStyle(a, b) == 0

proc eqIdent(a: PNode, b: string): bool =
  result = cmpIgnoreStyle(a.basename.str, b) == 0

proc eqIdent(a, b: PNode): bool =
  result = cmpIgnoreStyle(a.basename.str, b.basename.str) == 0

proc groupMatrixFieldsByRow(node: PNode) =
  const MatN = 4 # assumes a 4x4 matrix
  case node.kind
  of nkTypeSection:
    for child in node.items:
      if child.kind == nkTypeDef and eqIdent(child[0], "Matrix"):
        let reclist = child[2][2]
        if reclist.len != MatN*MatN: return
        for i in countdown(reclist.len-1, 0, MatN):
          for j in countdown(i-1, i-MatN+1):
            reclist[i].sons.insert(reclist[j][0])
        for i in countdown(reclist.len-1, 0):
          if (i + 1) mod 4 != 0:
            reclist.sons.delete(i)
  else:
    discard
  for child in node.items:
    groupMatrixFieldsByRow(child)

proc main =
  # Create a new configuration and module graph
  let conf = newConfigRef()
  let cache = newIdentCache()
  let graph = newModuleGraph(cache, conf)
  # Initialize defines and load configurations
  condsyms.initDefines(conf.symbols)
  conf.projectName = "stdinfile"
  conf.projectFull = "stdinfile".AbsoluteFile
  conf.projectPath = canonicalizePath(conf, getCurrentDir().AbsoluteFile).AbsoluteDir
  conf.projectIsStdin = true
  loadConfigs(DefaultConfig, cache, conf, graph.idgen)
  # Initialize external compiler variables
  extccomp.initVars(conf)
  # Parse input file
  let filename = "input.nim"
  let node = parseString(readFile(filename), cache, conf)
  # Apply postprocessing steps
  node.groupMatrixFieldsByRow()
  # Render the module to an output file
  renderModule(node, filename, {renderDocComments})

main()

@planetis-m
Copy link
Owner Author

Something similar was done in https://github.com/nim-lang/c2nim/blob/araq-gobject/gobject2nim.nim

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant