nimpylib icon indicating copy to clipboard operation
nimpylib copied to clipboard

Possible to use def outside of tonim:?

Open gnat opened this issue 2 years ago • 1 comments

Hello! This is an amazing project, good job.

Whenever I try to do this I get Error: undeclared identifier: 'def'

Is this possible to define these outside of tonim: given the current macro capabilities of nim?

If not, any tips to make this more ergonomic? or apply this to the entire file by default?

Thanks!!

gnat avatar Apr 15 '22 22:04 gnat

@gnat this is what I came up with for a simple def macro. It probably can't handle complex cases at all though, and you should really just use Nim's proc syntax as it's native. Nimpylib was meant as a half-joking project, not something people will use in real projects :)

import std/macros

proc genProc(define, body: NimNode): NimNode =
  # Copy the defines (arguments, return type, proc name)
  var define = define
  var 
    startIdx = 1 # start index of arguments of the proc
    stopIdx = define.len - 1 # end index

  # First argument is the return type of the procedure
  var args = @[newIdentNode("auto")]
  # If it's a infix ->, it's a type hint for the return type
  if define.kind == nnkInfix:
    if define[0].strVal != "->":
      error("expected a type hint arrow", define)
    # Replace the return type
    args[0] = define[^1]
    define = define[1] # Discard the arrow

  var procName = define[0]

  # Loop over all arguments except the procedure name
  for i in startIdx..stopIdx:
    # Argument name
    let arg = define[i]
    # arg = 5
    if arg.kind == nnkExprEqExpr:
      args.add newIdentDefs(arg[0], newEmptyNode(), arg[1])
    # arg: int or arg: int ~ 5
    elif arg.kind == nnkExprColonExpr:
      # With default value with ~
      if arg[1].kind == nnkInfix and arg[1][0].strVal == "~":
        args.add newIdentDefs(arg[0], arg[1][1], arg[1][2])
      # No default value, just a type hint
      else:
        args.add newIdentDefs(arg[0], arg[1], newEmptyNode())
    else:
      # Just add argument: auto and hope for the best
      args.add newIdentDefs(arg, ident("auto"), newEmptyNode())
  # Convert a python "doc" comment into a nim doc comment
  if body[0].kind == nnkTripleStrLit:
    body[0] = newCommentStmtNode($body[0])
  # Finally create a procedure and add it to result!
  return newProc(procName, args, body, nnkProcDef)

macro def*(args, body: untyped): untyped = 
  result = genProc(args, body)
  #echo repr result


def retStuff(a: string, b: int) -> string:
  result = newStringOfCap(a.len * b)
  for i in 0..<b:
    result.add a

doAssert retStuff("hello", 3) == "hellohellohello"

def add(x, y):
  """
  hello testing lol
  """
  return x + y

doAssert add(3, 5) == 8

def add2(x, y: int ~ 8) -> int:
  """
  hello testing lol
  """
  return x + y

doAssert add2(3) == 11

Yardanico avatar Apr 27 '22 16:04 Yardanico

Is this possible to define these outside of tonim: given the current macro capabilities of nim?

Sure, here

Also, I'm planning to implement raise ErrType(...) and non-declaration-needed assignments in def macro...

litlighilit avatar Apr 24 '24 13:04 litlighilit