<commit_before>import types, objects, verbs, scripting, strutils, tables, sequtils

template defBuiltin(name: string, body: stmt) {.immediate.} =
  var bproc: BuiltinProc = proc (args: var seq[MData], world: var World,
                                 caller, owner: MObject, symtable: SymbolTable): MData =
    # to provide a simpler call to eval (note the optional args)
    proc evalD(e: MData, w: var World = world, c: MObject = caller,
               o: MObject = owner, st: SymbolTable = symtable): MData =
      eval(e, w, c, o, st)

    body

  scripting.builtins[name] = bproc

proc strToType(str: string): tuple[b: bool, t: MDataType] =
  case str.toLower():
    of "int": return (true, dInt)
    of "float": return (true, dFloat)
    of "str": return (true, dStr)
    of "sym": return (true, dSym)
    of "obj": return (true, dObj)
    of "list": return (true, dList)
    of "nil": return (true, dNil)
    else: return (false, dInt)

template checkForError(value: MData) {.immediate.} =
  if value.isType(dErr):
    return value

template checkType(value: MData, expected: MDataType, ifnot: MError = E_ARGS)
          {.immediate.} =
  if not value.isType(expected):
    return ifnot.md("expected argument of type " & $expected & " instead got " & $value.dType)

template extractObject(objd: MData): MObject {.immediate.} =
  checkType(objd, dObj)
  let obj = world.dataToObj(objd)
  if obj == nil:
    return E_ARGS.md("invalid object " & $objd)

  obj

template checkOwn(obj, what: MObject) =
  if not obj.owns(what):
    return E_PERM.md(obj.toObjStr() & " doesn't own " & what.toObjStr())

template checkOwn(obj: MObject, prop: MProperty) =
  if not obj.owns(prop):
    return E_PERM.md(obj.toObjStr() & " doesn't own " & prop.name)

template checkOwn(obj: MObject, verb: MVerb) =
  if not obj.owns(verb):
    return E_PERM.md(obj.toObjStr() & " doesn't own " & verb.name)

template checkRead(obj, what: MObject) =
  if not obj.canRead(what):
    return E_PERM.md(obj.toObjStr() & " cannot read " & what.toObjStr())
template checkWrite(obj, what: MObject) =
  if not obj.canWrite(what):
    return E_PERM.md(obj.toObjStr() & " cannot write " & what.toObjStr())
template checkRead(obj: MObject, what: MProperty) =
  if not obj.canRead(what):
    return E_PERM.md(obj.toObjStr() & " cannot read property: " & what.name)
template checkWrite(obj: MObject, what: MProperty) =
  if not obj.canWrite(what):
    return E_PERM.md(obj.toObjStr() & " cannot write property: " & what.name)
template checkRead(obj: MObject, what: MVerb) =
  if not obj.canRead(what):
    return E_PERM.md(obj.toObjStr() & " cannot read verb: " & what.names)
template checkWrite(obj: MObject, what: MVerb) =
  if not obj.canWrite(what):
    return E_PERM.md(obj.toObjStr() & " cannot write verb: " & what.names)

proc genCall(fun: MData, args: seq[MData]): MData =
  var resList: seq[MData]
  if fun.isType(dSym):
    resList = @[fun]
  else:
    resList = @["call".mds, fun]

  return (resList & args).md

defBuiltin "echo":
  var newArgs: seq[MData] = @[]
  for arg in args:
    let res = evalD(arg)
    checkForError(res)
    caller.send(res.toEchoString())
    newArgs.add(res)
  return newArgs.md

defBuiltin "do":
  var newArgs: seq[MData] = @[]
  for arg in args:
    let res = evalD(arg)
    checkForError(res)
    newArgs.add(res)

  return newArgs.md

defBuiltin "eval":
  if args.len != 1:
    return E_ARGS.md("eval takes one argument")

  let argd = evalD(args[0])
  checkForError(argd)
  checkType(argd, dStr)
  var evalStr = argd.strVal
  if evalStr[0] != '(':
    evalStr = '(' & evalStr & ')'

  var parser = newParser(evalStr)
  try:
    let parsed = parser.parseList()
    return evalD(parsed, o = caller)
  except MParseError:
    let msg = getCurrentExceptionMsg()
    return E_PARSE.md("code failed to parse: $1" % msg)
<commit_msg>Change behavior of echo builtin to mimic Nim's echo<commit_after>import types, objects, verbs, scripting, strutils, tables, sequtils

template defBuiltin(name: string, body: stmt) {.immediate.} =
  var bproc: BuiltinProc = proc (args: var seq[MData], world: var World,
                                 caller, owner: MObject, symtable: SymbolTable): MData =
    # to provide a simpler call to eval (note the optional args)
    proc evalD(e: MData, w: var World = world, c: MObject = caller,
               o: MObject = owner, st: SymbolTable = symtable): MData =
      eval(e, w, c, o, st)

    body

  scripting.builtins[name] = bproc

proc strToType(str: string): tuple[b: bool, t: MDataType] =
  case str.toLower():
    of "int": return (true, dInt)
    of "float": return (true, dFloat)
    of "str": return (true, dStr)
    of "sym": return (true, dSym)
    of "obj": return (true, dObj)
    of "list": return (true, dList)
    of "nil": return (true, dNil)
    else: return (false, dInt)

template checkForError(value: MData) {.immediate.} =
  if value.isType(dErr):
    return value

template checkType(value: MData, expected: MDataType, ifnot: MError = E_ARGS)
          {.immediate.} =
  if not value.isType(expected):
    return ifnot.md("expected argument of type " & $expected & " instead got " & $value.dType)

template extractObject(objd: MData): MObject {.immediate.} =
  checkType(objd, dObj)
  let obj = world.dataToObj(objd)
  if obj == nil:
    return E_ARGS.md("invalid object " & $objd)

  obj

template checkOwn(obj, what: MObject) =
  if not obj.owns(what):
    return E_PERM.md(obj.toObjStr() & " doesn't own " & what.toObjStr())

template checkOwn(obj: MObject, prop: MProperty) =
  if not obj.owns(prop):
    return E_PERM.md(obj.toObjStr() & " doesn't own " & prop.name)

template checkOwn(obj: MObject, verb: MVerb) =
  if not obj.owns(verb):
    return E_PERM.md(obj.toObjStr() & " doesn't own " & verb.name)

template checkRead(obj, what: MObject) =
  if not obj.canRead(what):
    return E_PERM.md(obj.toObjStr() & " cannot read " & what.toObjStr())
template checkWrite(obj, what: MObject) =
  if not obj.canWrite(what):
    return E_PERM.md(obj.toObjStr() & " cannot write " & what.toObjStr())
template checkRead(obj: MObject, what: MProperty) =
  if not obj.canRead(what):
    return E_PERM.md(obj.toObjStr() & " cannot read property: " & what.name)
template checkWrite(obj: MObject, what: MProperty) =
  if not obj.canWrite(what):
    return E_PERM.md(obj.toObjStr() & " cannot write property: " & what.name)
template checkRead(obj: MObject, what: MVerb) =
  if not obj.canRead(what):
    return E_PERM.md(obj.toObjStr() & " cannot read verb: " & what.names)
template checkWrite(obj: MObject, what: MVerb) =
  if not obj.canWrite(what):
    return E_PERM.md(obj.toObjStr() & " cannot write verb: " & what.names)

proc genCall(fun: MData, args: seq[MData]): MData =
  var resList: seq[MData]
  if fun.isType(dSym):
    resList = @[fun]
  else:
    resList = @["call".mds, fun]

  return (resList & args).md

defBuiltin "echo":
  var
    newArgs: seq[MData] = @[]
    sendstr = ""
  for arg in args:
    let res = evalD(arg)
    checkForError(res)
    sendstr &= res.toEchoString()
    newArgs.add(res)
  caller.send(sendstr)
  return newArgs.md

defBuiltin "do":
  var newArgs: seq[MData] = @[]
  for arg in args:
    let res = evalD(arg)
    checkForError(res)
    newArgs.add(res)

  return newArgs.md

defBuiltin "eval":
  if args.len != 1:
    return E_ARGS.md("eval takes one argument")

  let argd = evalD(args[0])
  checkForError(argd)
  checkType(argd, dStr)
  var evalStr = argd.strVal
  if evalStr[0] != '(':
    evalStr = '(' & evalStr & ')'

  var parser = newParser(evalStr)
  try:
    let parsed = parser.parseList()
    return evalD(parsed, o = caller)
  except MParseError:
    let msg = getCurrentExceptionMsg()
    return E_PARSE.md("code failed to parse: $1" % msg)

{'fraction_non_alphanumeric': 0.13898916967509026, 'fraction_numerical': 0.0010314595152140279, 'mean_word_length': 3.502031340684852, 'pattern_counts': {'":': 20, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '47706', 'n_tokens_mistral': 2816, 'n_tokens_neox': 2794, 'n_words': 779}