2020-10-21 22:49:08 +02: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.
|
2020-10-21 22:34:04 +02:00
|
|
|
|
2020-10-27 14:38:28 +01:00
|
|
|
## The JAPL's type system. In JAPL, all entities are
|
|
|
|
## objects, and are always references to a memory location
|
|
|
|
## somewhere in the heap
|
2020-08-15 11:27:04 +02:00
|
|
|
|
2020-10-24 20:48:10 +02:00
|
|
|
import ../memory
|
2020-10-25 15:08:08 +01:00
|
|
|
import strformat
|
2020-10-27 18:59:36 +01:00
|
|
|
import math
|
2020-10-28 17:19:41 +01:00
|
|
|
import bitops
|
|
|
|
import strutils
|
2020-10-22 12:21:47 +02:00
|
|
|
|
2020-10-25 12:45:03 +01:00
|
|
|
|
2020-08-13 23:39:26 +02:00
|
|
|
type
|
2020-10-27 14:38:28 +01:00
|
|
|
NotImplementedError* = object of CatchableError
|
2020-10-26 20:29:35 +01:00
|
|
|
## Raised when a given operation is unsupported
|
|
|
|
## on a given type
|
|
|
|
Chunk* = ref object # TODO: This shouldn't be here, but Function needs it. Consider refactoring
|
2020-10-22 15:45:36 +02:00
|
|
|
## A piece of bytecode.
|
2020-10-26 20:29:35 +01:00
|
|
|
## Consts represents the constants table the code is referring to
|
|
|
|
## Code is the compiled bytecode
|
|
|
|
## Lines maps bytecode instructions to line numbers (1 to 1 correspondence)
|
2020-10-24 20:48:10 +02:00
|
|
|
consts*: seq[ptr Obj]
|
2020-10-22 15:45:36 +02:00
|
|
|
code*: seq[uint8]
|
2020-10-26 22:55:20 +01:00
|
|
|
lines*: seq[int] # TODO: Run-length encoding
|
2020-10-17 12:43:54 +02:00
|
|
|
ObjectType* {.pure.} = enum
|
2020-10-22 15:50:30 +02:00
|
|
|
## All the possible object types
|
2020-10-17 12:43:54 +02:00
|
|
|
String, Exception, Function,
|
2020-10-24 20:48:10 +02:00
|
|
|
Class, Module, BaseObject,
|
2020-10-26 20:29:35 +01:00
|
|
|
Integer, Float, Bool, NotANumber,
|
2020-10-24 20:48:10 +02:00
|
|
|
Infinity, Nil
|
2020-10-17 12:43:54 +02:00
|
|
|
Obj* = object of RootObj
|
2020-10-26 20:29:35 +01:00
|
|
|
## The base object for all
|
|
|
|
## JAPL types. Every object
|
|
|
|
## in JAPL implicitly inherits
|
|
|
|
## from this base type
|
2020-10-17 12:43:54 +02:00
|
|
|
kind*: ObjectType
|
2020-10-26 20:29:35 +01:00
|
|
|
hashValue*: uint64
|
2020-10-27 14:38:28 +01:00
|
|
|
isHashable: bool # This is false for unhashable objects
|
2020-10-26 20:29:35 +01:00
|
|
|
String* = object of Obj
|
|
|
|
## A string object
|
2020-10-22 12:21:47 +02:00
|
|
|
str*: ptr UncheckedArray[char] # TODO -> Unicode support
|
|
|
|
len*: int
|
2020-10-22 15:50:30 +02:00
|
|
|
Integer* = object of Obj
|
2020-10-26 20:29:35 +01:00
|
|
|
## An integer object
|
2020-10-22 15:50:30 +02:00
|
|
|
intValue: int # TODO: Bignum arithmetic
|
2020-10-24 20:48:10 +02:00
|
|
|
Bool* = object of Integer
|
2020-10-26 20:29:35 +01:00
|
|
|
## A boolean object
|
2020-10-24 20:48:10 +02:00
|
|
|
boolValue: bool # If the boolean is true or false
|
|
|
|
Nil* = object of Bool
|
2020-10-26 20:29:35 +01:00
|
|
|
## A nil object
|
2020-10-24 20:48:10 +02:00
|
|
|
Float* = object of Integer
|
2020-10-26 20:29:35 +01:00
|
|
|
## A float object
|
2020-10-22 15:50:30 +02:00
|
|
|
floatValue: float
|
2020-10-24 20:48:10 +02:00
|
|
|
Infinity* = object of Float # Inf is considered a float
|
2020-10-26 20:29:35 +01:00
|
|
|
## An inf object
|
2020-10-24 20:48:10 +02:00
|
|
|
isNegative: bool # This differentiates inf and -inf
|
|
|
|
NotANumber* = object of Float # NaN is as well (IEEE 754)
|
2020-10-26 20:29:35 +01:00
|
|
|
## A nan object
|
2020-10-22 12:21:47 +02:00
|
|
|
Function* = object of Obj
|
2020-10-26 20:29:35 +01:00
|
|
|
## A function objecy
|
2020-10-22 12:21:47 +02:00
|
|
|
name*: ptr String
|
2020-10-26 20:29:35 +01:00
|
|
|
arity*: int # The number of required parameters
|
|
|
|
optionals*: int # How many optional parameters
|
|
|
|
defaults*: seq[ptr Obj] # List of default arguments, in order
|
|
|
|
chunk*: Chunk # The function's body
|
|
|
|
JAPLException* = object of Obj # TODO: Create exceptions subclasses
|
|
|
|
## The base exception object
|
|
|
|
errName*: ptr String # TODO: Ditch error name in favor of inheritance-based types
|
2020-10-22 12:21:47 +02:00
|
|
|
message*: ptr String
|
|
|
|
|
|
|
|
|
2020-10-27 18:59:36 +01:00
|
|
|
# Custom operators
|
|
|
|
proc `**`(a, b: int): int = pow(a.float, b.float).int
|
|
|
|
proc `**`(a, b: float): float = pow(a, b)
|
|
|
|
|
|
|
|
|
2020-10-26 20:29:35 +01:00
|
|
|
## Object constructors and allocators
|
2020-10-25 17:47:53 +01:00
|
|
|
|
2020-10-24 20:48:10 +02:00
|
|
|
proc allocateObject*(size: int, kind: ObjectType): ptr Obj =
|
2020-10-26 20:29:35 +01:00
|
|
|
## Wrapper around memory.reallocate to create a new generic JAPL object
|
2020-10-24 20:48:10 +02:00
|
|
|
result = cast[ptr Obj](reallocate(nil, 0, size))
|
|
|
|
result.kind = kind
|
|
|
|
|
|
|
|
|
|
|
|
template allocateObj*(kind: untyped, objType: ObjectType): untyped =
|
|
|
|
## Wrapper around allocateObject to cast a generic object
|
|
|
|
## to a more specific type
|
|
|
|
cast[ptr kind](allocateObject(sizeof kind, objType))
|
|
|
|
|
2020-10-25 12:45:03 +01:00
|
|
|
|
2020-10-26 20:29:35 +01:00
|
|
|
proc newChunk*(): Chunk =
|
|
|
|
## Initializes a new, empty chunk
|
|
|
|
result = Chunk(consts: @[], code: @[], lines: @[])
|
|
|
|
|
|
|
|
|
2020-10-27 14:38:28 +01:00
|
|
|
## Utilities that bridge nim and JAPL types or to inspect
|
|
|
|
## JAPL objects
|
2020-10-26 22:55:20 +01:00
|
|
|
|
|
|
|
|
2020-10-22 12:21:47 +02:00
|
|
|
proc objType*(obj: ptr Obj): ObjectType =
|
2020-10-19 16:19:49 +02:00
|
|
|
## Returns the type of the object
|
2020-10-26 22:55:20 +01:00
|
|
|
result = obj.kind
|
2020-08-14 08:25:05 +02:00
|
|
|
|
|
|
|
|
2020-10-26 22:55:20 +01:00
|
|
|
proc isCallable*(obj: ptr Obj): bool =
|
|
|
|
## Returns true if the given object
|
|
|
|
## is callable, false otherwise
|
|
|
|
result = obj.kind in {ObjectType.Function, ObjectType.Class}
|
|
|
|
|
2020-10-26 20:29:35 +01:00
|
|
|
|
|
|
|
proc isNil*(obj: ptr Obj): bool =
|
|
|
|
## Returns true if the given obj
|
|
|
|
## is a JAPL nil object
|
|
|
|
result = obj.kind == ObjectType.Nil
|
|
|
|
|
2020-10-26 16:29:00 +01:00
|
|
|
|
2020-10-26 20:29:35 +01:00
|
|
|
proc isBool*(obj: ptr Obj): bool =
|
|
|
|
## Returns true if the given obj
|
|
|
|
## is a JAPL bool
|
|
|
|
result = obj.kind == ObjectType.Bool
|
|
|
|
|
|
|
|
|
|
|
|
proc isInt*(obj: ptr Obj): bool =
|
|
|
|
## Returns true if the given obj
|
|
|
|
## is a JAPL integer
|
|
|
|
result = obj.kind == ObjectType.Integer
|
|
|
|
|
|
|
|
|
|
|
|
proc isFloat*(obj: ptr Obj): bool =
|
|
|
|
## Returns true if the given obj
|
|
|
|
## is a JAPL float
|
|
|
|
result = obj.kind == ObjectType.Float
|
|
|
|
|
|
|
|
|
|
|
|
proc isInf*(obj: ptr Obj): bool =
|
|
|
|
## Returns true if the given obj
|
|
|
|
## is a JAPL inf object
|
|
|
|
result = obj.kind == ObjectType.Infinity
|
|
|
|
|
|
|
|
|
|
|
|
proc isNan*(obj: ptr Obj): bool =
|
|
|
|
## Returns true if the given obj
|
|
|
|
## is a JAPL nan object
|
|
|
|
result = obj.kind == ObjectType.NotANumber
|
|
|
|
|
|
|
|
|
|
|
|
proc isNum*(obj: ptr Obj): bool =
|
|
|
|
## Returns true if the given obj is
|
|
|
|
## either a JAPL number, nan or inf
|
|
|
|
result = isInt(obj) or isFloat(obj) or isInf(obj) or isNan(obj)
|
|
|
|
|
|
|
|
|
|
|
|
proc isStr*(obj: ptr Obj): bool =
|
|
|
|
## Returns true if the given object is a JAPL string
|
|
|
|
result = obj.kind == ObjectType.String
|
|
|
|
|
|
|
|
|
|
|
|
proc toBool*(obj: ptr Obj): bool =
|
|
|
|
## Converts a JAPL bool to a nim bool
|
|
|
|
result = cast[ptr Bool](obj).boolValue
|
|
|
|
|
|
|
|
|
|
|
|
proc toInt*(obj: ptr Obj): int =
|
|
|
|
## Converts a JAPL int to a nim int
|
|
|
|
result = cast[ptr Integer](obj).intValue
|
|
|
|
|
|
|
|
|
|
|
|
proc toFloat*(obj: ptr Obj): float =
|
|
|
|
## Converts a JAPL float to a nim float
|
|
|
|
result = cast[ptr Float](obj).floatValue
|
|
|
|
|
2020-10-27 14:38:28 +01:00
|
|
|
|
2020-10-26 20:29:35 +01:00
|
|
|
proc toStr*(obj: ptr Obj): string =
|
|
|
|
## Converts a JAPL string into a nim string
|
|
|
|
var strObj = cast[ptr String](obj)
|
|
|
|
for i in 0..strObj.str.len - 1:
|
|
|
|
result.add(strObj.str[i])
|
|
|
|
|
|
|
|
|
|
|
|
proc asInt*(n: int): ptr Integer =
|
|
|
|
## Converts a nim int into a JAPL int
|
|
|
|
result = allocateObj(Integer, ObjectType.Integer)
|
|
|
|
result.intValue = n
|
2020-10-27 14:38:28 +01:00
|
|
|
result.isHashable = true
|
2020-10-26 20:29:35 +01:00
|
|
|
|
|
|
|
|
|
|
|
proc asFloat*(n: float): ptr Float =
|
|
|
|
## Converts a nim float into a JAPL float
|
|
|
|
result = allocateObj(Float, ObjectType.Float)
|
|
|
|
result.floatValue = n
|
2020-10-27 14:38:28 +01:00
|
|
|
result.isHashable = true
|
2020-10-26 20:29:35 +01:00
|
|
|
|
|
|
|
|
|
|
|
proc asBool*(b: bool): ptr Bool =
|
|
|
|
## Converts a nim bool into a JAPL bool
|
|
|
|
result = allocateObj(Bool, ObjectType.Bool)
|
|
|
|
result.boolValue = b
|
2020-10-27 14:38:28 +01:00
|
|
|
result.isHashable = true
|
2020-10-25 15:08:08 +01:00
|
|
|
|
2020-10-27 14:38:28 +01:00
|
|
|
proc asNil*(): ptr Nil =
|
2020-10-26 20:29:35 +01:00
|
|
|
## Creates a nil object
|
|
|
|
result = allocateObj(Nil, ObjectType.Nil)
|
|
|
|
|
|
|
|
|
2020-10-27 14:38:28 +01:00
|
|
|
proc asNan*(): ptr NotANumber =
|
2020-10-26 20:29:35 +01:00
|
|
|
## Creates a nan object
|
|
|
|
result = allocateObj(NotANumber, ObjectType.NotANumber)
|
|
|
|
|
|
|
|
|
|
|
|
proc asInf*(): ptr Infinity =
|
|
|
|
## Creates an inf object
|
|
|
|
result = allocateObj(Infinity, ObjectType.Infinity)
|
|
|
|
|
|
|
|
|
|
|
|
proc newObj*(): ptr Obj =
|
|
|
|
## Allocates a generic JAPL object
|
|
|
|
result = allocateObj(Obj, ObjectType.BaseObject)
|
|
|
|
|
|
|
|
|
2020-10-27 14:38:28 +01:00
|
|
|
proc newString*(str: string): ptr String
|
|
|
|
proc asStr*(s: string): ptr String # Forward declarations
|
2020-10-26 20:29:35 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
2020-10-27 14:38:28 +01:00
|
|
|
# Functions constructors and procedures
|
|
|
|
|
|
|
|
type
|
|
|
|
FunctionType* {.pure.} = enum
|
|
|
|
## All code in JAPL is compiled
|
|
|
|
## as if it was inside some sort
|
|
|
|
## of function. To differentiate
|
|
|
|
## between actual functions and
|
|
|
|
## the top-level code, this tiny
|
|
|
|
## enum is used to tell the two
|
|
|
|
## contexts apart when compiling
|
|
|
|
Func, Script
|
|
|
|
|
|
|
|
|
|
|
|
proc newFunction*(name: string = "", chunk: Chunk = newChunk(), arity: int = 0): ptr Function =
|
|
|
|
## Allocates a new function object with the given
|
|
|
|
## bytecode chunk and arity. If the name is an empty string
|
|
|
|
## (the default), the function will be an
|
|
|
|
## anonymous code object
|
|
|
|
# TODO: Add lambdas
|
|
|
|
# TODO: Add support for optional parameters
|
|
|
|
result = allocateObj(Function, ObjectType.Function)
|
|
|
|
if name.len > 1:
|
|
|
|
result.name = newString(name)
|
|
|
|
else:
|
|
|
|
result.name = nil
|
|
|
|
result.arity = arity
|
|
|
|
result.chunk = chunk
|
|
|
|
result.isHashable = false
|
|
|
|
|
|
|
|
|
|
|
|
proc newIndexError*(message: string): ptr JAPLException =
|
|
|
|
result = allocateObj(JAPLException, ObjectType.Exception)
|
|
|
|
result.errName = "IndexError".asStr()
|
|
|
|
result.message = message.asStr()
|
|
|
|
|
|
|
|
|
|
|
|
proc newReferenceError*(message: string): ptr JAPLException =
|
|
|
|
result = allocateObj(JAPLException, ObjectType.Exception)
|
|
|
|
result.errName = "ReferenceError".asStr()
|
|
|
|
result.message = message.asStr()
|
|
|
|
|
|
|
|
|
|
|
|
proc newInterruptedError*(message: string): ptr JAPLException =
|
|
|
|
result = allocateObj(JAPLException, ObjectType.Exception)
|
|
|
|
result.errName = "InterruptedError".asStr()
|
|
|
|
result.message = message.asStr()
|
|
|
|
|
|
|
|
|
|
|
|
proc newRecursionError*(message: string): ptr JAPLException =
|
|
|
|
result = allocateObj(JAPLException, ObjectType.Exception)
|
|
|
|
result.errName = "RecursionError".asStr()
|
|
|
|
result.message = message.asStr()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
proc newTypeError*(message: string): ptr JAPLException =
|
|
|
|
result = allocateObj(JAPLException, ObjectType.Exception)
|
|
|
|
result.errName = "TypeError".asStr()
|
|
|
|
result.message = message.asStr()
|
|
|
|
|
|
|
|
|
|
|
|
## Exposed object methods used in the JAPL runtime
|
|
|
|
## are defined and implemented below
|
|
|
|
|
|
|
|
|
|
|
|
# Implementations for typeName
|
|
|
|
|
|
|
|
proc typeName(self: ptr Function): string =
|
2020-10-26 20:29:35 +01:00
|
|
|
result = "function"
|
|
|
|
|
2020-10-27 14:38:28 +01:00
|
|
|
|
|
|
|
proc typeName(self: ptr String): string =
|
2020-10-26 20:29:35 +01:00
|
|
|
return "string"
|
|
|
|
|
2020-10-27 14:38:28 +01:00
|
|
|
|
|
|
|
proc typeName(self: ptr Integer): string =
|
2020-10-26 20:29:35 +01:00
|
|
|
result = "integer"
|
|
|
|
|
2020-10-27 14:38:28 +01:00
|
|
|
|
2020-10-27 18:59:36 +01:00
|
|
|
proc typeName(self: ptr NotANumber): string =
|
|
|
|
result = "float"
|
|
|
|
|
|
|
|
|
2020-10-27 14:38:28 +01:00
|
|
|
proc typeName(self: ptr Float): string =
|
2020-10-26 20:29:35 +01:00
|
|
|
result = "float"
|
|
|
|
|
2020-10-27 14:38:28 +01:00
|
|
|
|
2020-10-27 18:59:36 +01:00
|
|
|
proc typeName(self: ptr Infinity): string =
|
|
|
|
result = "infinity"
|
|
|
|
|
|
|
|
|
|
|
|
proc typeName(self: ptr Nil): string =
|
|
|
|
result = "nil"
|
|
|
|
|
|
|
|
|
2020-10-27 14:38:28 +01:00
|
|
|
proc typeName(self: ptr Bool): string =
|
2020-10-26 20:29:35 +01:00
|
|
|
result = "bool"
|
|
|
|
|
2020-10-27 14:38:28 +01:00
|
|
|
|
|
|
|
proc typeName*(self: ptr Obj): string =
|
|
|
|
## Returns the name of the object's type
|
|
|
|
case self.kind:
|
|
|
|
of ObjectType.BaseObject:
|
|
|
|
result = "object"
|
|
|
|
of ObjectType.String:
|
|
|
|
result = cast[ptr String](self).typeName()
|
|
|
|
of ObjectType.Integer:
|
|
|
|
result = cast[ptr Integer](self).typeName()
|
|
|
|
of ObjectType.Float:
|
|
|
|
result = cast[ptr Float](self).typeName()
|
|
|
|
of ObjectType.Bool:
|
|
|
|
result = cast[ptr Bool](self).typeName()
|
|
|
|
of ObjectType.Function:
|
|
|
|
result = cast[ptr Function](self).typeName()
|
|
|
|
of ObjectType.Infinity:
|
|
|
|
result = cast[ptr Infinity](self).typeName()
|
|
|
|
of ObjectType.NotANumber:
|
|
|
|
result = cast[ptr NotANumber](self).typeName()
|
|
|
|
of ObjectType.Nil:
|
|
|
|
result = cast[ptr Nil](self).typeName()
|
|
|
|
else:
|
|
|
|
discard # TODO
|
|
|
|
|
|
|
|
|
2020-10-26 20:29:35 +01:00
|
|
|
# Implementations for stringify
|
|
|
|
|
|
|
|
proc stringify*(self: ptr Integer): string =
|
2020-10-26 16:29:00 +01:00
|
|
|
result = $self.intValue
|
|
|
|
|
|
|
|
|
2020-10-26 20:29:35 +01:00
|
|
|
proc stringify*(self: ptr String): string =
|
|
|
|
result = ""
|
|
|
|
for i in 0..<self.len:
|
|
|
|
result = result & (&"{self.str[i]}")
|
|
|
|
|
|
|
|
|
|
|
|
proc stringify*(self: ptr Float): string =
|
2020-10-26 16:29:00 +01:00
|
|
|
result = $self.floatValue
|
|
|
|
|
2020-10-26 20:29:35 +01:00
|
|
|
|
|
|
|
proc stringify*(self: ptr Bool): string =
|
|
|
|
result = $self.boolValue
|
|
|
|
|
|
|
|
|
|
|
|
proc stringify(self: ptr NotANumber): string =
|
|
|
|
result = "nan"
|
|
|
|
|
|
|
|
|
|
|
|
proc stringify(self: ptr Infinity): string =
|
|
|
|
if self.isNegative:
|
|
|
|
result = "-inf"
|
2020-10-26 16:29:00 +01:00
|
|
|
else:
|
2020-10-26 20:29:35 +01:00
|
|
|
result = "inf"
|
|
|
|
|
2020-10-27 14:38:28 +01:00
|
|
|
|
2020-10-26 20:29:35 +01:00
|
|
|
proc stringify(self: ptr Nil): string =
|
|
|
|
result = "nil"
|
|
|
|
|
2020-10-26 16:29:00 +01:00
|
|
|
|
2020-10-26 20:29:35 +01:00
|
|
|
proc stringify*(self: ptr JAPLException): string =
|
|
|
|
result = &"{self.errName.stringify()}: {self.message.stringify()}"
|
2020-10-26 16:29:00 +01:00
|
|
|
|
|
|
|
|
2020-10-26 20:29:35 +01:00
|
|
|
proc stringify*(self: ptr Function): string =
|
|
|
|
if self.name != nil:
|
|
|
|
result = &"<function {self.name.stringify()}>"
|
|
|
|
else:
|
|
|
|
result = "<code object>"
|
|
|
|
|
2020-10-27 14:38:28 +01:00
|
|
|
|
|
|
|
proc stringify*(self: ptr Obj): string =
|
2020-10-26 20:29:35 +01:00
|
|
|
## Returns a string representation of the
|
|
|
|
## given object
|
|
|
|
case self.kind:
|
|
|
|
of ObjectType.BaseObject:
|
|
|
|
result = "<object>"
|
|
|
|
of ObjectType.String:
|
|
|
|
result = cast[ptr String](self).stringify()
|
|
|
|
of ObjectType.Integer:
|
|
|
|
result = cast[ptr Integer](self).stringify()
|
|
|
|
of ObjectType.Float:
|
|
|
|
result = cast[ptr Float](self).stringify()
|
|
|
|
of ObjectType.Bool:
|
|
|
|
result = cast[ptr Bool](self).stringify()
|
|
|
|
of ObjectType.Function:
|
|
|
|
result = cast[ptr Function](self).stringify()
|
|
|
|
of ObjectType.Infinity:
|
|
|
|
result = cast[ptr Infinity](self).stringify()
|
|
|
|
of ObjectType.NotANumber:
|
|
|
|
result = cast[ptr NotANumber](self).stringify()
|
|
|
|
of ObjectType.Nil:
|
|
|
|
result = cast[ptr Nil](self).stringify()
|
|
|
|
else:
|
|
|
|
discard # TODO
|
|
|
|
|
|
|
|
|
|
|
|
# Implementations for isFalsey
|
|
|
|
|
|
|
|
|
|
|
|
proc isFalsey(self: ptr String): bool =
|
2020-10-26 16:29:00 +01:00
|
|
|
result = self.len == 0
|
|
|
|
|
2020-10-25 15:08:08 +01:00
|
|
|
|
2020-10-26 20:29:35 +01:00
|
|
|
proc isFalsey(self: ptr Function): bool =
|
|
|
|
result = false
|
|
|
|
|
|
|
|
|
|
|
|
proc isFalsey(self: ptr Integer): bool =
|
|
|
|
result = self.intValue == 0
|
2020-10-25 15:08:08 +01:00
|
|
|
|
2020-10-26 16:29:00 +01:00
|
|
|
|
2020-10-26 20:29:35 +01:00
|
|
|
proc isFalsey(self: ptr Float): bool =
|
|
|
|
result = self.floatValue == 0.0
|
|
|
|
|
|
|
|
|
2020-10-27 14:38:28 +01:00
|
|
|
proc isFalsey(self: ptr Bool): bool =
|
2020-10-26 20:29:35 +01:00
|
|
|
result = not self.boolValue
|
|
|
|
|
|
|
|
|
2020-10-27 14:38:28 +01:00
|
|
|
proc isFalsey(self: ptr Infinity): bool =
|
2020-10-26 20:29:35 +01:00
|
|
|
result = false
|
|
|
|
|
|
|
|
|
|
|
|
proc isFalsey(self: ptr NotANumber): bool =
|
|
|
|
result = true
|
|
|
|
|
|
|
|
|
|
|
|
proc isFalsey(self: ptr Nil): bool =
|
|
|
|
result = true
|
|
|
|
|
|
|
|
|
|
|
|
proc isFalsey*(self: ptr Obj): bool =
|
|
|
|
## Returns true if the object is
|
|
|
|
## falsey, true otherwise
|
|
|
|
case self.kind:
|
|
|
|
of ObjectType.BaseObject:
|
|
|
|
result = false
|
|
|
|
of ObjectType.String:
|
|
|
|
result = cast[ptr String](self).isFalsey()
|
|
|
|
of ObjectType.Integer:
|
|
|
|
result = cast[ptr Integer](self).isFalsey()
|
|
|
|
of ObjectType.Float:
|
|
|
|
result = cast[ptr Float](self).isFalsey()
|
|
|
|
of ObjectType.Bool:
|
|
|
|
result = cast[ptr Bool](self).isFalsey()
|
|
|
|
of ObjectType.Function:
|
|
|
|
result = cast[ptr Function](self).isFalsey()
|
|
|
|
of ObjectType.Infinity:
|
|
|
|
result = cast[ptr Infinity](self).isFalsey()
|
|
|
|
of ObjectType.NotANumber:
|
|
|
|
result = cast[ptr NotANumber](self).isFalsey()
|
|
|
|
of ObjectType.Nil:
|
|
|
|
result = cast[ptr Nil](self).isFalsey()
|
|
|
|
else:
|
|
|
|
discard # TODO
|
|
|
|
|
|
|
|
# Implementation for hash
|
|
|
|
|
|
|
|
proc hash(self: ptr String): uint64 =
|
|
|
|
result = 2166136261u
|
2020-10-25 15:08:08 +01:00
|
|
|
var i = 0
|
|
|
|
while i < self.len:
|
2020-10-26 20:29:35 +01:00
|
|
|
result = result xor uint64 self.str[i]
|
2020-10-25 15:08:08 +01:00
|
|
|
result *= 16777619
|
|
|
|
i += 1
|
|
|
|
return result
|
|
|
|
|
2020-10-26 20:29:35 +01:00
|
|
|
proc hash(self: ptr Float): uint64 =
|
|
|
|
result = 2166136261u xor uint64 self.floatValue # TODO: Improve this
|
|
|
|
result *= 16777619
|
|
|
|
|
2020-10-25 15:08:08 +01:00
|
|
|
|
2020-10-26 20:29:35 +01:00
|
|
|
proc hash(self: ptr Infinity): uint64 =
|
|
|
|
# TODO: Arbitrary hash seems a bad idea
|
|
|
|
if self.isNegative:
|
|
|
|
result = 1u
|
|
|
|
else:
|
|
|
|
result = 0u
|
|
|
|
|
|
|
|
|
|
|
|
proc hash(self: ptr NotANumber): uint64 =
|
|
|
|
# TODO: Hashable?
|
|
|
|
raise newException(NotImplementedError, "unhashable type 'nan'")
|
|
|
|
|
|
|
|
|
|
|
|
proc hash(self: ptr Nil): uint64 =
|
|
|
|
# TODO: Arbitrary hash seems a bad idea
|
|
|
|
result = 2u
|
|
|
|
|
2020-10-27 14:38:28 +01:00
|
|
|
proc hash(self: ptr Function): uint64 =
|
2020-10-26 20:29:35 +01:00
|
|
|
# TODO: Hashable?
|
|
|
|
raise newException(NotImplementedError, "unhashable type 'function'")
|
|
|
|
|
|
|
|
|
|
|
|
proc hash*(self: ptr Obj): uint64 =
|
|
|
|
## Returns the hash of the object using
|
|
|
|
## the FNV-1a algorithm (or a predefined value).
|
|
|
|
## Raises an error if the object is not hashable
|
2020-10-27 14:38:28 +01:00
|
|
|
if not self.isHashable:
|
|
|
|
raise newException(NotImplementedError, &"unhashable type '{self.typeName}'")
|
2020-10-26 20:29:35 +01:00
|
|
|
case self.kind:
|
|
|
|
of ObjectType.BaseObject:
|
|
|
|
result = 2166136261u # Constant hash
|
|
|
|
of ObjectType.String:
|
|
|
|
result = cast[ptr String](self).hash()
|
|
|
|
of ObjectType.Integer:
|
|
|
|
result = cast[ptr Integer](self).hash()
|
|
|
|
of ObjectType.Float:
|
|
|
|
result = cast[ptr Float](self).hash()
|
|
|
|
of ObjectType.Bool:
|
|
|
|
result = cast[ptr Bool](self).hash()
|
|
|
|
of ObjectType.Function:
|
|
|
|
result = cast[ptr Function](self).hash()
|
|
|
|
of ObjectType.Infinity:
|
|
|
|
result = cast[ptr Infinity](self).hash()
|
|
|
|
of ObjectType.NotANumber:
|
|
|
|
result = cast[ptr NotANumber](self).hash()
|
|
|
|
of ObjectType.Nil:
|
|
|
|
result = cast[ptr Nil](self).hash()
|
|
|
|
else:
|
|
|
|
discard # TODO
|
|
|
|
|
|
|
|
|
|
|
|
# Implementation for eq
|
|
|
|
|
|
|
|
proc eq(self, other: ptr String): bool =
|
|
|
|
if self.len != other.len:
|
2020-10-25 15:08:08 +01:00
|
|
|
return false
|
2020-10-26 20:29:35 +01:00
|
|
|
elif self.hash != other.hash:
|
2020-10-25 15:08:08 +01:00
|
|
|
return false
|
2020-10-26 20:29:35 +01:00
|
|
|
for i in 0..self.len - 1:
|
|
|
|
if self.str[i] != other.str[i]:
|
2020-10-25 15:08:08 +01:00
|
|
|
return false
|
2020-10-26 20:29:35 +01:00
|
|
|
result = true
|
|
|
|
|
|
|
|
|
|
|
|
proc eq(self, other: ptr Integer): bool =
|
|
|
|
result = self.intValue == other.intValue
|
|
|
|
|
|
|
|
|
|
|
|
proc eq(self, other: ptr Float): bool =
|
|
|
|
result = self.floatValue == other.floatValue
|
|
|
|
|
|
|
|
|
|
|
|
proc eq(self, other: ptr Bool): bool =
|
|
|
|
result = self.boolValue == other.boolValue
|
|
|
|
|
|
|
|
|
|
|
|
proc eq(self, other: ptr Function): bool =
|
2020-10-27 18:59:36 +01:00
|
|
|
result = self.name.stringify() == other.name.stringify() # Since in JAPL functions cannot
|
|
|
|
# be overridden, if two function names are equal they are also the same
|
|
|
|
# function object (TODO: Verify this)
|
2020-10-25 15:08:08 +01:00
|
|
|
|
|
|
|
|
2020-10-26 20:29:35 +01:00
|
|
|
proc eq(self, other: ptr NotANumber): bool =
|
2020-10-27 18:59:36 +01:00
|
|
|
result = false # As per IEEE 754 spec, nan != nan
|
2020-10-26 20:29:35 +01:00
|
|
|
|
|
|
|
|
|
|
|
proc eq(self, other: ptr Nil): bool =
|
|
|
|
result = true
|
|
|
|
|
|
|
|
|
|
|
|
proc eq(self, other: ptr Infinity): bool =
|
|
|
|
result = self.isNegative == other.isNegative
|
|
|
|
|
|
|
|
|
|
|
|
proc eq*(self, other: ptr Obj): bool =
|
|
|
|
## Compares two objects for equality,
|
|
|
|
## returns true if self equals other
|
|
|
|
## and false otherwise
|
2020-10-27 18:59:36 +01:00
|
|
|
if self.kind != other.kind: # If the types are different it's not
|
|
|
|
# even worth going any further (and you couldn't anyway)
|
2020-10-26 20:29:35 +01:00
|
|
|
return false
|
|
|
|
case self.kind:
|
|
|
|
of ObjectType.BaseObject:
|
|
|
|
result = other.kind == ObjectType.BaseObject
|
|
|
|
of ObjectType.String:
|
|
|
|
var self = cast[ptr String](self)
|
|
|
|
var other = cast[ptr String](other)
|
|
|
|
result = self.eq(other)
|
|
|
|
of ObjectType.Integer:
|
|
|
|
var self = cast[ptr Integer](self)
|
|
|
|
var other = cast[ptr Integer](other)
|
|
|
|
result = self.eq(other)
|
|
|
|
of ObjectType.Float:
|
|
|
|
var self = cast[ptr Float](self)
|
|
|
|
var other = cast[ptr Float](other)
|
|
|
|
result = self.eq(other)
|
|
|
|
of ObjectType.Bool:
|
|
|
|
var self = cast[ptr Bool](self)
|
|
|
|
var other = cast[ptr Bool](other)
|
|
|
|
result = self.eq(other)
|
|
|
|
of ObjectType.Function:
|
|
|
|
var self = cast[ptr Function](self)
|
|
|
|
var other = cast[ptr Function](other)
|
|
|
|
result = self.eq(other)
|
2020-10-27 18:59:36 +01:00
|
|
|
of ObjectType.Infinity:
|
|
|
|
var self = cast[ptr Infinity](self)
|
|
|
|
var other = cast[ptr Infinity](other)
|
|
|
|
result = self.eq(other)
|
|
|
|
of ObjectType.NotANumber:
|
|
|
|
var self = cast[ptr NotANumber](self)
|
|
|
|
var other = cast[ptr NotANumber](other)
|
|
|
|
result = self.eq(other)
|
|
|
|
of ObjectType.Nil:
|
|
|
|
var self = cast[ptr Nil](self)
|
|
|
|
var other = cast[ptr Nil](other)
|
|
|
|
result = self.eq(other)
|
2020-10-26 20:29:35 +01:00
|
|
|
else:
|
|
|
|
discard # TODO
|
|
|
|
|
|
|
|
|
2020-10-27 18:59:36 +01:00
|
|
|
proc negate(self: ptr Integer): ptr Integer =
|
|
|
|
result = (-self.toInt()).asInt()
|
|
|
|
|
|
|
|
|
|
|
|
proc negate(self: ptr Float): ptr Float =
|
|
|
|
result = (-self.toFloat()).asFloat()
|
|
|
|
|
|
|
|
|
|
|
|
proc negate(self: ptr Infinity): ptr Infinity =
|
|
|
|
result = asInf()
|
|
|
|
result.isNegative = true
|
|
|
|
|
|
|
|
|
|
|
|
proc negate*(self: ptr Obj): ptr Obj =
|
|
|
|
## Returns the result of -self or
|
|
|
|
## raises an error if the operation
|
|
|
|
## is unsupported
|
|
|
|
case self.kind:
|
|
|
|
of ObjectType.Integer:
|
|
|
|
result = cast[ptr Integer](self).negate()
|
|
|
|
of ObjectType.Float:
|
|
|
|
result = cast[ptr Float](self).negate()
|
|
|
|
of ObjectType.Infinity:
|
|
|
|
result = cast[ptr Infinity](self).negate()
|
|
|
|
else:
|
|
|
|
raise newException(NotImplementedError, &"unsupported unary operator '-' for object of type '{self.typeName()}'")
|
|
|
|
|
|
|
|
|
|
|
|
proc lt(self: ptr Integer, other: ptr Obj): bool =
|
|
|
|
case other.kind:
|
|
|
|
of ObjectType.Integer:
|
|
|
|
result = self.intValue < cast[ptr Integer](other).intValue
|
|
|
|
of ObjectType.Float:
|
|
|
|
result = (float self.intValue) < cast[ptr Float](other).floatValue
|
|
|
|
of ObjectType.Infinity:
|
|
|
|
let other = cast[ptr Infinity](other)
|
|
|
|
if other.isNegative:
|
|
|
|
result = false
|
|
|
|
else:
|
|
|
|
result = true
|
|
|
|
else:
|
|
|
|
raise newException(NotImplementedError, &"unsupported binary operator '<' for object of type '{self.typeName()}'")
|
|
|
|
|
|
|
|
|
|
|
|
proc lt(self: ptr Float, other: ptr Obj): bool =
|
|
|
|
case other.kind:
|
|
|
|
of ObjectType.Integer:
|
|
|
|
result = self.floatValue < (float cast[ptr Integer](other).intValue)
|
|
|
|
of ObjectType.Float:
|
|
|
|
result = self.floatValue < cast[ptr Float](other).floatValue
|
|
|
|
of ObjectType.Infinity:
|
|
|
|
let other = cast[ptr Infinity](other)
|
|
|
|
if other.isNegative:
|
|
|
|
result = false
|
|
|
|
else:
|
|
|
|
result = true
|
|
|
|
else:
|
|
|
|
raise newException(NotImplementedError, &"unsupported binary operator '<' for object of type '{self.typeName()}'")
|
|
|
|
|
|
|
|
|
|
|
|
proc lt(self: ptr Infinity, other: ptr Obj): bool =
|
|
|
|
case other.kind:
|
|
|
|
of ObjectType.Integer:
|
|
|
|
let other = cast[ptr Integer](other)
|
|
|
|
if self.isNegative and other.intValue > 0:
|
|
|
|
result = true
|
|
|
|
else:
|
|
|
|
result = false
|
|
|
|
of ObjectType.Float:
|
|
|
|
let other = cast[ptr Float](other)
|
|
|
|
if self.isNegative and other.floatValue > 0.0:
|
|
|
|
result = true
|
|
|
|
else:
|
|
|
|
result = false
|
|
|
|
of ObjectType.Infinity:
|
|
|
|
let other = cast[ptr Infinity](other)
|
|
|
|
if other.isNegative and not self.isNegative:
|
|
|
|
result = false
|
|
|
|
else:
|
|
|
|
result = false
|
|
|
|
else:
|
|
|
|
raise newException(NotImplementedError, &"unsupported binary operator '<' for object of type '{self.typeName()}'")
|
|
|
|
|
|
|
|
|
|
|
|
proc lt*(self: ptr Obj, other: ptr Obj): bool =
|
|
|
|
## Returns the result of self < other or
|
|
|
|
## raises an error if the operation
|
|
|
|
## is unsupported
|
|
|
|
case self.kind:
|
|
|
|
of ObjectType.Integer:
|
|
|
|
result = cast[ptr Integer](self).lt(other)
|
|
|
|
of ObjectType.Float:
|
|
|
|
result = cast[ptr Float](self).lt(other)
|
|
|
|
of ObjectType.Infinity:
|
|
|
|
result = cast[ptr Infinity](self).lt(other)
|
|
|
|
else:
|
|
|
|
raise newException(NotImplementedError, &"unsupported binary operator '<' for object of type '{self.typeName()}'")
|
|
|
|
|
|
|
|
|
|
|
|
proc gt(self: ptr Integer, other: ptr Obj): bool =
|
|
|
|
case other.kind:
|
|
|
|
of ObjectType.Integer:
|
|
|
|
result = self.intValue > cast[ptr Integer](other).intValue
|
|
|
|
of ObjectType.Float:
|
|
|
|
result = (float self.intValue) > cast[ptr Float](other).floatValue
|
|
|
|
of ObjectType.Infinity:
|
|
|
|
let other = cast[ptr Infinity](other)
|
|
|
|
if other.isNegative:
|
|
|
|
result = true
|
|
|
|
else:
|
|
|
|
result = false
|
|
|
|
else:
|
|
|
|
raise newException(NotImplementedError, &"unsupported binary operator '>' for object of type '{self.typeName()}'")
|
|
|
|
|
|
|
|
|
|
|
|
proc gt(self: ptr Float, other: ptr Obj): bool =
|
|
|
|
case other.kind:
|
|
|
|
of ObjectType.Integer:
|
|
|
|
result = self.floatValue > (float cast[ptr Integer](other).intValue)
|
|
|
|
of ObjectType.Float:
|
|
|
|
result = self.floatValue > cast[ptr Float](other).floatValue
|
|
|
|
of ObjectType.Infinity:
|
|
|
|
let other = cast[ptr Infinity](other)
|
|
|
|
if other.isNegative:
|
|
|
|
result = true
|
|
|
|
else:
|
|
|
|
result = false
|
|
|
|
else:
|
|
|
|
raise newException(NotImplementedError, &"unsupported binary operator '>' for object of type '{self.typeName()}'")
|
|
|
|
|
|
|
|
|
|
|
|
proc gt(self: ptr Infinity, other: ptr Obj): bool =
|
|
|
|
case other.kind:
|
|
|
|
of ObjectType.Integer:
|
|
|
|
let other = cast[ptr Integer](other)
|
|
|
|
if self.isNegative and other.intValue > 0:
|
|
|
|
result = false
|
|
|
|
else:
|
|
|
|
result = true
|
|
|
|
of ObjectType.Float:
|
|
|
|
let other = cast[ptr Float](other)
|
|
|
|
if self.isNegative and other.floatValue > 0.0:
|
|
|
|
result = false
|
|
|
|
else:
|
|
|
|
result = true
|
|
|
|
of ObjectType.Infinity:
|
|
|
|
let other = cast[ptr Infinity](other)
|
|
|
|
if other.isNegative and not self.isNegative:
|
|
|
|
result = true
|
|
|
|
else:
|
|
|
|
result = false
|
|
|
|
else:
|
|
|
|
raise newException(NotImplementedError, &"unsupported binary operator '>' for object of type '{self.typeName()}'")
|
|
|
|
|
|
|
|
|
|
|
|
proc gt*(self: ptr Obj, other: ptr Obj): bool =
|
|
|
|
## Returns the result of self < other or
|
|
|
|
## raises an error if the operation
|
|
|
|
## is unsupported
|
|
|
|
case self.kind:
|
|
|
|
of ObjectType.Integer:
|
|
|
|
result = cast[ptr Integer](self).gt(other)
|
|
|
|
of ObjectType.Float:
|
|
|
|
result = cast[ptr Float](self).gt(other)
|
|
|
|
of ObjectType.Infinity:
|
|
|
|
result = cast[ptr Infinity](self).gt(other)
|
|
|
|
else:
|
|
|
|
raise newException(NotImplementedError, &"unsupported binary operator '>' for object of type '{self.typeName()}'")
|
|
|
|
|
|
|
|
|
|
|
|
proc sum(self: ptr Infinity, other: ptr Obj): ptr Infinity =
|
|
|
|
result = asInf()
|
|
|
|
case other.kind:
|
|
|
|
of ObjectType.Infinity:
|
|
|
|
var other = cast[ptr Infinity](other)
|
|
|
|
if self.isNegative or other.isNegative:
|
|
|
|
result.isNegative = true
|
|
|
|
of ObjectType.Integer, ObjectType.Float:
|
|
|
|
discard
|
|
|
|
else:
|
|
|
|
raise newException(NotImplementedError, &"unsupported binary operator '+' for objects of type '{self.typeName()}' and '{other.typeName()}'")
|
|
|
|
|
|
|
|
|
|
|
|
proc sum(self: ptr NotANumber, other: ptr Obj): ptr NotANumber =
|
|
|
|
result = asNan()
|
|
|
|
case other.kind:
|
|
|
|
of ObjectType.NotANumber, ObjectType.Integer, ObjectType.Float:
|
|
|
|
discard
|
|
|
|
else:
|
|
|
|
raise newException(NotImplementedError, &"unsupported binary operator '+' for objects of type '{self.typeName()}' and '{other.typeName()}'")
|
|
|
|
|
|
|
|
|
|
|
|
|
2020-10-27 14:38:28 +01:00
|
|
|
proc sum(self: ptr String, other: ptr Obj): ptr String =
|
|
|
|
if other.kind == ObjectType.String:
|
|
|
|
var other = cast[ptr String](other)
|
|
|
|
var selfStr = self.toStr()
|
|
|
|
var otherStr = other.toStr()
|
|
|
|
result = (selfStr & otherStr).asStr()
|
|
|
|
else:
|
|
|
|
raise newException(NotImplementedError, &"unsupported binary operator '+' for objects of type '{self.typeName()}' and '{other.typeName()}'")
|
2020-10-25 15:08:08 +01:00
|
|
|
|
|
|
|
|
2020-10-27 14:38:28 +01:00
|
|
|
proc sum(self: ptr Integer, other: ptr Obj): ptr Obj = # This can yield a float!
|
|
|
|
case other.kind:
|
|
|
|
of ObjectType.Integer:
|
|
|
|
result = (self.toInt() + cast[ptr Integer](other).toInt()).asInt()
|
|
|
|
of ObjectType.Float:
|
|
|
|
let res = ((float self.toInt()) + cast[ptr Float](other).toFloat())
|
|
|
|
if res == system.Inf:
|
|
|
|
result = asInf()
|
|
|
|
elif res == -system.Inf:
|
|
|
|
let negInf = asInf()
|
|
|
|
negInf.isNegative = true
|
|
|
|
result = negInf
|
|
|
|
else:
|
|
|
|
result = res.asFloat()
|
|
|
|
of ObjectType.NotANumber:
|
|
|
|
result = asNan()
|
|
|
|
of ObjectType.Infinity:
|
|
|
|
result = cast[ptr Infinity](other)
|
|
|
|
else:
|
|
|
|
raise newException(NotImplementedError, &"unsupported binary operator '+' for objects of type '{self.typeName()}' and '{other.typeName()}'")
|
2020-10-25 15:08:08 +01:00
|
|
|
|
|
|
|
|
2020-10-27 14:38:28 +01:00
|
|
|
proc sum(self: ptr Float, other: ptr Obj): ptr Obj =
|
|
|
|
case other.kind:
|
|
|
|
of ObjectType.Integer:
|
|
|
|
result = (self.toFloat() + float cast[ptr Integer](other).toInt()).asFloat()
|
|
|
|
of ObjectType.Float:
|
|
|
|
let res = (self.toFloat() + cast[ptr Float](other).toFloat())
|
|
|
|
if res == system.Inf:
|
|
|
|
result = asInf()
|
|
|
|
elif res == -system.Inf:
|
|
|
|
let negInf = asInf()
|
|
|
|
negInf.isNegative = true
|
|
|
|
result = negInf
|
|
|
|
else:
|
|
|
|
result = res.asFloat()
|
|
|
|
of ObjectType.NotANumber:
|
|
|
|
result = asNan()
|
|
|
|
of ObjectType.Infinity:
|
|
|
|
result = cast[ptr Infinity](other)
|
|
|
|
else:
|
|
|
|
raise newException(NotImplementedError, &"unsupported binary operator '+' for objects of type '{self.typeName()}' and '{other.typeName()}'")
|
2020-08-23 12:10:08 +02:00
|
|
|
|
2020-10-24 20:48:10 +02:00
|
|
|
|
2020-10-27 14:38:28 +01:00
|
|
|
proc sum*(self, other: ptr Obj): ptr Obj =
|
2020-10-19 16:19:49 +02:00
|
|
|
## Returns the result of self + other
|
2020-10-27 14:38:28 +01:00
|
|
|
## or raises NotImplementedError if the operation is unsupported
|
|
|
|
case self.kind:
|
|
|
|
of ObjectType.String: # Here we don't cast other (yet)
|
|
|
|
# because binary operators can mix types together,
|
|
|
|
# like in "hello" * 5, or 3.5 * 8. Casting that
|
|
|
|
# later allows for finer error reporting and keeps
|
|
|
|
# these methods as generic as possible
|
|
|
|
result = cast[ptr String](self).sum(other)
|
|
|
|
of ObjectType.Integer:
|
|
|
|
result = cast[ptr Integer](self).sum(other)
|
|
|
|
of ObjectType.Float:
|
|
|
|
result = cast[ptr Float](self).sum(other)
|
2020-10-27 18:59:36 +01:00
|
|
|
of ObjectType.NotANumber:
|
|
|
|
result = cast[ptr NotANumber](self).sum(other)
|
|
|
|
of ObjectType.Infinity:
|
|
|
|
result = cast[ptr Infinity](self).sum(other)
|
|
|
|
else:
|
|
|
|
raise newException(NotImplementedError, &"unsupported binary operator '+' for objects of type '{self.typeName()}' and '{other.typeName()}'")
|
|
|
|
|
|
|
|
|
|
|
|
proc sub(self: ptr Infinity, other: ptr Obj): ptr Infinity =
|
|
|
|
result = asInf()
|
|
|
|
case other.kind:
|
|
|
|
of ObjectType.Infinity:
|
|
|
|
var other = cast[ptr Infinity](other)
|
|
|
|
if self.isNegative or other.isNegative:
|
|
|
|
result.isNegative = true
|
|
|
|
of ObjectType.Integer, ObjectType.Float:
|
|
|
|
discard
|
|
|
|
else:
|
|
|
|
raise newException(NotImplementedError, &"unsupported binary operator '+' for objects of type '{self.typeName()}' and '{other.typeName()}'")
|
|
|
|
|
|
|
|
|
|
|
|
proc sub(self: ptr NotANumber, other: ptr Obj): ptr NotANumber =
|
|
|
|
result = asNan()
|
|
|
|
case other.kind:
|
|
|
|
of ObjectType.NotANumber, ObjectType.Integer, ObjectType.Float:
|
|
|
|
discard
|
|
|
|
else:
|
|
|
|
raise newException(NotImplementedError, &"unsupported binary operator '+' for objects of type '{self.typeName()}' and '{other.typeName()}'")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
proc sub(self: ptr Integer, other: ptr Obj): ptr Obj = # This can yield a float!
|
|
|
|
case other.kind:
|
|
|
|
of ObjectType.Integer:
|
|
|
|
result = (self.toInt() - cast[ptr Integer](other).toInt()).asInt()
|
|
|
|
of ObjectType.Float:
|
|
|
|
let res = ((float self.toInt()) - cast[ptr Float](other).toFloat())
|
|
|
|
if res == system.Inf:
|
|
|
|
result = asInf()
|
|
|
|
elif res == -system.Inf:
|
|
|
|
let negInf = asInf()
|
|
|
|
negInf.isNegative = true
|
|
|
|
result = negInf
|
|
|
|
else:
|
|
|
|
result = res.asFloat()
|
|
|
|
of ObjectType.NotANumber:
|
|
|
|
result = asNan()
|
|
|
|
of ObjectType.Infinity:
|
|
|
|
result = cast[ptr Infinity](other)
|
|
|
|
else:
|
|
|
|
raise newException(NotImplementedError, &"unsupported binary operator '+' for objects of type '{self.typeName()}' and '{other.typeName()}'")
|
|
|
|
|
|
|
|
|
|
|
|
proc sub(self: ptr Float, other: ptr Obj): ptr Obj =
|
|
|
|
case other.kind:
|
|
|
|
of ObjectType.Integer:
|
|
|
|
result = (self.toFloat() - float cast[ptr Integer](other).toInt()).asFloat()
|
|
|
|
of ObjectType.Float:
|
|
|
|
let res = (self.toFloat() - cast[ptr Float](other).toFloat())
|
|
|
|
if res == system.Inf:
|
|
|
|
result = asInf()
|
|
|
|
elif res == -system.Inf:
|
|
|
|
let negInf = asInf()
|
|
|
|
negInf.isNegative = true
|
|
|
|
result = negInf
|
|
|
|
else:
|
|
|
|
result = res.asFloat()
|
|
|
|
of ObjectType.NotANumber:
|
|
|
|
result = asNan()
|
|
|
|
of ObjectType.Infinity:
|
|
|
|
result = cast[ptr Infinity](other)
|
2020-10-27 14:38:28 +01:00
|
|
|
else:
|
|
|
|
raise newException(NotImplementedError, &"unsupported binary operator '+' for objects of type '{self.typeName()}' and '{other.typeName()}'")
|
2020-10-19 16:19:49 +02:00
|
|
|
|
|
|
|
|
2020-10-27 18:59:36 +01:00
|
|
|
proc sub*(self, other: ptr Obj): ptr Obj =
|
2020-10-19 16:19:49 +02:00
|
|
|
## Returns the result of self - other
|
2020-10-27 14:38:28 +01:00
|
|
|
## or raises NotImplementedError if the operation is unsupported
|
2020-10-27 18:59:36 +01:00
|
|
|
case self.kind:
|
|
|
|
of ObjectType.Integer:
|
|
|
|
result = cast[ptr Integer](self).sub(other)
|
|
|
|
of ObjectType.Float:
|
|
|
|
result = cast[ptr Float](self).sub(other)
|
|
|
|
of ObjectType.NotANumber:
|
|
|
|
result = cast[ptr NotANumber](self).sub(other)
|
|
|
|
of ObjectType.Infinity:
|
|
|
|
result = cast[ptr Infinity](self).sub(other)
|
|
|
|
else:
|
|
|
|
raise newException(NotImplementedError, &"unsupported binary operator '+' for objects of type '{self.typeName()}' and '{other.typeName()}'")
|
|
|
|
|
|
|
|
|
|
|
|
proc mul(self: ptr Infinity, other: ptr Obj): ptr Infinity =
|
|
|
|
result = asInf()
|
|
|
|
case other.kind:
|
|
|
|
of ObjectType.Infinity:
|
|
|
|
var other = cast[ptr Infinity](other)
|
|
|
|
if self.isNegative or other.isNegative:
|
|
|
|
result.isNegative = true
|
|
|
|
of ObjectType.Integer, ObjectType.Float:
|
|
|
|
discard
|
|
|
|
else:
|
|
|
|
raise newException(NotImplementedError, &"unsupported binary operator '+' for objects of type '{self.typeName()}' and '{other.typeName()}'")
|
|
|
|
|
|
|
|
|
|
|
|
proc mul(self: ptr NotANumber, other: ptr Obj): ptr NotANumber =
|
|
|
|
result = asNan()
|
|
|
|
case other.kind:
|
|
|
|
of ObjectType.NotANumber, ObjectType.Integer, ObjectType.Float:
|
|
|
|
discard
|
|
|
|
else:
|
|
|
|
raise newException(NotImplementedError, &"unsupported binary operator '*' for objects of type '{self.typeName()}' and '{other.typeName()}'")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
proc mul(self: ptr Integer, other: ptr Obj): ptr Obj = # This can yield a float!
|
|
|
|
case other.kind:
|
|
|
|
of ObjectType.Integer:
|
|
|
|
result = (self.toInt() * cast[ptr Integer](other).toInt()).asInt()
|
|
|
|
of ObjectType.Float:
|
|
|
|
let res = ((float self.toInt()) * cast[ptr Float](other).toFloat())
|
|
|
|
if res == system.Inf:
|
|
|
|
result = asInf()
|
|
|
|
elif res == -system.Inf:
|
|
|
|
let negInf = asInf()
|
|
|
|
negInf.isNegative = true
|
|
|
|
result = negInf
|
|
|
|
else:
|
|
|
|
result = res.asFloat()
|
|
|
|
of ObjectType.NotANumber:
|
|
|
|
result = asNan()
|
|
|
|
of ObjectType.Infinity:
|
|
|
|
result = cast[ptr Infinity](other)
|
2020-10-28 17:19:41 +01:00
|
|
|
of ObjectType.String:
|
|
|
|
result = cast[ptr String](other).toStr().repeat(self.toInt()).asStr()
|
|
|
|
else:
|
|
|
|
raise newException(NotImplementedError, &"unsupported binary operator '*' for objects of type '{self.typeName()}' and '{other.typeName()}'")
|
|
|
|
|
|
|
|
|
|
|
|
proc mul(self: ptr String, other: ptr Obj): ptr Obj = # This can yield a float!
|
|
|
|
case other.kind:
|
|
|
|
of ObjectType.Integer:
|
|
|
|
result = self.toStr().repeat(cast[ptr Integer](other).toInt()).asStr()
|
2020-10-27 18:59:36 +01:00
|
|
|
else:
|
|
|
|
raise newException(NotImplementedError, &"unsupported binary operator '*' for objects of type '{self.typeName()}' and '{other.typeName()}'")
|
|
|
|
|
|
|
|
|
|
|
|
proc mul(self: ptr Float, other: ptr Obj): ptr Obj =
|
|
|
|
case other.kind:
|
|
|
|
of ObjectType.Integer:
|
|
|
|
result = (self.toFloat() * float cast[ptr Integer](other).toInt()).asFloat()
|
|
|
|
of ObjectType.Float:
|
|
|
|
let res = (self.toFloat() * cast[ptr Float](other).toFloat())
|
|
|
|
if res == system.Inf:
|
|
|
|
result = asInf()
|
|
|
|
elif res == -system.Inf:
|
|
|
|
let negInf = asInf()
|
|
|
|
negInf.isNegative = true
|
|
|
|
result = negInf
|
|
|
|
else:
|
|
|
|
result = res.asFloat()
|
|
|
|
of ObjectType.NotANumber:
|
|
|
|
result = asNan()
|
|
|
|
of ObjectType.Infinity:
|
|
|
|
result = cast[ptr Infinity](other)
|
|
|
|
else:
|
|
|
|
raise newException(NotImplementedError, &"unsupported binary operator '*' for objects of type '{self.typeName()}' and '{other.typeName()}'")
|
2020-10-19 16:19:49 +02:00
|
|
|
|
|
|
|
|
2020-10-27 18:59:36 +01:00
|
|
|
proc mul*(self, other: ptr Obj): ptr Obj =
|
|
|
|
## Returns the result of self + other
|
2020-10-27 14:38:28 +01:00
|
|
|
## or raises NotImplementedError if the operation is unsupported
|
2020-10-27 18:59:36 +01:00
|
|
|
case self.kind:
|
|
|
|
of ObjectType.Integer:
|
|
|
|
result = cast[ptr Integer](self).mul(other)
|
|
|
|
of ObjectType.Float:
|
|
|
|
result = cast[ptr Float](self).mul(other)
|
|
|
|
of ObjectType.NotANumber:
|
|
|
|
result = cast[ptr NotANumber](self).mul(other)
|
|
|
|
of ObjectType.Infinity:
|
|
|
|
result = cast[ptr Infinity](self).mul(other)
|
2020-10-28 17:19:41 +01:00
|
|
|
of ObjectType.String:
|
|
|
|
result = cast[ptr String](self).mul(other)
|
2020-10-27 18:59:36 +01:00
|
|
|
else:
|
|
|
|
raise newException(NotImplementedError, &"unsupported binary operator '*' for objects of type '{self.typeName()}' and '{other.typeName()}'")
|
|
|
|
|
|
|
|
|
|
|
|
proc trueDiv(self: ptr Infinity, other: ptr Obj): ptr Infinity =
|
|
|
|
result = asInf()
|
|
|
|
case other.kind:
|
|
|
|
of ObjectType.Infinity:
|
|
|
|
var other = cast[ptr Infinity](other)
|
|
|
|
if self.isNegative or other.isNegative:
|
|
|
|
result.isNegative = true
|
|
|
|
of ObjectType.Integer, ObjectType.Float:
|
|
|
|
discard
|
|
|
|
else:
|
|
|
|
raise newException(NotImplementedError, &"unsupported binary operator '/' for objects of type '{self.typeName()}' and '{other.typeName()}'")
|
|
|
|
|
|
|
|
|
|
|
|
proc trueDiv(self: ptr NotANumber, other: ptr Obj): ptr NotANumber =
|
|
|
|
result = asNan()
|
|
|
|
case other.kind:
|
|
|
|
of ObjectType.NotANumber, ObjectType.Integer, ObjectType.Float:
|
|
|
|
discard
|
|
|
|
else:
|
|
|
|
raise newException(NotImplementedError, &"unsupported binary operator '/' for objects of type '{self.typeName()}' and '{other.typeName()}'")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
proc trueDiv(self: ptr Integer, other: ptr Obj): ptr Obj =
|
|
|
|
case other.kind:
|
|
|
|
of ObjectType.Integer:
|
|
|
|
result = ((float self.toInt()) / (float cast[ptr Integer](other).toInt())).asFloat() # so that 4 / 2 == 2.0
|
|
|
|
of ObjectType.Float:
|
|
|
|
let res = ((float self.toInt()) / cast[ptr Float](other).toFloat())
|
|
|
|
if res == system.Inf:
|
|
|
|
result = asInf()
|
|
|
|
elif res == -system.Inf:
|
|
|
|
let negInf = asInf()
|
|
|
|
negInf.isNegative = true
|
|
|
|
result = negInf
|
|
|
|
else:
|
|
|
|
result = res.asFloat()
|
|
|
|
of ObjectType.NotANumber:
|
|
|
|
result = asNan()
|
|
|
|
of ObjectType.Infinity:
|
|
|
|
result = cast[ptr Infinity](other)
|
|
|
|
else:
|
|
|
|
raise newException(NotImplementedError, &"unsupported binary operator '/' for objects of type '{self.typeName()}' and '{other.typeName()}'")
|
2020-10-19 16:19:49 +02:00
|
|
|
|
|
|
|
|
2020-10-27 18:59:36 +01:00
|
|
|
proc trueDiv(self: ptr Float, other: ptr Obj): ptr Obj =
|
|
|
|
case other.kind:
|
|
|
|
of ObjectType.Integer:
|
|
|
|
result = (self.toFloat() / float cast[ptr Integer](other).toInt()).asFloat()
|
|
|
|
of ObjectType.Float:
|
|
|
|
let res = (self.toFloat() / cast[ptr Float](other).toFloat())
|
|
|
|
if res == system.Inf:
|
|
|
|
result = asInf()
|
|
|
|
elif res == -system.Inf:
|
|
|
|
let negInf = asInf()
|
|
|
|
negInf.isNegative = true
|
|
|
|
result = negInf
|
|
|
|
else:
|
|
|
|
result = res.asFloat()
|
|
|
|
of ObjectType.NotANumber:
|
|
|
|
result = asNan()
|
|
|
|
of ObjectType.Infinity:
|
|
|
|
result = cast[ptr Infinity](other)
|
|
|
|
else:
|
|
|
|
raise newException(NotImplementedError, &"unsupported binary operator '/' for objects of type '{self.typeName()}' and '{other.typeName()}'")
|
|
|
|
|
|
|
|
|
|
|
|
proc trueDiv*(self, other: ptr Obj): ptr Obj =
|
2020-10-19 16:19:49 +02:00
|
|
|
## Returns the result of self / other
|
2020-10-27 14:38:28 +01:00
|
|
|
## or raises NotImplementedError if the operation is unsupported
|
2020-10-27 18:59:36 +01:00
|
|
|
case self.kind:
|
|
|
|
of ObjectType.Integer:
|
|
|
|
result = cast[ptr Integer](self).trueDiv(other)
|
|
|
|
of ObjectType.Float:
|
|
|
|
result = cast[ptr Float](self).trueDiv(other)
|
|
|
|
of ObjectType.NotANumber:
|
|
|
|
result = cast[ptr NotANumber](self).trueDiv(other)
|
|
|
|
of ObjectType.Infinity:
|
|
|
|
result = cast[ptr Infinity](self).trueDiv(other)
|
|
|
|
else:
|
|
|
|
raise newException(NotImplementedError, &"unsupported binary operator '/' for objects of type '{self.typeName()}' and '{other.typeName()}'")
|
|
|
|
|
|
|
|
|
|
|
|
proc pow(self: ptr Infinity, other: ptr Obj): ptr Infinity =
|
|
|
|
result = asInf()
|
|
|
|
case other.kind:
|
|
|
|
of ObjectType.Infinity:
|
|
|
|
var other = cast[ptr Infinity](other)
|
|
|
|
if self.isNegative or other.isNegative:
|
|
|
|
result.isNegative = true
|
|
|
|
of ObjectType.Integer, ObjectType.Float:
|
|
|
|
discard
|
|
|
|
else:
|
|
|
|
raise newException(NotImplementedError, &"unsupported binary operator '**' for objects of type '{self.typeName()}' and '{other.typeName()}'")
|
|
|
|
|
|
|
|
|
|
|
|
proc pow(self: ptr NotANumber, other: ptr Obj): ptr NotANumber =
|
|
|
|
result = asNan()
|
|
|
|
case other.kind:
|
|
|
|
of ObjectType.NotANumber, ObjectType.Integer, ObjectType.Float:
|
|
|
|
discard
|
|
|
|
else:
|
|
|
|
raise newException(NotImplementedError, &"unsupported binary operator '**' for objects of type '{self.typeName()}' and '{other.typeName()}'")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
proc pow(self: ptr Integer, other: ptr Obj): ptr Obj = # This can yield a float!
|
|
|
|
case other.kind:
|
|
|
|
of ObjectType.Integer:
|
|
|
|
result = (self.toInt() ** cast[ptr Integer](other).toInt()).asInt()
|
|
|
|
of ObjectType.Float:
|
|
|
|
let res = ((float self.toInt()) ** cast[ptr Float](other).toFloat())
|
|
|
|
if res == system.Inf:
|
|
|
|
result = asInf()
|
|
|
|
elif res == -system.Inf:
|
|
|
|
let negInf = asInf()
|
|
|
|
negInf.isNegative = true
|
|
|
|
result = negInf
|
|
|
|
else:
|
|
|
|
result = res.asFloat()
|
|
|
|
of ObjectType.NotANumber:
|
|
|
|
result = asNan()
|
|
|
|
of ObjectType.Infinity:
|
|
|
|
result = cast[ptr Infinity](other)
|
|
|
|
else:
|
|
|
|
raise newException(NotImplementedError, &"unsupported binary operator '**' for objects of type '{self.typeName()}' and '{other.typeName()}'")
|
2020-10-19 16:19:49 +02:00
|
|
|
|
|
|
|
|
2020-10-27 18:59:36 +01:00
|
|
|
proc pow(self: ptr Float, other: ptr Obj): ptr Obj =
|
|
|
|
case other.kind:
|
|
|
|
of ObjectType.Integer:
|
|
|
|
result = (self.toFloat() ** float cast[ptr Integer](other).toInt()).asFloat()
|
|
|
|
of ObjectType.Float:
|
|
|
|
let res = (self.toFloat() ** cast[ptr Float](other).toFloat())
|
|
|
|
if res == system.Inf:
|
|
|
|
result = asInf()
|
|
|
|
elif res == -system.Inf:
|
|
|
|
let negInf = asInf()
|
|
|
|
negInf.isNegative = true
|
|
|
|
result = negInf
|
|
|
|
else:
|
|
|
|
result = res.asFloat()
|
|
|
|
of ObjectType.NotANumber:
|
|
|
|
result = asNan()
|
|
|
|
of ObjectType.Infinity:
|
|
|
|
result = cast[ptr Infinity](other)
|
|
|
|
else:
|
|
|
|
raise newException(NotImplementedError, &"unsupported binary operator '**' for objects of type '{self.typeName()}' and '{other.typeName()}'")
|
|
|
|
|
|
|
|
|
|
|
|
proc pow*(self, other: ptr Obj): ptr Obj =
|
|
|
|
## Returns the result of self ** other (exponentiation)
|
2020-10-27 14:38:28 +01:00
|
|
|
## or raises NotImplementedError if the operation is unsupported
|
2020-10-27 18:59:36 +01:00
|
|
|
case self.kind:
|
|
|
|
of ObjectType.Integer:
|
|
|
|
result = cast[ptr Integer](self).pow(other)
|
|
|
|
of ObjectType.Float:
|
|
|
|
result = cast[ptr Float](self).pow(other)
|
|
|
|
of ObjectType.NotANumber:
|
|
|
|
result = cast[ptr NotANumber](self).pow(other)
|
|
|
|
of ObjectType.Infinity:
|
|
|
|
result = cast[ptr Infinity](self).pow(other)
|
|
|
|
else:
|
|
|
|
raise newException(NotImplementedError, &"unsupported binary operator '**' for objects of type '{self.typeName()}' and '{other.typeName()}'")
|
|
|
|
|
|
|
|
|
|
|
|
proc divMod(self: ptr Infinity, other: ptr Obj): ptr Infinity =
|
|
|
|
result = asInf()
|
|
|
|
case other.kind:
|
|
|
|
of ObjectType.Infinity:
|
|
|
|
var other = cast[ptr Infinity](other)
|
|
|
|
if self.isNegative or other.isNegative:
|
|
|
|
result.isNegative = true
|
|
|
|
of ObjectType.Integer, ObjectType.Float:
|
|
|
|
discard
|
|
|
|
else:
|
|
|
|
raise newException(NotImplementedError, &"unsupported binary operator '%' for objects of type '{self.typeName()}' and '{other.typeName()}'")
|
|
|
|
|
2020-10-19 16:19:49 +02:00
|
|
|
|
2020-10-27 18:59:36 +01:00
|
|
|
proc divMod(self: ptr NotANumber, other: ptr Obj): ptr NotANumber =
|
|
|
|
result = asNan()
|
|
|
|
case other.kind:
|
|
|
|
of ObjectType.NotANumber, ObjectType.Integer, ObjectType.Float:
|
|
|
|
discard
|
|
|
|
else:
|
|
|
|
raise newException(NotImplementedError, &"unsupported binary operator '%' for objects of type '{self.typeName()}' and '{other.typeName()}'")
|
|
|
|
|
|
|
|
|
|
|
|
proc divMod(self: ptr Integer, other: ptr Obj): ptr Obj = # This can yield a float!
|
|
|
|
case other.kind:
|
|
|
|
of ObjectType.Integer:
|
|
|
|
result = (self.toInt() mod cast[ptr Integer](other).toInt()).asInt()
|
|
|
|
of ObjectType.Float:
|
|
|
|
let res = ((float self.toInt()) mod cast[ptr Float](other).toFloat())
|
|
|
|
if res == system.Inf:
|
|
|
|
result = asInf()
|
|
|
|
elif res == -system.Inf:
|
|
|
|
let negInf = asInf()
|
|
|
|
negInf.isNegative = true
|
|
|
|
result = negInf
|
|
|
|
else:
|
|
|
|
result = res.asFloat()
|
|
|
|
of ObjectType.NotANumber:
|
|
|
|
result = asNan()
|
|
|
|
of ObjectType.Infinity:
|
|
|
|
result = cast[ptr Infinity](other)
|
|
|
|
else:
|
|
|
|
raise newException(NotImplementedError, &"unsupported binary operator '%' for objects of type '{self.typeName()}' and '{other.typeName()}'")
|
|
|
|
|
|
|
|
|
|
|
|
proc divMod(self: ptr Float, other: ptr Obj): ptr Obj =
|
|
|
|
case other.kind:
|
|
|
|
of ObjectType.Integer:
|
|
|
|
result = (self.toFloat() mod float cast[ptr Integer](other).toInt()).asFloat()
|
|
|
|
of ObjectType.Float:
|
|
|
|
let res = (self.toFloat() mod cast[ptr Float](other).toFloat())
|
|
|
|
if res == system.Inf:
|
|
|
|
result = asInf()
|
|
|
|
elif res == -system.Inf:
|
|
|
|
let negInf = asInf()
|
|
|
|
negInf.isNegative = true
|
|
|
|
result = negInf
|
|
|
|
else:
|
|
|
|
result = res.asFloat()
|
|
|
|
of ObjectType.NotANumber:
|
|
|
|
result = asNan()
|
|
|
|
of ObjectType.Infinity:
|
|
|
|
result = cast[ptr Infinity](other)
|
|
|
|
else:
|
|
|
|
raise newException(NotImplementedError, &"unsupported binary operator '%' for objects of type '{self.typeName()}' and '{other.typeName()}'")
|
|
|
|
|
|
|
|
|
|
|
|
proc divMod*(self, other: ptr Obj): ptr Obj =
|
|
|
|
## Returns the result of self % other
|
|
|
|
## or raises NotImplementedError if the operation is unsupported
|
|
|
|
case self.kind:
|
|
|
|
of ObjectType.Integer:
|
|
|
|
result = cast[ptr Integer](self).divMod(other)
|
|
|
|
of ObjectType.Float:
|
|
|
|
result = cast[ptr Float](self).divMod(other)
|
|
|
|
of ObjectType.NotANumber:
|
|
|
|
result = cast[ptr NotANumber](self).divMod(other)
|
|
|
|
of ObjectType.Infinity:
|
|
|
|
result = cast[ptr Infinity](self).divMod(other)
|
|
|
|
else:
|
|
|
|
raise newException(NotImplementedError, &"unsupported binary operator '%' for objects of type '{self.typeName()}' and '{other.typeName()}'")
|
2020-10-19 16:19:49 +02:00
|
|
|
|
2020-10-28 17:19:41 +01:00
|
|
|
|
|
|
|
proc binaryAnd(self, other: ptr Integer): ptr Integer =
|
|
|
|
result = bitand(self.toInt(), other.toInt()).asInt()
|
|
|
|
|
|
|
|
|
|
|
|
proc binaryAnd*(self, other: ptr Obj): ptr Obj =
|
2020-10-19 16:19:49 +02:00
|
|
|
## Returns the result of self & other
|
2020-10-27 14:38:28 +01:00
|
|
|
## or raises NotImplementedError if the operation is unsupported
|
2020-10-28 17:19:41 +01:00
|
|
|
case self.kind:
|
|
|
|
of ObjectType.Integer:
|
|
|
|
result = cast[ptr Integer](self).binaryAnd(cast[ptr Integer](other))
|
|
|
|
else:
|
|
|
|
raise newException(NotImplementedError, &"unsupported binary operator '&' for objects of type '{self.typeName()}' and '{other.typeName()}'")
|
|
|
|
|
2020-10-19 16:19:49 +02:00
|
|
|
|
2020-10-28 17:19:41 +01:00
|
|
|
proc binaryOr(self, other: ptr Integer): ptr Integer =
|
|
|
|
result = bitor(self.toInt(), other.toInt()).asInt()
|
2020-10-19 16:19:49 +02:00
|
|
|
|
2020-10-28 17:19:41 +01:00
|
|
|
|
|
|
|
proc binaryOr*(self, other: ptr Obj): ptr Obj =
|
2020-10-19 16:19:49 +02:00
|
|
|
## Returns the result of self | other
|
2020-10-27 14:38:28 +01:00
|
|
|
## or raises NotImplementedError if the operation is unsupported
|
2020-10-28 17:19:41 +01:00
|
|
|
case self.kind:
|
|
|
|
of ObjectType.Integer:
|
|
|
|
result = cast[ptr Integer](self).binaryOr(cast[ptr Integer](other))
|
|
|
|
else:
|
|
|
|
raise newException(NotImplementedError, &"unsupported binary operator '|' for objects of type '{self.typeName()}' and '{other.typeName()}'")
|
|
|
|
|
|
|
|
|
|
|
|
proc binaryNot(self: ptr Integer): ptr Integer =
|
|
|
|
result = bitnot(self.toInt()).asInt()
|
2020-10-19 16:19:49 +02:00
|
|
|
|
|
|
|
|
2020-10-28 17:19:41 +01:00
|
|
|
proc binaryNot*(self: ptr Obj): ptr Obj =
|
2020-10-19 16:19:49 +02:00
|
|
|
## Returns the result of ~self
|
2020-10-27 14:38:28 +01:00
|
|
|
## or raises NotImplementedError if the operation is unsupported
|
2020-10-28 17:19:41 +01:00
|
|
|
case self.kind:
|
|
|
|
of ObjectType.Integer:
|
|
|
|
result = cast[ptr Integer](self).binaryNot()
|
|
|
|
else:
|
|
|
|
raise newException(NotImplementedError, &"unsupported unary operator '~' for object of type '{self.typeName()}'")
|
|
|
|
|
|
|
|
|
|
|
|
proc binaryXor(self, other: ptr Integer): ptr Integer =
|
|
|
|
result = bitxor(self.toInt(), other.toInt()).asInt()
|
2020-10-19 16:19:49 +02:00
|
|
|
|
|
|
|
|
2020-10-28 17:19:41 +01:00
|
|
|
proc binaryXor*(self, other: ptr Obj): ptr Obj =
|
2020-10-19 16:19:49 +02:00
|
|
|
## Returns the result of self ^ other
|
2020-10-27 14:38:28 +01:00
|
|
|
## or raises NotImplementedError if the operation is unsupported
|
2020-10-28 17:19:41 +01:00
|
|
|
case self.kind:
|
|
|
|
of ObjectType.Integer:
|
|
|
|
result = cast[ptr Integer](self).binaryXor(cast[ptr Integer](other))
|
|
|
|
else:
|
|
|
|
raise newException(NotImplementedError, &"unsupported binary operator '^' for object of type '{self.typeName()}'")
|
|
|
|
|
|
|
|
|
|
|
|
proc binaryShr(self, other: ptr Integer): ptr Integer =
|
|
|
|
result = (self.toInt() shr other.toInt()).asInt()
|
|
|
|
|
|
|
|
|
|
|
|
proc binaryShr*(self, other: ptr Obj): ptr Obj =
|
|
|
|
## Returns the result of self >> other
|
|
|
|
## or raises NotImplementedError if the operation is unsupported
|
|
|
|
case self.kind:
|
|
|
|
of ObjectType.Integer:
|
|
|
|
result = cast[ptr Integer](self).binaryShr(cast[ptr Integer](other))
|
|
|
|
else:
|
|
|
|
raise newException(NotImplementedError, &"unsupported binary operator '>>' for object of type '{self.typeName()}'")
|
|
|
|
|
|
|
|
|
|
|
|
proc binaryShl(self, other: ptr Integer): ptr Integer =
|
|
|
|
result = (self.toInt() shr other.toInt()).asInt()
|
|
|
|
|
|
|
|
|
|
|
|
proc binaryShl*(self, other: ptr Obj): ptr Obj =
|
|
|
|
## Returns the result of self << other
|
|
|
|
## or raises NotImplementedError if the operation is unsupported
|
|
|
|
case self.kind:
|
|
|
|
of ObjectType.Integer:
|
|
|
|
result = cast[ptr Integer](self).binaryShl(cast[ptr Integer](other))
|
|
|
|
else:
|
|
|
|
raise newException(NotImplementedError, &"unsupported binary operator '<<' for object of type '{self.typeName()}'")
|
2020-10-23 00:31:39 +02:00
|
|
|
|
2020-10-25 17:47:53 +01:00
|
|
|
|
2020-10-27 14:38:28 +01:00
|
|
|
proc newString*(str: string): ptr String =
|
|
|
|
# TODO -> Unicode
|
|
|
|
# TODO -> Move this into asStr
|
|
|
|
result = allocateObj(String, ObjectType.String)
|
|
|
|
result.str = allocate(UncheckedArray[char], char, len(str))
|
|
|
|
for i in 0..len(str) - 1:
|
|
|
|
result.str[i] = str[i]
|
|
|
|
result.len = len(str)
|
|
|
|
result.hashValue = result.hash()
|
|
|
|
result.isHashable = true
|
2020-10-25 17:47:53 +01:00
|
|
|
|
|
|
|
|
2020-10-27 14:38:28 +01:00
|
|
|
proc asStr*(s: string): ptr String =
|
|
|
|
## Converts a nim string into a
|
|
|
|
## JAPL string
|
|
|
|
result = newString(s)
|