2021-01-05 09:35:18 +01:00
|
|
|
# Copyright 2020 Mattia Giambirtone
|
|
|
|
#
|
|
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
# you may not use this file except in compliance with the License.
|
|
|
|
# You may obtain a copy of the License at
|
|
|
|
#
|
|
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
#
|
|
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
# See the License for the specific language governing permissions and
|
|
|
|
# limitations under the License.
|
2021-01-05 00:32:17 +01:00
|
|
|
|
2021-01-05 09:35:18 +01:00
|
|
|
# Implementations of builtin functions and modules
|
2021-01-05 00:32:17 +01:00
|
|
|
|
|
|
|
import types/baseObject
|
2021-01-05 09:35:18 +01:00
|
|
|
import types/numbers
|
2021-01-05 00:32:17 +01:00
|
|
|
import types/methods
|
2021-01-16 11:47:01 +01:00
|
|
|
import types/typeutils
|
2021-01-09 18:03:47 +01:00
|
|
|
import types/japlString
|
|
|
|
import types/exception
|
2021-01-11 13:17:01 +01:00
|
|
|
import types/native
|
2021-01-05 09:35:18 +01:00
|
|
|
|
2021-01-09 18:03:47 +01:00
|
|
|
import times
|
|
|
|
import math
|
|
|
|
import strformat
|
2021-02-04 12:03:10 +01:00
|
|
|
import parseutils
|
|
|
|
import strutils
|
2021-01-05 09:35:18 +01:00
|
|
|
|
2021-03-18 15:09:36 +01:00
|
|
|
|
2021-02-09 16:59:34 +01:00
|
|
|
template join(args: seq[ptr Obj]): string =
|
|
|
|
## A template that returns the string
|
|
|
|
## representation of all args separated
|
|
|
|
## by a space.
|
2021-01-05 09:35:18 +01:00
|
|
|
var res = ""
|
2021-01-05 12:52:41 +01:00
|
|
|
for i in countup(0, args.high()):
|
|
|
|
let arg = args[i]
|
|
|
|
if i < args.high():
|
|
|
|
res = res & arg.stringify() & " "
|
|
|
|
else:
|
|
|
|
res = res & arg.stringify()
|
2021-02-09 16:59:34 +01:00
|
|
|
res
|
|
|
|
|
2021-03-18 15:09:36 +01:00
|
|
|
|
2021-02-09 16:59:34 +01:00
|
|
|
proc natPrint*(args: seq[ptr Obj]): tuple[kind: retNative, result: ptr Obj] =
|
|
|
|
## Native function print
|
|
|
|
## Prints an object representation
|
|
|
|
## to stdout. If more than one argument
|
|
|
|
## is passed, they will be printed separated
|
|
|
|
## by a space
|
2021-01-09 18:03:47 +01:00
|
|
|
# Note: we return nil and not asNil() because
|
|
|
|
# the VM will later use its own cached pointer
|
|
|
|
# to nil
|
2021-02-09 16:59:34 +01:00
|
|
|
echo join(args)
|
2021-01-11 13:17:01 +01:00
|
|
|
return (kind: retNative.Nil, result: nil)
|
2021-01-05 00:32:17 +01:00
|
|
|
|
2021-03-18 15:09:36 +01:00
|
|
|
|
2021-02-09 16:59:34 +01:00
|
|
|
proc natPrintErr*(args: seq[ptr Obj]): tuple[kind:
|
|
|
|
retNative, result: ptr Obj] =
|
|
|
|
## Native function printErr
|
|
|
|
## Prints an object representation
|
|
|
|
## to stderr. If more than one argument
|
|
|
|
## is passed, they will be printed separated
|
|
|
|
## by a space
|
|
|
|
writeLine stderr, join(args)
|
|
|
|
return (kind: retNative.Nil, result: nil)
|
2021-02-04 12:03:10 +01:00
|
|
|
|
2021-03-18 15:09:36 +01:00
|
|
|
|
2021-01-30 18:42:04 +01:00
|
|
|
proc natReadline*(args: seq[ptr Obj]): tuple[kind: retNative, result: ptr Obj] =
|
|
|
|
## Native function readline
|
|
|
|
## Reads a line from stdin and returns
|
2021-02-04 12:03:10 +01:00
|
|
|
## it as a string, optionally writing
|
|
|
|
## a given prompt to stdout
|
2021-02-15 00:04:49 +01:00
|
|
|
if args.len() > 1:
|
2021-02-04 12:03:10 +01:00
|
|
|
return (kind: retNative.Exception, result: newTypeError(&"Function 'readLine' takes 0 to 1 arguments, got {len(args)}"))
|
2021-02-15 00:04:49 +01:00
|
|
|
elif args.len() > 0 and not args[0].isStr():
|
2021-02-04 12:03:10 +01:00
|
|
|
return (kind: retNative.Exception, result: newTypeError(&"The prompt must be of type 'string', not '{args[0].typeName()}'"))
|
2021-02-15 00:04:49 +01:00
|
|
|
if args.len() > 0:
|
2021-02-15 00:11:37 +01:00
|
|
|
stdout.write(args[0].toStr())
|
2021-01-30 18:42:04 +01:00
|
|
|
return (kind: retNative.Object, result: stdin.readLine().asStr())
|
|
|
|
|
2021-01-05 09:35:18 +01:00
|
|
|
|
2021-01-11 13:17:01 +01:00
|
|
|
proc natClock*(args: seq[ptr Obj]): tuple[kind: retNative, result: ptr Obj] =
|
2021-01-05 09:35:18 +01:00
|
|
|
## Native function clock
|
|
|
|
## Returns the current unix
|
|
|
|
## time (also known as epoch)
|
|
|
|
## with subsecond precision
|
|
|
|
|
|
|
|
# TODO: Move this to a separate module once we have imports
|
|
|
|
|
2021-01-11 13:17:01 +01:00
|
|
|
result = (kind: retNative.Object, result: getTime().toUnixFloat().asFloat())
|
2021-01-05 09:35:18 +01:00
|
|
|
|
|
|
|
|
2021-02-04 12:03:10 +01:00
|
|
|
proc natRound*(args: seq[ptr Obj]): tuple[kind: retNative, result: ptr Obj] =
|
2021-01-09 18:03:47 +01:00
|
|
|
## Rounds a floating point number to a given
|
|
|
|
## precision (when precision == 0, this function drops the
|
|
|
|
## decimal part and returns an integer). Note that when
|
|
|
|
## precision > 0 and the value of the dropped digits
|
|
|
|
## exceeds or equals 5, the closest decimal place is
|
|
|
|
## increased by 1 (i.e. round(3.141519, 3) == 3.142)
|
|
|
|
var precision = 0
|
|
|
|
if len(args) notin 1..2:
|
|
|
|
# Here we need to return immediately to exit the procedure
|
2021-01-11 13:17:01 +01:00
|
|
|
return (kind: retNative.Exception, result: newTypeError(&"function 'round' takes from 1 to 2 arguments, got {len(args)}"))
|
2021-01-09 18:03:47 +01:00
|
|
|
elif len(args) == 2:
|
|
|
|
if not args[1].isInt():
|
2021-01-11 13:17:01 +01:00
|
|
|
return (kind: retNative.Exception, result: newTypeError(&"precision must be of type 'int', not '{args[1].typeName()}'"))
|
2021-01-09 18:03:47 +01:00
|
|
|
else:
|
|
|
|
precision = args[1].toInt()
|
|
|
|
if args[0].kind notin {ObjectType.Integer, ObjectType.Float}:
|
2021-01-11 13:17:01 +01:00
|
|
|
return (kind: retNative.Exception, result: newTypeError(&"input must be of type 'int' or 'float', not '{args[0].typeName()}'"))
|
2021-01-09 18:03:47 +01:00
|
|
|
if precision < 0:
|
2021-01-11 13:17:01 +01:00
|
|
|
result = (kind: retNative.Exception, result: newTypeError(&"precision must be positive"))
|
2021-01-09 18:03:47 +01:00
|
|
|
else:
|
|
|
|
if args[0].isInt():
|
2021-01-11 13:17:01 +01:00
|
|
|
result = (kind: retNative.Object, result: args[0])
|
2021-01-09 18:03:47 +01:00
|
|
|
elif precision == 0:
|
2021-01-11 13:17:01 +01:00
|
|
|
result = (kind: retNative.Object, result: int(args[0].toFloat()).asInt())
|
2021-01-09 18:03:47 +01:00
|
|
|
else:
|
2021-01-11 13:17:01 +01:00
|
|
|
result = (kind: retNative.Object, result: round(args[0].toFloat(), precision).asFloat())
|
2021-01-09 18:03:47 +01:00
|
|
|
|
|
|
|
|
2021-02-04 12:03:10 +01:00
|
|
|
proc natToInt*(args: seq[ptr Obj]): tuple[kind: retNative, result: ptr Obj] =
|
|
|
|
## Drops the decimal part of a float and returns an integer or
|
|
|
|
## converts an integer string to an actual integer object.
|
2021-01-09 18:03:47 +01:00
|
|
|
## If the value is already an integer, the same object is returned
|
|
|
|
if args[0].isInt():
|
2021-01-11 13:17:01 +01:00
|
|
|
result = (kind: retNative.Object, result: args[0])
|
2021-01-09 18:03:47 +01:00
|
|
|
elif args[0].isFloat():
|
2021-01-11 13:17:01 +01:00
|
|
|
result = (kind: retNative.Object, result: int(args[0].toFloat()).asInt())
|
2021-02-04 12:03:10 +01:00
|
|
|
elif args[0].isStr():
|
|
|
|
let s = args[0].toStr()
|
|
|
|
for c in s:
|
|
|
|
if not c.isDigit():
|
|
|
|
return (kind: retNative.Exception, result: newValueError("invalid argument"))
|
|
|
|
try:
|
|
|
|
var num: int
|
|
|
|
discard parseInt(args[0].toStr(), num)
|
|
|
|
result = (kind: retNative.Object, result: num.asInt())
|
|
|
|
except ValueError:
|
|
|
|
result = (kind: retNative.Exception, result: newValueError("invalid argument"))
|
2021-01-09 18:03:47 +01:00
|
|
|
else:
|
2021-02-04 12:03:10 +01:00
|
|
|
result = (kind: retNative.Exception, result: newTypeError(&"input must be of type 'int', 'float' or 'string', not '{args[0].typeName()}'"))
|
2021-01-09 18:03:47 +01:00
|
|
|
|
|
|
|
|
2021-02-04 12:03:10 +01:00
|
|
|
proc natType*(args: seq[ptr Obj]): tuple[kind: retNative, result: ptr Obj] =
|
2021-01-09 18:03:47 +01:00
|
|
|
## Returns the type of a given object as a string
|
2021-01-11 13:17:01 +01:00
|
|
|
result = (kind: retNative.Object, result: args[0].typeName().asStr())
|
2021-01-09 18:03:47 +01:00
|
|
|
|
|
|
|
|
2021-02-04 12:03:10 +01:00
|
|
|
proc natToString*(args: seq[ptr Obj]): tuple[kind: retNative, result: ptr Obj] =
|
2021-01-14 22:37:11 +01:00
|
|
|
## Returns the string representation of an object
|
|
|
|
result = (kind: retNative.Object, result: args[0].stringify().asStr())
|