Compare commits
No commits in common. "4fdd90614a5a3912b365b9dfbbc8a3809d0393dd" and "36970e493be6182c3e3e6eda9c003fcf1f50efd7" have entirely different histories.
4fdd90614a
...
36970e493b
|
@ -12,26 +12,24 @@
|
||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
## The Peon runtime environment
|
## The Peon runtime environment
|
||||||
|
{.push checks:off.} # The VM is a critical point where checks are deleterious
|
||||||
|
|
||||||
import std/monotimes
|
import std/monotimes
|
||||||
import std/math
|
import std/math
|
||||||
import std/segfaults
|
|
||||||
import std/strutils
|
|
||||||
import std/sequtils
|
|
||||||
import std/sets
|
|
||||||
|
|
||||||
|
|
||||||
import ../config
|
import ../config
|
||||||
import ../frontend/meta/bytecode
|
import ../frontend/meta/bytecode
|
||||||
import ../util/multibyte
|
import ../util/multibyte
|
||||||
|
import ../memory/allocator
|
||||||
|
|
||||||
|
|
||||||
when debugVM or debugMem or debugGC:
|
import strutils
|
||||||
|
when debugVM:
|
||||||
import std/strformat
|
import std/strformat
|
||||||
import std/terminal
|
import std/terminal
|
||||||
|
|
||||||
|
|
||||||
{.push checks:off.} # The VM is a critical point where checks are deleterious
|
|
||||||
|
|
||||||
type
|
type
|
||||||
PeonVM* = ref object
|
PeonVM* = ref object
|
||||||
|
@ -56,274 +54,14 @@ type
|
||||||
frames: seq[uint64] # Stores the bottom of stack frames
|
frames: seq[uint64] # Stores the bottom of stack frames
|
||||||
closedOver: seq[uint64] # Stores variables that do not have stack semantics
|
closedOver: seq[uint64] # Stores variables that do not have stack semantics
|
||||||
results: seq[uint64] # Stores function's results (return values)
|
results: seq[uint64] # Stores function's results (return values)
|
||||||
gc: PeonGC
|
|
||||||
ObjectKind* = enum
|
|
||||||
## A tag for heap-allocated
|
|
||||||
## peon objects
|
|
||||||
String, List,
|
|
||||||
Dict, Tuple,
|
|
||||||
CustomType
|
|
||||||
HeapObject* = object
|
|
||||||
## A tagged box for a heap-allocated
|
|
||||||
## peon object
|
|
||||||
marked*: bool
|
|
||||||
case kind*: ObjectKind
|
|
||||||
of String:
|
|
||||||
str*: ptr UncheckedArray[char]
|
|
||||||
len*: int
|
|
||||||
else:
|
|
||||||
discard # TODO
|
|
||||||
PeonGC* = ref object
|
|
||||||
## A simple Mark&Sweep collector
|
|
||||||
## to manage peon's heap space
|
|
||||||
vm: PeonVM
|
|
||||||
bytesAllocated: tuple[total, current: int]
|
|
||||||
nextGC: int
|
|
||||||
pointers: HashSet[uint64]
|
|
||||||
objects: seq[ptr HeapObject]
|
|
||||||
|
|
||||||
|
|
||||||
# Implementation of peon's memory manager
|
|
||||||
|
|
||||||
proc newPeonGC*: PeonGC =
|
|
||||||
## Initializes a new, blank
|
|
||||||
## garbage collector
|
|
||||||
new(result)
|
|
||||||
result.bytesAllocated = (0, 0)
|
|
||||||
result.objects = @[]
|
|
||||||
result.nextGC = FirstGC
|
|
||||||
|
|
||||||
|
|
||||||
proc collect*(self: PeonGC)
|
|
||||||
|
|
||||||
|
|
||||||
proc reallocate*(self: PeonGC, p: pointer, oldSize: int, newSize: int): pointer =
|
|
||||||
## Simple wrapper around realloc/dealloc with
|
|
||||||
## built-in garbage collection
|
|
||||||
self.bytesAllocated.current += newSize - oldSize
|
|
||||||
try:
|
|
||||||
if newSize == 0 and not p.isNil():
|
|
||||||
when debugMem:
|
|
||||||
if oldSize > 1:
|
|
||||||
echo &"DEBUG - Memory manager: Deallocating {oldSize} bytes of memory"
|
|
||||||
else:
|
|
||||||
echo "DEBUG - Memory manager: Deallocating 1 byte of memory"
|
|
||||||
dealloc(p)
|
|
||||||
elif (oldSize > 0 and not p.isNil() and newSize > oldSize) or oldSize == 0:
|
|
||||||
self.bytesAllocated.total += newSize - oldSize
|
|
||||||
when debugStressGC:
|
|
||||||
self.collect()
|
|
||||||
else:
|
|
||||||
if self.bytesAllocated.current > self.nextGC:
|
|
||||||
self.collect()
|
|
||||||
when debugMem:
|
|
||||||
if oldSize == 0:
|
|
||||||
if newSize > 1:
|
|
||||||
echo &"DEBUG - Memory manager: Allocating {newSize} bytes of memory"
|
|
||||||
else:
|
|
||||||
echo "DEBUG - Memory manager: Allocating 1 byte of memory"
|
|
||||||
else:
|
|
||||||
echo &"DEBUG - Memory manager: Resizing {oldSize} bytes of memory to {newSize} bytes"
|
|
||||||
result = realloc(p, newSize)
|
|
||||||
when debugMem:
|
|
||||||
if p.isNil() and newSize == 0:
|
|
||||||
echo &"DEBUG - Memory manager: Warning, asked to dealloc() nil pointer from {oldSize} to {newSize} bytes, ignoring request"
|
|
||||||
elif oldSize > 0 and p.isNil():
|
|
||||||
echo &"DEBUG - Memory manager: Warning, asked to realloc() nil pointer from {oldSize} to {newSize} bytes, ignoring request"
|
|
||||||
except NilAccessDefect:
|
|
||||||
stderr.write("Peon: could not manage memory, segmentation fault\n")
|
|
||||||
quit(139) # For now, there's not much we can do if we can't get the memory we need, so we exit
|
|
||||||
|
|
||||||
|
|
||||||
template resizeArray*(self: PeonGC, kind: untyped, p: pointer, oldCount, newCount: int): untyped =
|
|
||||||
## Handy template to resize a dynamic array
|
|
||||||
cast[ptr UncheckedArray[kind]](reallocate(self, p, sizeof(kind) * oldCount, sizeof(kind) * newCount))
|
|
||||||
|
|
||||||
|
|
||||||
template freeArray*(self: PeonGC, kind: untyped, p: pointer, size: int): untyped =
|
|
||||||
## Frees a dynamic array
|
|
||||||
discard reallocate(self, p, sizeof(kind) * size, 0)
|
|
||||||
|
|
||||||
|
|
||||||
template free*(self: PeonGC, kind: typedesc, p: pointer): untyped =
|
|
||||||
## Frees a pointer by reallocating its
|
|
||||||
## size to 0
|
|
||||||
discard reallocate(self, p, sizeof(kind), 0)
|
|
||||||
|
|
||||||
|
|
||||||
proc allocate*(self: PeonGC, kind: ObjectKind, size: typedesc, count: int): ptr HeapObject {.inline.} =
|
|
||||||
## Allocates aobject on the heap
|
|
||||||
result = cast[ptr HeapObject](self.reallocate(nil, 0, sizeof(HeapObject) * 1))
|
|
||||||
result.marked = false
|
|
||||||
self.bytesAllocated.total += sizeof(result)
|
|
||||||
self.bytesAllocated.current += sizeof(result)
|
|
||||||
case kind:
|
|
||||||
of String:
|
|
||||||
result.str = cast[ptr UncheckedArray[char]](self.reallocate(nil, 0, sizeof(size) * count))
|
|
||||||
result.len = count
|
|
||||||
self.bytesAllocated.current += sizeof(size) * count
|
|
||||||
else:
|
|
||||||
discard # TODO
|
|
||||||
self.objects.add(result)
|
|
||||||
self.pointers.incl(cast[uint64](result))
|
|
||||||
|
|
||||||
|
|
||||||
proc mark(self: ptr HeapObject): bool =
|
|
||||||
## Marks a single object
|
|
||||||
if self.marked:
|
|
||||||
return false
|
|
||||||
self.marked = true
|
|
||||||
return true
|
|
||||||
|
|
||||||
|
|
||||||
proc markRoots(self: PeonGC): seq[ptr HeapObject] =
|
|
||||||
## Marks root objects *not* to be
|
|
||||||
## collected by the GC and returns
|
|
||||||
## their addresses
|
|
||||||
|
|
||||||
# Unlike what bob does in his book,
|
|
||||||
# we keep track of objects in a different
|
|
||||||
# way due to how the whole thing is designed.
|
|
||||||
# Specifically, we don't have neat structs for
|
|
||||||
# all peon objects: When we allocate() an object,
|
|
||||||
# we keep track of the small wrapper it created
|
|
||||||
# along with its type and other metadata. Then,
|
|
||||||
# we can go through the various sources of roots
|
|
||||||
# in the VM, see if they match any pointers we
|
|
||||||
# already know about (we store them in a hash set so
|
|
||||||
# it's really fast), and then we can be sure that
|
|
||||||
# anything that's in the difference (i.e. mathematical
|
|
||||||
# set difference) between our full list of pointers
|
|
||||||
# and the live ones is not a root object, so if it's
|
|
||||||
# not indirectly reachable through a root itself, it
|
|
||||||
# can be freed. I'm not sure if I can call this GC
|
|
||||||
# strategy precise, since technically there is a chance
|
|
||||||
# for a regular value to collide with one of the pointers
|
|
||||||
# we allocated and that would cause a memory leak, but
|
|
||||||
# with a 64-bit address-space it probably hardly matters,
|
|
||||||
# so I guess this is a mostly-precise Mark&Sweep collector
|
|
||||||
when debugGC:
|
|
||||||
echo "DEBUG - GC: Starting mark phase"
|
|
||||||
var live = initHashSet[uint64]()
|
|
||||||
for obj in self.vm.calls:
|
|
||||||
if obj in self.pointers:
|
|
||||||
live.incl(obj)
|
|
||||||
for obj in self.vm.operands:
|
|
||||||
if obj in self.pointers:
|
|
||||||
live.incl(obj)
|
|
||||||
for obj in self.vm.closedOver:
|
|
||||||
if obj in self.pointers:
|
|
||||||
live.incl(obj)
|
|
||||||
# We preallocate the space on the seq
|
|
||||||
result = newSeqOfCap[ptr HeapObject](len(live))
|
|
||||||
var obj: ptr HeapObject
|
|
||||||
for p in live:
|
|
||||||
obj = cast[ptr HeapObject](p)
|
|
||||||
if obj.mark():
|
|
||||||
when debugGC:
|
|
||||||
echo &"DEBUG - GC: Marking object: {obj[]}"
|
|
||||||
result.add(obj)
|
|
||||||
when debugGC:
|
|
||||||
echo "DEBUG - GC: Mark phase complete"
|
|
||||||
|
|
||||||
|
|
||||||
proc trace(self: PeonGC, roots: seq[ptr HeapObject]) =
|
|
||||||
## Traces references to other
|
|
||||||
## objects starting from the
|
|
||||||
## roots. The second argument
|
|
||||||
## is the output of the mark
|
|
||||||
## phase. To speak in terms
|
|
||||||
## of the tricolor abstraction,
|
|
||||||
## this is where we blacken gray
|
|
||||||
## objects
|
|
||||||
when debugGC:
|
|
||||||
echo &"DEBUG - GC: Tracing indirect references from {len(roots)} roots"
|
|
||||||
for root in roots:
|
|
||||||
case root.kind:
|
|
||||||
of String:
|
|
||||||
discard # Strings hold no additional references
|
|
||||||
else:
|
|
||||||
discard # TODO: Other types
|
|
||||||
when debugGC:
|
|
||||||
echo &"DEBUG - GC: Tracing phase complete"
|
|
||||||
|
|
||||||
|
|
||||||
proc free(self: PeonGC, obj: ptr HeapObject) =
|
|
||||||
## Frees a single heap-allocated
|
|
||||||
## peon object and all the memory
|
|
||||||
## it directly or indirectly owns
|
|
||||||
when debugAlloc:
|
|
||||||
echo &"DEBUG - GC: Freeing object: {obj[]}"
|
|
||||||
case obj.kind:
|
|
||||||
of String:
|
|
||||||
# Strings only own their
|
|
||||||
# underlying character array
|
|
||||||
if obj.len > 0 and not obj.str.isNil():
|
|
||||||
self.freeArray(char, obj.str, obj.len)
|
|
||||||
else:
|
|
||||||
discard # TODO
|
|
||||||
self.free(HeapObject, obj)
|
|
||||||
self.pointers.excl(cast[uint64](obj))
|
|
||||||
|
|
||||||
|
|
||||||
proc sweep(self: PeonGC) =
|
|
||||||
## Sweeps unmarked objects
|
|
||||||
## that have been left behind
|
|
||||||
## during the mark phase.
|
|
||||||
## This is more convoluted
|
|
||||||
## than it needs to be because
|
|
||||||
## nim disallows changing the
|
|
||||||
## size of a sequence during
|
|
||||||
## iteration
|
|
||||||
|
|
||||||
when debugGC:
|
|
||||||
echo "DEBUG - GC: Beginning sweeping phase"
|
|
||||||
var j = -1
|
|
||||||
var idx = 0
|
|
||||||
var count = 0
|
|
||||||
while j < self.objects.high():
|
|
||||||
inc(j)
|
|
||||||
if self.objects[j].marked:
|
|
||||||
# Object is marked: don't touch it,
|
|
||||||
# but reset its mark so that it doesn't
|
|
||||||
# stay alive forever
|
|
||||||
self.objects[j].marked = false
|
|
||||||
when debugGC:
|
|
||||||
echo &"DEBUG - GC: Unmarking object: {self.objects[j][]}"
|
|
||||||
inc(idx)
|
|
||||||
else:
|
|
||||||
# Object is unmarked: its memory is
|
|
||||||
# fair game
|
|
||||||
self.free(self.objects[idx])
|
|
||||||
self.objects.delete(idx)
|
|
||||||
inc(idx)
|
|
||||||
inc(count)
|
|
||||||
when debugGC:
|
|
||||||
echo &"DEBUG - GC: Swept {count} objects"
|
|
||||||
|
|
||||||
|
|
||||||
proc collect(self: PeonGC) =
|
|
||||||
## Attempts to reclaim some
|
|
||||||
## memory from unreachable
|
|
||||||
## objects onto the heap
|
|
||||||
let before {.used.} = self.bytesAllocated.current
|
|
||||||
let time {.used.} = getMonoTime().ticks().float() / 1_000_000
|
|
||||||
when debugGC:
|
|
||||||
echo &"DEBUG - GC: Starting collection cycle at heap size {self.bytesAllocated.current}"
|
|
||||||
self.trace(self.markRoots())
|
|
||||||
self.sweep()
|
|
||||||
self.nextGC = self.bytesAllocated.current * HeapGrowFactor
|
|
||||||
when debugGC:
|
|
||||||
echo &"DEBUG - GC: Collection cycle has terminated in {getMonoTime().ticks().float() / 1_000_000 - time:.2f} ms, collected {before - self.bytesAllocated.current} bytes of memory in total"
|
|
||||||
echo &"DEBUG - GC: Next cycle at {self.nextGC} bytes"
|
|
||||||
|
|
||||||
|
|
||||||
proc initCache*(self: PeonVM) =
|
proc initCache*(self: PeonVM) =
|
||||||
## Initializes the VM's
|
## Initializes the VM's
|
||||||
## singletons cache
|
## singletons cache
|
||||||
self.cache[0] = 0x0 # False
|
self.cache[0] = 0x0 # Nil
|
||||||
self.cache[1] = 0x1 # True
|
self.cache[1] = 0x1 # True
|
||||||
self.cache[2] = 0x2 # Nil
|
self.cache[2] = 0x2 # False
|
||||||
self.cache[3] = 0x3 # Positive inf
|
self.cache[3] = 0x3 # Positive inf
|
||||||
self.cache[4] = 0x4 # Negative inf
|
self.cache[4] = 0x4 # Negative inf
|
||||||
self.cache[5] = 0x5 # NaN
|
self.cache[5] = 0x5 # NaN
|
||||||
|
@ -334,14 +72,10 @@ proc newPeonVM*: PeonVM =
|
||||||
## for executing Peon bytecode
|
## for executing Peon bytecode
|
||||||
new(result)
|
new(result)
|
||||||
result.ip = 0
|
result.ip = 0
|
||||||
result.initCache()
|
|
||||||
result.gc = newPeonGC()
|
|
||||||
result.frames = @[]
|
result.frames = @[]
|
||||||
result.calls = @[]
|
result.calls = newSeq[uint64]()
|
||||||
result.operands = @[]
|
result.operands = newSeq[uint64]()
|
||||||
result.results = @[]
|
result.initCache()
|
||||||
result.closedOver = @[]
|
|
||||||
result.gc.vm = result
|
|
||||||
|
|
||||||
|
|
||||||
# Getters for singleton types
|
# Getters for singleton types
|
||||||
|
@ -406,10 +140,11 @@ proc peek(self: PeonVM, distance: int = 0): uint64 =
|
||||||
## given distance from the top of
|
## given distance from the top of
|
||||||
## the operand stack without consuming it
|
## the operand stack without consuming it
|
||||||
if distance < 0:
|
if distance < 0:
|
||||||
return self.peekb(^(-int(distance)))
|
return self.peekb(^(-distance))
|
||||||
return self.operands[self.operands.high() + distance]
|
return self.operands[self.operands.high() + distance]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
proc pushc(self: PeonVM, val: uint64) =
|
proc pushc(self: PeonVM, val: uint64) =
|
||||||
## Pushes a value to the
|
## Pushes a value to the
|
||||||
## call stack
|
## call stack
|
||||||
|
@ -429,7 +164,7 @@ proc peekc(self: PeonVM, distance: int = 0): uint64 {.used.} =
|
||||||
return self.calls[self.calls.high() + distance]
|
return self.calls[self.calls.high() + distance]
|
||||||
|
|
||||||
|
|
||||||
proc getc(self: PeonVM, idx: uint64): uint64 =
|
proc getc(self: PeonVM, idx: uint): uint64 =
|
||||||
## Accessor method that abstracts
|
## Accessor method that abstracts
|
||||||
## indexing our call stack through stack
|
## indexing our call stack through stack
|
||||||
## frames
|
## frames
|
||||||
|
@ -574,17 +309,15 @@ proc constReadFloat64(self: PeonVM, idx: int): float =
|
||||||
copyMem(result.addr, arr.addr, sizeof(arr))
|
copyMem(result.addr, arr.addr, sizeof(arr))
|
||||||
|
|
||||||
|
|
||||||
proc constReadString(self: PeonVM, size, idx: int): ptr HeapObject =
|
proc constReadString(self: PeonVM, size, idx: int): ptr UncheckedArray[char] =
|
||||||
## Reads a constant from the
|
## Reads a constant from the
|
||||||
## chunk's constant table and
|
## chunk's constant table and
|
||||||
## returns it as a pointer to
|
## returns it as a pointer to
|
||||||
## a heap-allocated string
|
## a heap-allocated string
|
||||||
let str = self.chunk.consts[idx..<idx + size].fromBytes()
|
let str = self.chunk.consts[idx..<idx + size].fromBytes()
|
||||||
result = self.gc.allocate(String, char, len(str))
|
result = allocate(UncheckedArray[char], char, len(str))
|
||||||
for i, c in str:
|
for i, c in str:
|
||||||
result.str[i] = c
|
result[i] = c
|
||||||
when debugAlloc:
|
|
||||||
echo &"DEBUG - GC: Allocated new object: {result[]}"
|
|
||||||
|
|
||||||
{.pop.}
|
{.pop.}
|
||||||
|
|
||||||
|
@ -611,7 +344,7 @@ when debugVM: # So nim shuts up
|
||||||
styledEcho fgMagenta, "]"
|
styledEcho fgMagenta, "]"
|
||||||
if self.frames.len() !> 0:
|
if self.frames.len() !> 0:
|
||||||
stdout.styledWrite(fgCyan, "Current Frame: ", fgMagenta, "[")
|
stdout.styledWrite(fgCyan, "Current Frame: ", fgMagenta, "[")
|
||||||
for i, e in self.calls[self.frames[^1]..self.calls.high()]:
|
for i, e in self.calls[self.frames[^1]..^1]:
|
||||||
stdout.styledWrite(fgYellow, $e)
|
stdout.styledWrite(fgYellow, $e)
|
||||||
if i < self.calls.high():
|
if i < self.calls.high():
|
||||||
stdout.styledWrite(fgYellow, ", ")
|
stdout.styledWrite(fgYellow, ", ")
|
||||||
|
@ -757,7 +490,7 @@ proc dispatch*(self: PeonVM) =
|
||||||
# into the given call stack index
|
# into the given call stack index
|
||||||
let idx = self.readLong()
|
let idx = self.readLong()
|
||||||
when debugVM:
|
when debugVM:
|
||||||
assert idx - self.calls.high() <= 1, "StoreVar index is bigger than the length of the call stack"
|
assert idx.int - self.calls.high() <= 1, "StoreVar index is bigger than the length of the call stack"
|
||||||
if idx + self.frames[^1] <= self.calls.high().uint:
|
if idx + self.frames[^1] <= self.calls.high().uint:
|
||||||
self.setc(idx, self.pop())
|
self.setc(idx, self.pop())
|
||||||
else:
|
else:
|
||||||
|
@ -821,17 +554,16 @@ proc dispatch*(self: PeonVM) =
|
||||||
self.ip += self.readLong()
|
self.ip += self.readLong()
|
||||||
of JumpIfTrue:
|
of JumpIfTrue:
|
||||||
# Conditional positive jump
|
# Conditional positive jump
|
||||||
let ip = self.readLong()
|
|
||||||
if self.peek().bool:
|
if self.peek().bool:
|
||||||
self.ip += ip
|
self.ip += self.readLong()
|
||||||
of JumpIfFalsePop:
|
of JumpIfFalsePop:
|
||||||
let ip = self.readLong()
|
|
||||||
if not self.pop().bool:
|
|
||||||
self.ip += ip
|
|
||||||
of JumpIfFalseOrPop:
|
|
||||||
let ip = self.readLong()
|
let ip = self.readLong()
|
||||||
if not self.peek().bool:
|
if not self.peek().bool:
|
||||||
self.ip += ip
|
self.ip += ip
|
||||||
|
discard self.pop()
|
||||||
|
of JumpIfFalseOrPop:
|
||||||
|
if not self.peek().bool:
|
||||||
|
self.ip += self.readLong()
|
||||||
else:
|
else:
|
||||||
discard self.pop()
|
discard self.pop()
|
||||||
# Built-in operations on primitive types.
|
# Built-in operations on primitive types.
|
||||||
|
@ -949,10 +681,7 @@ proc dispatch*(self: PeonVM) =
|
||||||
of PrintNan:
|
of PrintNan:
|
||||||
echo "nan"
|
echo "nan"
|
||||||
of PrintString:
|
of PrintString:
|
||||||
let s = cast[ptr HeapObject](self.pop())
|
echo $cast[ptr UncheckedArray[char]](self.pop()) # TODO
|
||||||
for i in 0..<s.len:
|
|
||||||
stdout.write(s.str[i])
|
|
||||||
stdout.write("\n")
|
|
||||||
of SysClock64:
|
of SysClock64:
|
||||||
# Pushes the value of a monotonic clock
|
# Pushes the value of a monotonic clock
|
||||||
# onto the operand stack. This can be used
|
# onto the operand stack. This can be used
|
||||||
|
@ -970,32 +699,7 @@ proc run*(self: PeonVM, chunk: Chunk) =
|
||||||
self.frames = @[]
|
self.frames = @[]
|
||||||
self.calls = @[]
|
self.calls = @[]
|
||||||
self.operands = @[]
|
self.operands = @[]
|
||||||
self.results = @[]
|
|
||||||
self.ip = 0
|
self.ip = 0
|
||||||
#[
|
self.dispatch()
|
||||||
# Sorry, but there only is enough space
|
|
||||||
# for one GC in this VM :(
|
|
||||||
when defined(gcOrc):
|
|
||||||
GC_disableOrc()
|
|
||||||
when not defined(gcArc):
|
|
||||||
GC_disable()
|
|
||||||
GC_disableMarkAndSweep()
|
|
||||||
]#
|
|
||||||
try:
|
|
||||||
self.dispatch()
|
|
||||||
except NilAccessDefect:
|
|
||||||
stderr.writeLine("Memory Access Violation: SIGSEGV")
|
|
||||||
quit(1)
|
|
||||||
# We clean up after ourselves!
|
|
||||||
self.gc.collect()
|
|
||||||
#[
|
|
||||||
# This is unnecessary if we use ARC,
|
|
||||||
# but *just in case*
|
|
||||||
when defined(gcOrc):
|
|
||||||
GC_enable_Orc()
|
|
||||||
when not defined(gcArc):
|
|
||||||
GC_enable()
|
|
||||||
GC_enableMarkAndSweep()
|
|
||||||
]#
|
|
||||||
|
|
||||||
{.pop.}
|
{.pop.}
|
||||||
|
|
|
@ -14,19 +14,16 @@
|
||||||
|
|
||||||
import strformat
|
import strformat
|
||||||
|
|
||||||
# These variables can be tweaked to debug and test various components of the toolchain
|
# Debug various components of peon
|
||||||
const debugLexer* {.booldefine.} = false # Print the tokenizer's output
|
const debugLexer* {.booldefine.} = false
|
||||||
const debugParser* {.booldefine.} = false # Print the AST generated by the parser
|
const debugParser* {.booldefine.} = false
|
||||||
const debugCompiler* {.booldefine.} = false # Disassemble and print the bytecode generated by the compiler
|
const debugCompiler* {.booldefine.} = false
|
||||||
const debugVM* {.booldefine.} = false # Run the VM in debug mode and show stack and instruction info
|
const debugVM* {.booldefine.} = false
|
||||||
const debugGC* {.booldefine.} = false # Debug the Garbage Collector (extremely verbose)
|
const debugGC* {.booldefine.} = false
|
||||||
const debugAlloc* {.booldefine.} = false # Trace object allocation (extremely verbose)
|
const debugMem* {.booldefine.} = false
|
||||||
const debugMem* {.booldefine.} = false # Debug the memory allocator (extremely verbose)
|
const debugSerializer* {.booldefine.} = false
|
||||||
const debugSerializer* {.booldefine.} = false # Validate the bytecode serializer's output
|
const PeonBytecodeMarker* = "PEON_BYTECODE"
|
||||||
const debugStressGC* {.booldefine.} = false # Make the GC run a collection at every allocation (VERY SLOW!)
|
const HeapGrowFactor* = 2 # How much extra memory to allocate for dynamic arrays and garbage collection when resizing
|
||||||
const PeonBytecodeMarker* = "PEON_BYTECODE" # Magic value at the beginning of bytecode files
|
|
||||||
const HeapGrowFactor* = 2 # The growth factor used by the GC to schedule the next collection
|
|
||||||
const FirstGC* = 1024 * 1024; # How many bytes to allocate before running the first GC
|
|
||||||
when HeapGrowFactor <= 1:
|
when HeapGrowFactor <= 1:
|
||||||
{.fatal: "Heap growth factor must be > 1".}
|
{.fatal: "Heap growth factor must be > 1".}
|
||||||
const PeonVersion* = (major: 0, minor: 1, patch: 0)
|
const PeonVersion* = (major: 0, minor: 1, patch: 0)
|
||||||
|
|
|
@ -296,26 +296,17 @@ proc emitBytes(self: Compiler, bytarr: openarray[OpCode | uint8]) {.inline.} =
|
||||||
proc makeConstant(self: Compiler, val: Expression, typ: Type): array[3, uint8] =
|
proc makeConstant(self: Compiler, val: Expression, typ: Type): array[3, uint8] =
|
||||||
## Adds a constant to the current chunk's constant table
|
## Adds a constant to the current chunk's constant table
|
||||||
## and returns its index as a 3-byte array of uint8s
|
## and returns its index as a 3-byte array of uint8s
|
||||||
var lit: string
|
var v: int
|
||||||
if typ.kind in [UInt8, Int8, Int16, UInt16, Int32, UInt32, Int64, UInt64]:
|
discard parseInt(val.token.lexeme, v)
|
||||||
lit = val.token.lexeme
|
|
||||||
if "'" in lit:
|
|
||||||
var idx = lit.high()
|
|
||||||
while lit[idx] != '\'':
|
|
||||||
lit = lit[0..^2]
|
|
||||||
dec(idx)
|
|
||||||
lit = lit[0..^2]
|
|
||||||
case typ.kind:
|
case typ.kind:
|
||||||
of UInt8, Int8:
|
of UInt8, Int8:
|
||||||
result = self.chunk.writeConstant([uint8(parseInt(lit))])
|
result = self.chunk.writeConstant([uint8(v)])
|
||||||
of Int16, UInt16:
|
of Int16, UInt16:
|
||||||
result = self.chunk.writeConstant(parseInt(lit).toDouble())
|
result = self.chunk.writeConstant(v.toDouble())
|
||||||
of Int32, UInt32:
|
of Int32, UInt32:
|
||||||
result = self.chunk.writeConstant(parseInt(lit).toQuad())
|
result = self.chunk.writeConstant(v.toQuad())
|
||||||
of Int64:
|
of Int64, UInt64:
|
||||||
result = self.chunk.writeConstant(parseInt(lit).toLong())
|
result = self.chunk.writeConstant(v.toLong())
|
||||||
of UInt64:
|
|
||||||
result = self.chunk.writeConstant(parseBiggestUInt(lit).toLong())
|
|
||||||
of String:
|
of String:
|
||||||
result = self.chunk.writeConstant(val.token.lexeme[1..^1].toBytes())
|
result = self.chunk.writeConstant(val.token.lexeme[1..^1].toBytes())
|
||||||
of Float32:
|
of Float32:
|
||||||
|
@ -381,16 +372,10 @@ proc patchJump(self: Compiler, offset: int) =
|
||||||
var jump: int = self.chunk.code.len() - offset
|
var jump: int = self.chunk.code.len() - offset
|
||||||
if jump > 16777215:
|
if jump > 16777215:
|
||||||
self.error("cannot jump more than 16777215 instructions")
|
self.error("cannot jump more than 16777215 instructions")
|
||||||
case OpCode(self.chunk.code[offset]):
|
# We subtract 4 because that's the size of our jump instruction
|
||||||
of JumpBackwards, Jump, JumpIfFalsePop, JumpIfFalse:
|
# which the caller of patchJump doesn't take into account (and
|
||||||
# We subtract 4 because backwards
|
# that's by design)
|
||||||
# and absolute jumps don't take
|
let offsetArray = (jump - 4).toTriple()
|
||||||
# the size of the jump offset
|
|
||||||
# into account
|
|
||||||
jump -= 4
|
|
||||||
else:
|
|
||||||
discard
|
|
||||||
let offsetArray = jump.toTriple()
|
|
||||||
self.chunk.code[offset + 1] = offsetArray[0]
|
self.chunk.code[offset + 1] = offsetArray[0]
|
||||||
self.chunk.code[offset + 2] = offsetArray[1]
|
self.chunk.code[offset + 2] = offsetArray[1]
|
||||||
self.chunk.code[offset + 3] = offsetArray[2]
|
self.chunk.code[offset + 3] = offsetArray[2]
|
||||||
|
@ -867,21 +852,14 @@ proc literal(self: Compiler, node: ASTNode) =
|
||||||
of strExpr:
|
of strExpr:
|
||||||
self.emitConstant(LiteralExpr(node), Type(kind: String))
|
self.emitConstant(LiteralExpr(node), Type(kind: String))
|
||||||
of intExpr:
|
of intExpr:
|
||||||
let y = IntExpr(node)
|
var x: int
|
||||||
let kind = self.inferType(y)
|
var y = IntExpr(node)
|
||||||
if kind.kind in [Int64, Int32, Int16, Int8]:
|
try:
|
||||||
var x: int
|
discard parseInt(y.literal.lexeme, x)
|
||||||
try:
|
except ValueError:
|
||||||
discard parseInt(y.literal.lexeme, x)
|
self.error("integer value out of range")
|
||||||
except ValueError:
|
|
||||||
self.error("integer value out of range")
|
self.emitConstant(y, self.inferType(y))
|
||||||
else:
|
|
||||||
var x: uint64
|
|
||||||
try:
|
|
||||||
discard parseBiggestUInt(y.literal.lexeme, x)
|
|
||||||
except ValueError:
|
|
||||||
self.error("integer value out of range")
|
|
||||||
self.emitConstant(y, kind)
|
|
||||||
of hexExpr:
|
of hexExpr:
|
||||||
var x: int
|
var x: int
|
||||||
var y = HexExpr(node)
|
var y = HexExpr(node)
|
||||||
|
@ -925,7 +903,7 @@ proc literal(self: Compiler, node: ASTNode) =
|
||||||
var x: float
|
var x: float
|
||||||
var y = FloatExpr(node)
|
var y = FloatExpr(node)
|
||||||
try:
|
try:
|
||||||
discard parseFloat(y.literal.lexeme)
|
discard parseFloat(y.literal.lexeme, x)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
self.error("floating point value out of range")
|
self.error("floating point value out of range")
|
||||||
self.emitConstant(y, self.inferType(y))
|
self.emitConstant(y, self.inferType(y))
|
||||||
|
@ -941,7 +919,7 @@ proc literal(self: Compiler, node: ASTNode) =
|
||||||
proc handleBuiltinFunction(self: Compiler, fn: Name, args: seq[Expression]) =
|
proc handleBuiltinFunction(self: Compiler, fn: Name, args: seq[Expression]) =
|
||||||
## Emits instructions for builtin functions
|
## Emits instructions for builtin functions
|
||||||
## such as addition or subtraction
|
## such as addition or subtraction
|
||||||
if fn.valueType.builtinOp notin ["LogicalOr", "LogicalAnd"]:
|
if fn.valueType.builtinOp notin ["GenericLogicalOr", "GenericLogicalAnd"]:
|
||||||
if len(args) == 2:
|
if len(args) == 2:
|
||||||
self.expression(args[1])
|
self.expression(args[1])
|
||||||
self.expression(args[0])
|
self.expression(args[0])
|
||||||
|
@ -1336,8 +1314,8 @@ proc whileStmt(self: Compiler, node: WhileStmt) =
|
||||||
self.expression(node.condition)
|
self.expression(node.condition)
|
||||||
let jump = self.emitJump(JumpIfFalsePop)
|
let jump = self.emitJump(JumpIfFalsePop)
|
||||||
self.statement(node.body)
|
self.statement(node.body)
|
||||||
self.emitLoop(start)
|
|
||||||
self.patchJump(jump)
|
self.patchJump(jump)
|
||||||
|
self.emitLoop(start)
|
||||||
|
|
||||||
|
|
||||||
proc checkCallIsPure(self: Compiler, node: ASTnode): bool =
|
proc checkCallIsPure(self: Compiler, node: ASTnode): bool =
|
||||||
|
|
|
@ -451,7 +451,7 @@ proc call(self: Parser): Expression =
|
||||||
|
|
||||||
proc unary(self: Parser): Expression =
|
proc unary(self: Parser): Expression =
|
||||||
## Parses unary expressions
|
## Parses unary expressions
|
||||||
if self.peek().kind in [Identifier, Symbol] and self.peek().lexeme in self.operators.tokens:
|
if self.peek().kind == Symbol and self.peek().lexeme in self.operators.tokens:
|
||||||
result = newUnaryExpr(self.step(), self.unary())
|
result = newUnaryExpr(self.step(), self.unary())
|
||||||
else:
|
else:
|
||||||
result = self.call()
|
result = self.call()
|
||||||
|
@ -462,7 +462,7 @@ proc parsePow(self: Parser): Expression =
|
||||||
result = self.unary()
|
result = self.unary()
|
||||||
var operator: Token
|
var operator: Token
|
||||||
var right: Expression
|
var right: Expression
|
||||||
while self.peek().kind in [Identifier, Symbol] and self.operators.getPrecedence(self.peek().lexeme) == Power:
|
while self.peek().kind == Symbol and self.operators.getPrecedence(self.peek().lexeme) == Power:
|
||||||
operator = self.step()
|
operator = self.step()
|
||||||
right = self.unary()
|
right = self.unary()
|
||||||
result = newBinaryExpr(result, operator, right)
|
result = newBinaryExpr(result, operator, right)
|
||||||
|
@ -474,7 +474,7 @@ proc parseMul(self: Parser): Expression =
|
||||||
result = self.parsePow()
|
result = self.parsePow()
|
||||||
var operator: Token
|
var operator: Token
|
||||||
var right: Expression
|
var right: Expression
|
||||||
while self.peek().kind in [Identifier, Symbol] and self.operators.getPrecedence(self.peek().lexeme) == Multiplication:
|
while self.peek().kind == Symbol and self.operators.getPrecedence(self.peek().lexeme) == Multiplication:
|
||||||
operator = self.step()
|
operator = self.step()
|
||||||
right = self.parsePow()
|
right = self.parsePow()
|
||||||
result = newBinaryExpr(result, operator, right)
|
result = newBinaryExpr(result, operator, right)
|
||||||
|
@ -486,7 +486,7 @@ proc parseAdd(self: Parser): Expression =
|
||||||
result = self.parseMul()
|
result = self.parseMul()
|
||||||
var operator: Token
|
var operator: Token
|
||||||
var right: Expression
|
var right: Expression
|
||||||
while self.peek().kind in [Identifier, Symbol] and self.operators.getPrecedence(self.peek().lexeme) == Addition:
|
while self.peek().kind == Symbol and self.operators.getPrecedence(self.peek().lexeme) == Addition:
|
||||||
operator = self.step()
|
operator = self.step()
|
||||||
right = self.parseMul()
|
right = self.parseMul()
|
||||||
result = newBinaryExpr(result, operator, right)
|
result = newBinaryExpr(result, operator, right)
|
||||||
|
@ -497,7 +497,7 @@ proc parseCmp(self: Parser): Expression =
|
||||||
result = self.parseAdd()
|
result = self.parseAdd()
|
||||||
var operator: Token
|
var operator: Token
|
||||||
var right: Expression
|
var right: Expression
|
||||||
while self.peek().kind in [Identifier, Symbol] and self.operators.getPrecedence(self.peek().lexeme) == Compare:
|
while self.peek().kind == Symbol and self.operators.getPrecedence(self.peek().lexeme) == Compare:
|
||||||
operator = self.step()
|
operator = self.step()
|
||||||
right = self.parseAdd()
|
right = self.parseAdd()
|
||||||
result = newBinaryExpr(result, operator, right)
|
result = newBinaryExpr(result, operator, right)
|
||||||
|
@ -508,7 +508,7 @@ proc parseAnd(self: Parser): Expression =
|
||||||
result = self.parseCmp()
|
result = self.parseCmp()
|
||||||
var operator: Token
|
var operator: Token
|
||||||
var right: Expression
|
var right: Expression
|
||||||
while self.peek().kind in [Identifier, Symbol] and self.operators.getPrecedence(self.peek().lexeme) == Precedence.And:
|
while self.peek().kind == Symbol and self.operators.getPrecedence(self.peek().lexeme) == Precedence.And:
|
||||||
operator = self.step()
|
operator = self.step()
|
||||||
right = self.parseCmp()
|
right = self.parseCmp()
|
||||||
result = newBinaryExpr(result, operator, right)
|
result = newBinaryExpr(result, operator, right)
|
||||||
|
@ -519,7 +519,7 @@ proc parseOr(self: Parser): Expression =
|
||||||
result = self.parseAnd()
|
result = self.parseAnd()
|
||||||
var operator: Token
|
var operator: Token
|
||||||
var right: Expression
|
var right: Expression
|
||||||
while self.peek().kind in [Identifier, Symbol] and self.operators.getPrecedence(self.peek().lexeme) == Precedence.Or:
|
while self.peek().kind == Symbol and self.operators.getPrecedence(self.peek().lexeme) == Precedence.Or:
|
||||||
operator = self.step()
|
operator = self.step()
|
||||||
right = self.parseAnd()
|
right = self.parseAnd()
|
||||||
result = newBinaryExpr(result, operator, right)
|
result = newBinaryExpr(result, operator, right)
|
||||||
|
@ -528,7 +528,7 @@ proc parseOr(self: Parser): Expression =
|
||||||
proc parseAssign(self: Parser): Expression =
|
proc parseAssign(self: Parser): Expression =
|
||||||
## Parses assignment expressions
|
## Parses assignment expressions
|
||||||
result = self.parseOr()
|
result = self.parseOr()
|
||||||
if self.peek().kind in [Identifier, Symbol] and self.operators.getPrecedence(self.peek().lexeme) == Assign:
|
if self.peek().kind == Symbol and self.operators.getPrecedence(self.peek().lexeme) == Assign:
|
||||||
let tok = self.step()
|
let tok = self.step()
|
||||||
var value = self.expression()
|
var value = self.expression()
|
||||||
case result.kind:
|
case result.kind:
|
||||||
|
@ -545,7 +545,7 @@ proc parseArrow(self: Parser): Expression =
|
||||||
result = self.parseAssign()
|
result = self.parseAssign()
|
||||||
var operator: Token
|
var operator: Token
|
||||||
var right: Expression
|
var right: Expression
|
||||||
while self.peek().kind in [Identifier, Symbol] and self.operators.getPrecedence(self.peek().lexeme) == Precedence.Or:
|
while self.peek().kind == Symbol and self.operators.getPrecedence(self.peek().lexeme) == Precedence.Or:
|
||||||
operator = self.step()
|
operator = self.step()
|
||||||
right = self.parseAssign()
|
right = self.parseAssign()
|
||||||
result = newBinaryExpr(result, operator, right)
|
result = newBinaryExpr(result, operator, right)
|
||||||
|
|
22
src/main.nim
22
src/main.nim
|
@ -14,23 +14,12 @@
|
||||||
|
|
||||||
## Peon's main executable
|
## Peon's main executable
|
||||||
|
|
||||||
# Our stuff
|
|
||||||
import frontend/lexer as l
|
|
||||||
import frontend/parser as p
|
|
||||||
import frontend/compiler as c
|
|
||||||
import backend/vm as v
|
|
||||||
import util/serializer as s
|
|
||||||
import util/debugger
|
|
||||||
import util/symbols
|
|
||||||
import config
|
|
||||||
|
|
||||||
# Builtins & external libs
|
# Builtins & external libs
|
||||||
import std/strformat
|
import std/strformat
|
||||||
import std/strutils
|
import std/strutils
|
||||||
import std/terminal
|
import std/terminal
|
||||||
import std/parseopt
|
import std/parseopt
|
||||||
when debugSerializer:
|
import std/times
|
||||||
import std/times
|
|
||||||
import std/os
|
import std/os
|
||||||
|
|
||||||
# Thanks art <3
|
# Thanks art <3
|
||||||
|
@ -41,6 +30,15 @@ import jale/plugin/editor_history
|
||||||
import jale/keycodes
|
import jale/keycodes
|
||||||
import jale/multiline
|
import jale/multiline
|
||||||
|
|
||||||
|
# Our stuff
|
||||||
|
import frontend/lexer as l
|
||||||
|
import frontend/parser as p
|
||||||
|
import frontend/compiler as c
|
||||||
|
import backend/vm as v
|
||||||
|
import util/serializer as s
|
||||||
|
import util/debugger
|
||||||
|
import util/symbols
|
||||||
|
import config
|
||||||
|
|
||||||
# Forward declarations
|
# Forward declarations
|
||||||
proc getLineEditor: LineEditor
|
proc getLineEditor: LineEditor
|
||||||
|
|
|
@ -0,0 +1,97 @@
|
||||||
|
# Copyright 2022 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.
|
||||||
|
|
||||||
|
## Memory allocator from JAPL
|
||||||
|
|
||||||
|
|
||||||
|
import std/segfaults
|
||||||
|
import ../config
|
||||||
|
|
||||||
|
when debugMem:
|
||||||
|
import std/strformat
|
||||||
|
|
||||||
|
|
||||||
|
proc reallocate*(p: pointer, oldSize: int, newSize: int): pointer =
|
||||||
|
## Simple wrapper around realloc/dealloc
|
||||||
|
try:
|
||||||
|
if newSize == 0 and not p.isNil():
|
||||||
|
when debugMem:
|
||||||
|
if oldSize > 1:
|
||||||
|
echo &"DEBUG - Memory manager: Deallocating {oldSize} bytes"
|
||||||
|
else:
|
||||||
|
echo "DEBUG - Memory manager: Deallocating 1 byte"
|
||||||
|
dealloc(p)
|
||||||
|
return nil
|
||||||
|
if oldSize > 0 and not p.isNil() or oldSize == 0:
|
||||||
|
when debugMem:
|
||||||
|
if oldSize == 0:
|
||||||
|
if newSize > 1:
|
||||||
|
echo &"DEBUG - Memory manager: Allocating {newSize} bytes of memory"
|
||||||
|
else:
|
||||||
|
echo "DEBUG - Memory manager: Allocating 1 byte of memory"
|
||||||
|
else:
|
||||||
|
echo &"DEBUG - Memory manager: Resizing {oldSize} bytes of memory to {newSize} bytes"
|
||||||
|
result = realloc(p, newSize)
|
||||||
|
|
||||||
|
when debugMem:
|
||||||
|
if p.isNil() and newSize == 0:
|
||||||
|
echo &"DEBUG - Memory manager: Warning, asked to dealloc() nil pointer from {oldSize} to {newSize} bytes, ignoring request"
|
||||||
|
elif oldSize > 0 and p.isNil():
|
||||||
|
echo &"DEBUG - Memory manager: Warning, asked to realloc() nil pointer from {oldSize} to {newSize} bytes, ignoring request"
|
||||||
|
except NilAccessDefect:
|
||||||
|
stderr.write("Peon: could not manage memory, segmentation fault\n")
|
||||||
|
quit(139) # For now, there's not much we can do if we can't get the memory we need, so we exit
|
||||||
|
|
||||||
|
type
|
||||||
|
ObjectKind* = enum
|
||||||
|
String, List,
|
||||||
|
Dict, Tuple,
|
||||||
|
CustomType
|
||||||
|
HeapObject* = object
|
||||||
|
## A tag for a heap-allocated
|
||||||
|
## peon object
|
||||||
|
case kind*: ObjectKind
|
||||||
|
of String:
|
||||||
|
str*: ptr UncheckedArray[char]
|
||||||
|
len*: uint64
|
||||||
|
else:
|
||||||
|
discard # TODO
|
||||||
|
|
||||||
|
|
||||||
|
template resizeArray*(kind: untyped, p: pointer, oldCount, newCount: int): untyped =
|
||||||
|
## Handy template to resize a dynamic array
|
||||||
|
cast[ptr UncheckedArray[kind]](reallocate(p, sizeof(kind) * oldCount, sizeof(kind) * newCount))
|
||||||
|
|
||||||
|
|
||||||
|
template freeArray*(kind: untyped, p: pointer, size: int): untyped =
|
||||||
|
## Frees a dynamic array
|
||||||
|
reallocate(p, sizeof(kind) * size, 0)
|
||||||
|
|
||||||
|
|
||||||
|
template free*(kind: untyped, p: pointer): untyped =
|
||||||
|
## Frees a pointer by reallocating its
|
||||||
|
## size to 0
|
||||||
|
reallocate(p, sizeof(kind), 0)
|
||||||
|
|
||||||
|
|
||||||
|
template growCapacity*(capacity: int): untyped =
|
||||||
|
## Handy template used to calculate how much
|
||||||
|
## more memory is needed when reallocating
|
||||||
|
## dynamic arrays
|
||||||
|
if capacity < 8: 8 else: capacity * HeapGrowFactor
|
||||||
|
|
||||||
|
|
||||||
|
template allocate*(castTo: untyped, sizeTo: untyped, count: int): untyped =
|
||||||
|
## Allocates an object and casts its pointer to the specified type
|
||||||
|
cast[ptr castTo](reallocate(nil, 0, sizeof(sizeTo) * count))
|
|
@ -75,11 +75,9 @@ proc toBytes*(s: int): array[8, uint8] =
|
||||||
proc fromBytes*(input: seq[byte]): string =
|
proc fromBytes*(input: seq[byte]): string =
|
||||||
## Converts a sequence of bytes to
|
## Converts a sequence of bytes to
|
||||||
## a string
|
## a string
|
||||||
var i = 0
|
for b in input:
|
||||||
while i < input.len():
|
result.add(char(b))
|
||||||
result.add(char(input[i]))
|
|
||||||
inc(i)
|
|
||||||
|
|
||||||
|
|
||||||
proc extend*[T](s: var seq[T], a: openarray[T]) =
|
proc extend*[T](s: var seq[T], a: openarray[T]) =
|
||||||
## Extends s with the elements of a
|
## Extends s with the elements of a
|
||||||
|
|
16
tests/gc.pn
16
tests/gc.pn
|
@ -1,16 +0,0 @@
|
||||||
import std;
|
|
||||||
|
|
||||||
var x: uint64 = 1000000'u64;
|
|
||||||
var y = "just a test";
|
|
||||||
print(y);
|
|
||||||
print("Starting GC torture test");
|
|
||||||
print(x);
|
|
||||||
while x > 0'u64 {
|
|
||||||
"hello";
|
|
||||||
x = x - 1'u64;
|
|
||||||
}
|
|
||||||
print("END");
|
|
||||||
print(y);
|
|
||||||
y = "test";
|
|
||||||
print(y);
|
|
||||||
"";
|
|
|
@ -1,6 +0,0 @@
|
||||||
# Tests importing another module and executing it
|
|
||||||
|
|
||||||
import std;
|
|
||||||
import import_b;
|
|
||||||
|
|
||||||
print("a");
|
|
|
@ -1,3 +0,0 @@
|
||||||
import std;
|
|
||||||
|
|
||||||
print("b");
|
|
|
@ -1,22 +0,0 @@
|
||||||
import std;
|
|
||||||
|
|
||||||
|
|
||||||
print("Counting down...");
|
|
||||||
var from = 10;
|
|
||||||
let to = 0;
|
|
||||||
while from > to {
|
|
||||||
print(from);
|
|
||||||
from = from - 1;
|
|
||||||
}
|
|
||||||
print("Done!");
|
|
||||||
|
|
||||||
print("Counting up...");
|
|
||||||
var start = 0;
|
|
||||||
let stop = 10;
|
|
||||||
while start < stop {
|
|
||||||
print(start);
|
|
||||||
start = start + 1;
|
|
||||||
}
|
|
||||||
print("Done!");
|
|
||||||
|
|
||||||
|
|
221
tests/std.pn
221
tests/std.pn
|
@ -8,10 +8,8 @@
|
||||||
# - It makes the implementation easier and more flexible
|
# - It makes the implementation easier and more flexible
|
||||||
|
|
||||||
|
|
||||||
# TODO: Use generics
|
|
||||||
|
|
||||||
operator `+`*(a, b: int): int {
|
operator `+`*(a, b: int): int {
|
||||||
#pragma[magic: "Add", pure]
|
#pragma[magic: "SignedAdd", pure]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -21,7 +19,7 @@ operator `+`*(a, b: uint64): uint64 {
|
||||||
|
|
||||||
|
|
||||||
operator `+`*(a, b: int32): int32 {
|
operator `+`*(a, b: int32): int32 {
|
||||||
#pragma[magic: "Add", pure]
|
#pragma[magic: "SignedAdd", pure]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -31,7 +29,7 @@ operator `+`*(a, b: uint32): uint32 {
|
||||||
|
|
||||||
|
|
||||||
operator `+`*(a, b: int16): int16 {
|
operator `+`*(a, b: int16): int16 {
|
||||||
#pragma[magic: "Add", pure]
|
#pragma[magic: "SignedAdd", pure]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -46,157 +44,157 @@ operator `+`*(a, b: int8): int8 {
|
||||||
|
|
||||||
|
|
||||||
operator `+`*(a, b: uint8): uint8 {
|
operator `+`*(a, b: uint8): uint8 {
|
||||||
#pragma[magic: "Add", pure]
|
#pragma[magic: "AddUInt8", pure]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
operator `+`*(a, b: float64): float64 {
|
operator `+`*(a, b: float64): float64 {
|
||||||
#pragma[magic: "Add", pure]
|
#pragma[magic: "AddFloat64", pure]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
operator `+`*(a, b: float32): float32 {
|
operator `+`*(a, b: float32): float32 {
|
||||||
#pragma[magic: "Add", pure]
|
#pragma[magic: "AddFloat32", pure]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
operator `-`*(a, b: int): int {
|
operator `-`*(a, b: int): int {
|
||||||
#pragma[magic: "Subtract", pure]
|
#pragma[magic: "SubInt64", pure]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
operator `-`*(a, b: uint64): uint64 {
|
operator `-`*(a, b: uint64): uint64 {
|
||||||
#pragma[magic: "Subtract", pure]
|
#pragma[magic: "SubUInt64", pure]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
operator `-`*(a, b: int32): int32 {
|
operator `-`*(a, b: int32): int32 {
|
||||||
#pragma[magic: "Subtract", pure]
|
#pragma[magic: "SubInt32", pure]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
operator `-`*(a, b: uint32): uint32 {
|
operator `-`*(a, b: uint32): uint32 {
|
||||||
#pragma[magic: "Subtract", pure]
|
#pragma[magic: "SubUInt32", pure]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
operator `-`*(a, b: int16): int16 {
|
operator `-`*(a, b: int16): int16 {
|
||||||
#pragma[magic: "Subtract", pure]
|
#pragma[magic: "SubInt16", pure]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
operator `-`*(a, b: uint16): uint16 {
|
operator `-`*(a, b: uint16): uint16 {
|
||||||
#pragma[magic: "Subtract", pure]
|
#pragma[magic: "SubUInt16", pure]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
operator `-`*(a, b: int8): int8 {
|
operator `-`*(a, b: int8): int8 {
|
||||||
#pragma[magic: "Subtract", pure]
|
#pragma[magic: "SubInt8", pure]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
operator `-`*(a, b: uint8): uint8 {
|
operator `-`*(a, b: uint8): uint8 {
|
||||||
#pragma[magic: "Subtract", pure]
|
#pragma[magic: "SubUInt8", pure]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
operator `-`*(a, b: float64): float64 {
|
operator `-`*(a, b: float64): float64 {
|
||||||
#pragma[magic: "SubtractFloat64", pure]
|
#pragma[magic: "SubFloat64", pure]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
operator `-`*(a, b: float32): float32 {
|
operator `-`*(a, b: float32): float32 {
|
||||||
#pragma[magic: "SubtractFloat32", pure]
|
#pragma[magic: "SubFloat32", pure]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
operator `*`*(a, b: int): int {
|
operator `*`*(a, b: int): int {
|
||||||
#pragma[magic: "Multiply", pure]
|
#pragma[magic: "SignedMultiply", pure]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
operator `*`*(a, b: uint64): uint64 {
|
operator `*`*(a, b: uint64): uint64 {
|
||||||
#pragma[magic: "Multiply", pure]
|
#pragma[magic: "MulUInt64", pure]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
operator `*`*(a, b: int32): int32 {
|
operator `*`*(a, b: int32): int32 {
|
||||||
#pragma[magic: "Multiply", pure]
|
#pragma[magic: "SignedMultiply", pure]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
operator `*`*(a, b: uint32): uint32 {
|
operator `*`*(a, b: uint32): uint32 {
|
||||||
#pragma[magic: "Multiply", pure]
|
#pragma[magic: "MulUInt32", pure]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
operator `*`*(a, b: int16): int16 {
|
operator `*`*(a, b: int16): int16 {
|
||||||
#pragma[magic: "Multiply", pure]
|
#pragma[magic: "SignedMultiply", pure]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
operator `*`*(a, b: uint16): uint16 {
|
operator `*`*(a, b: uint16): uint16 {
|
||||||
#pragma[magic: "Multiply", pure]
|
#pragma[magic: "MulUInt16", pure]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
operator `*`*(a, b: int8): int8 {
|
operator `*`*(a, b: int8): int8 {
|
||||||
#pragma[magic: "Multiply", pure]
|
#pragma[magic: "SignedMultiply", pure]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
operator `*`*(a, b: uint8): uint8 {
|
operator `*`*(a, b: uint8): uint8 {
|
||||||
#pragma[magic: "Multiply", pure]
|
#pragma[magic: "MulUInt8", pure]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
operator `*`*(a, b: float64): float64 {
|
operator `*`*(a, b: float64): float64 {
|
||||||
#pragma[magic: "MultiplyFloat64", pure]
|
#pragma[magic: "MulFloat64", pure]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
operator `*`*(a, b: float32): float32 {
|
operator `*`*(a, b: float32): float32 {
|
||||||
#pragma[magic: "MultiplyFloat32", pure]
|
#pragma[magic: "MulFloat32", pure]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
operator `/`*(a, b: int): int {
|
operator `/`*(a, b: int): int {
|
||||||
#pragma[magic: "SignedDivide", pure]
|
#pragma[magic: "DivInt64", pure]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
operator `/`*(a, b: uint64): uint64 {
|
operator `/`*(a, b: uint64): uint64 {
|
||||||
#pragma[magic: "Divide", pure]
|
#pragma[magic: "DivUInt64", pure]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
operator `/`*(a, b: int32): int32 {
|
operator `/`*(a, b: int32): int32 {
|
||||||
#pragma[magic: "SignedDivide", pure]
|
#pragma[magic: "DivInt32", pure]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
operator `/`*(a, b: uint32): uint32 {
|
operator `/`*(a, b: uint32): uint32 {
|
||||||
#pragma[magic: "Divide", pure]
|
#pragma[magic: "DivUInt32", pure]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
operator `/`*(a, b: int16): int16 {
|
operator `/`*(a, b: int16): int16 {
|
||||||
#pragma[magic: "SignedDivide", pure]
|
#pragma[magic: "DivInt16", pure]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
operator `/`*(a, b: uint16): uint16 {
|
operator `/`*(a, b: uint16): uint16 {
|
||||||
#pragma[magic: "Divide", pure]
|
#pragma[magic: "DivUInt16", pure]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
operator `/`*(a, b: int8): int8 {
|
operator `/`*(a, b: int8): int8 {
|
||||||
#pragma[magic: "SignedDivide", pure]
|
#pragma[magic: "DivInt8", pure]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
operator `/`*(a, b: uint8): uint8 {
|
operator `/`*(a, b: uint8): uint8 {
|
||||||
#pragma[magic: "Divide", pure]
|
#pragma[magic: "DivUInt8", pure]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -211,313 +209,308 @@ operator `/`*(a, b: float32): float32 {
|
||||||
|
|
||||||
|
|
||||||
operator `**`*(a, b: int64): int64 {
|
operator `**`*(a, b: int64): int64 {
|
||||||
#pragma[magic: "SignedPow", pure]
|
#pragma[magic: "PowInt64", pure]
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
operator `**`*(a, b: uint64): uint64 {
|
|
||||||
#pragma[magic: "Pow", pure]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
# Comparison operators
|
# Comparison operators
|
||||||
|
|
||||||
operator `>`*(a, b: int): bool {
|
operator `>`*(a, b: int): bool {
|
||||||
#pragma[magic: "GreaterThan", pure]
|
#pragma[magic: "GreaterThanInt64", pure]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
operator `<`*(a, b: int): bool {
|
operator `<`*(a, b: int): bool {
|
||||||
#pragma[magic: "LessThan", pure]
|
#pragma[magic: "LessThanInt64", pure]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
operator `==`*(a, b: int): bool {
|
operator `==`*(a, b: int): bool {
|
||||||
#pragma[magic: "Equal", pure]
|
#pragma[magic: "EqualInt64", pure]
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
operator `!=`*(a, b: int): bool {
|
operator `!=`*(a, b: int): bool {
|
||||||
#pragma[magic: "NotEqual", pure]
|
#pragma[magic: "NotEqualInt64", pure]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
operator `>`*(a, b: uint64): bool {
|
operator `>`*(a, b: uint64): bool {
|
||||||
#pragma[magic: "GreaterThan", pure]
|
#pragma[magic: "GreaterThanUInt64", pure]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
operator `<`*(a, b: uint64): bool {
|
operator `<`*(a, b: uint64): bool {
|
||||||
#pragma[magic: "LessThan", pure]
|
#pragma[magic: "LessThanUInt64", pure]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
operator `==`*(a, b: uint64): bool {
|
operator `==`*(a, b: uint64): bool {
|
||||||
#pragma[magic: "Equal", pure]
|
#pragma[magic: "EqualUInt64", pure]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
operator `!=`*(a, b: uint64): bool {
|
operator `!=`*(a, b: uint64): bool {
|
||||||
#pragma[magic: "NotEqual", pure]
|
#pragma[magic: "NotEqualUInt64", pure]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
operator `>`*(a, b: int32): bool {
|
operator `>`*(a, b: int32): bool {
|
||||||
#pragma[magic: "GreaterThan", pure]
|
#pragma[magic: "GreaterThanInt32", pure]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
operator `<`*(a, b: int32): bool {
|
operator `<`*(a, b: int32): bool {
|
||||||
#pragma[magic: "LessThan", pure]
|
#pragma[magic: "LessThanInt32", pure]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
operator `==`*(a, b: int32): bool {
|
operator `==`*(a, b: int32): bool {
|
||||||
#pragma[magic: "Equal", pure]
|
#pragma[magic: "EqualInt32", pure]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
operator `!=`*(a, b: int32): bool {
|
operator `!=`*(a, b: int32): bool {
|
||||||
#pragma[magic: "NotEqual", pure]
|
#pragma[magic: "NotEqualInt32", pure]
|
||||||
}
|
}
|
||||||
|
|
||||||
operator `>`*(a, b: uint32): bool {
|
operator `>`*(a, b: uint32): bool {
|
||||||
#pragma[magic: "GreaterThan", pure]
|
#pragma[magic: "GreaterThanUInt32", pure]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
operator `<`*(a, b: uint32): bool {
|
operator `<`*(a, b: uint32): bool {
|
||||||
#pragma[magic: "LessThan", pure]
|
#pragma[magic: "LessThanUInt32", pure]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
operator `==`*(a, b: uint32): bool {
|
operator `==`*(a, b: uint32): bool {
|
||||||
#pragma[magic: "Equal", pure]
|
#pragma[magic: "EqualUInt32", pure]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
operator `!=`*(a, b: uint32): bool {
|
operator `!=`*(a, b: uint32): bool {
|
||||||
#pragma[magic: "NotEqual", pure]
|
#pragma[magic: "NotEqualUInt32", pure]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
operator `>`*(a, b: int16): bool {
|
operator `>`*(a, b: int16): bool {
|
||||||
#pragma[magic: "GreaterThan", pure]
|
#pragma[magic: "GreaterThanInt16", pure]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
operator `<`*(a, b: int16): bool {
|
operator `<`*(a, b: int16): bool {
|
||||||
#pragma[magic: "LessThan", pure]
|
#pragma[magic: "LessThanInt16", pure]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
operator `==`*(a, b: int16): bool {
|
operator `==`*(a, b: int16): bool {
|
||||||
#pragma[magic: "Equal", pure]
|
#pragma[magic: "EqualInt16", pure]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
operator `!=`*(a, b: int16): bool {
|
operator `!=`*(a, b: int16): bool {
|
||||||
#pragma[magic: "NotEqual", pure]
|
#pragma[magic: "NotEqualInt16", pure]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
operator `>`*(a, b: uint16): bool {
|
operator `>`*(a, b: uint16): bool {
|
||||||
#pragma[magic: "GreaterThan", pure]
|
#pragma[magic: "GreaterThanUInt16", pure]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
operator `<`*(a, b: uint16): bool {
|
operator `<`*(a, b: uint16): bool {
|
||||||
#pragma[magic: "LessThan", pure]
|
#pragma[magic: "LessThanUInt16", pure]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
operator `==`*(a, b: uint16): bool {
|
operator `==`*(a, b: uint16): bool {
|
||||||
#pragma[magic: "Equal", pure]
|
#pragma[magic: "EqualUInt16", pure]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
operator `!=`*(a, b: uint16): bool {
|
operator `!=`*(a, b: uint16): bool {
|
||||||
#pragma[magic: "NotEqual", pure]
|
#pragma[magic: "NotEqualUInt16", pure]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
operator `>`*(a, b: int8): bool {
|
operator `>`*(a, b: int8): bool {
|
||||||
#pragma[magic: "GreaterThan", pure]
|
#pragma[magic: "GreaterThanInt8", pure]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
operator `<`*(a, b: int8): bool {
|
operator `<`*(a, b: int8): bool {
|
||||||
#pragma[magic: "LessThan", pure]
|
#pragma[magic: "LessThanInt8", pure]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
operator `==`*(a, b: int8): bool {
|
operator `==`*(a, b: int8): bool {
|
||||||
#pragma[magic: "Equal", pure]
|
#pragma[magic: "EqualInt8", pure]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
operator `!=`*(a, b: int8): bool {
|
operator `!=`*(a, b: int8): bool {
|
||||||
#pragma[magic: "NotEqual", pure]
|
#pragma[magic: "NotEqualInt8", pure]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
operator `>`*(a, b: uint8): bool {
|
operator `>`*(a, b: uint8): bool {
|
||||||
#pragma[magic: "GreaterThan", pure]
|
#pragma[magic: "GreaterThanUInt8", pure]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
operator `<`*(a, b: uint8): bool {
|
operator `<`*(a, b: uint8): bool {
|
||||||
#pragma[magic: "LessThan", pure]
|
#pragma[magic: "LessThanUInt8", pure]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
operator `==`*(a, b: uint8): bool {
|
operator `==`*(a, b: uint8): bool {
|
||||||
#pragma[magic: "Equal", pure]
|
#pragma[magic: "EqualUInt8", pure]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
operator `!=`*(a, b: uint8): bool {
|
operator `!=`*(a, b: uint8): bool {
|
||||||
#pragma[magic: "NotEqual", pure]
|
#pragma[magic: "NotEqualUInt8", pure]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
operator `>`*(a, b: float): bool {
|
operator `>`*(a, b: float): bool {
|
||||||
#pragma[magic: "GreaterThan", pure]
|
#pragma[magic: "GreaterThanFloat64", pure]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
operator `<`*(a, b: float): bool {
|
operator `<`*(a, b: float): bool {
|
||||||
#pragma[magic: "LessThan", pure]
|
#pragma[magic: "LessThanFloat64", pure]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
operator `==`*(a, b: float): bool {
|
operator `==`*(a, b: float): bool {
|
||||||
#pragma[magic: "Equal", pure]
|
#pragma[magic: "EqualFloat64", pure]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
operator `!=`*(a, b: float): bool {
|
operator `!=`*(a, b: float): bool {
|
||||||
#pragma[magic: "NotEqual", pure]
|
#pragma[magic: "NotEqualFloat64", pure]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
operator `>`*(a, b: float32): bool {
|
operator `>`*(a, b: float32): bool {
|
||||||
#pragma[magic: "GreaterThan", pure]
|
#pragma[magic: "GreaterThanFloat32", pure]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
operator `<`*(a, b: float32): bool {
|
operator `<`*(a, b: float32): bool {
|
||||||
#pragma[magic: "LessThan", pure]
|
#pragma[magic: "LessThanFloat32", pure]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
operator `==`*(a, b: float32): bool {
|
operator `==`*(a, b: float32): bool {
|
||||||
#pragma[magic: "Equal", pure]
|
#pragma[magic: "EqualFloat32", pure]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
operator `!=`*(a, b: float32): bool {
|
operator `!=`*(a, b: float32): bool {
|
||||||
#pragma[magic: "NotEqual", pure]
|
#pragma[magic: "NotEqualFloat32", pure]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
operator `>=`*(a, b: int): bool {
|
operator `>=`*(a, b: int): bool {
|
||||||
#pragma[magic: "GreaterOrEqual", pure]
|
#pragma[magic: "GreaterOrEqualInt64", pure]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
operator `<=`*(a, b: int): bool {
|
operator `<=`*(a, b: int): bool {
|
||||||
#pragma[magic: "LessOrEqual", pure]
|
#pragma[magic: "LessOrEqualInt64", pure]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
operator `>=`*(a, b: uint64): bool {
|
operator `>=`*(a, b: uint64): bool {
|
||||||
#pragma[magic: "GreaterOrEqual", pure]
|
#pragma[magic: "GreaterOrEqualUInt64", pure]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
operator `<=`*(a, b: uint64): bool {
|
operator `<=`*(a, b: uint64): bool {
|
||||||
#pragma[magic: "LessOrEqual", pure]
|
#pragma[magic: "LessOrEqualUInt64", pure]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
operator `>=`*(a, b: int32): bool {
|
operator `>=`*(a, b: int32): bool {
|
||||||
#pragma[magic: "GreaterOrEqual", pure]
|
#pragma[magic: "GreaterOrEqualInt32", pure]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
operator `<=`*(a, b: int32): bool {
|
operator `<=`*(a, b: int32): bool {
|
||||||
#pragma[magic: "LessOrEqual", pure]
|
#pragma[magic: "LessOrEqualInt32", pure]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
operator `>=`*(a, b: uint32): bool {
|
operator `>=`*(a, b: uint32): bool {
|
||||||
#pragma[magic: "GreaterOrEqual", pure]
|
#pragma[magic: "GreaterOrEqualUInt32", pure]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
operator `<=`*(a, b: uint32): bool {
|
operator `<=`*(a, b: uint32): bool {
|
||||||
#pragma[magic: "LessOrEqual", pure]
|
#pragma[magic: "LessOrEqualUInt32", pure]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
operator `>=`*(a, b: int16): bool {
|
operator `>=`*(a, b: int16): bool {
|
||||||
#pragma[magic: "GreaterOrEqual", pure]
|
#pragma[magic: "GreaterOrEqualInt16", pure]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
operator `<=`*(a, b: int16): bool {
|
operator `<=`*(a, b: int16): bool {
|
||||||
#pragma[magic: "LessOrEqual", pure]
|
#pragma[magic: "LessOrEqualInt16", pure]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
operator `>=`*(a, b: uint16): bool {
|
operator `>=`*(a, b: uint16): bool {
|
||||||
#pragma[magic: "GreaterOrEqual", pure]
|
#pragma[magic: "GreaterOrEqualUInt16", pure]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
operator `<=`*(a, b: uint16): bool {
|
operator `<=`*(a, b: uint16): bool {
|
||||||
#pragma[magic: "LessOrEqual", pure]
|
#pragma[magic: "LessOrEqualUInt16", pure]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
operator `>=`*(a, b: int8): bool {
|
operator `>=`*(a, b: int8): bool {
|
||||||
#pragma[magic: "GreaterOrEqual", pure]
|
#pragma[magic: "GreaterOrEqualInt8", pure]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
operator `<=`*(a, b: int8): bool {
|
operator `<=`*(a, b: int8): bool {
|
||||||
#pragma[magic: "LessOrEqual", pure]
|
#pragma[magic: "LessOrEqualInt8", pure]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
operator `>=`*(a, b: uint8): bool {
|
operator `>=`*(a, b: uint8): bool {
|
||||||
#pragma[magic: "GreaterOrEqual", pure]
|
#pragma[magic: "GreaterOrEqualUInt8", pure]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
operator `<=`*(a, b: uint8): bool {
|
operator `<=`*(a, b: uint8): bool {
|
||||||
#pragma[magic: "LessOrEqual", pure]
|
#pragma[magic: "LessOrEqualUInt8", pure]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
operator `>=`*(a, b: float): bool {
|
operator `>=`*(a, b: float): bool {
|
||||||
#pragma[magic: "GreaterOrEqual", pure]
|
#pragma[magic: "GreaterOrEqualFloat64", pure]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
operator `<=`*(a, b: float): bool {
|
operator `<=`*(a, b: float): bool {
|
||||||
#pragma[magic: "LessOrEqual", pure]
|
#pragma[magic: "LessOrEqualFloat64", pure]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
operator `>=`*(a, b: float32): bool {
|
operator `>=`*(a, b: float32): bool {
|
||||||
#pragma[magic: "GreaterOrEqual", pure]
|
#pragma[magic: "GreaterOrEqualFloat32", pure]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
operator `<=`*(a, b: float32): bool {
|
operator `<=`*(a, b: float32): bool {
|
||||||
#pragma[magic: "LessOrEqual", pure]
|
#pragma[magic: "LessOrEqualFloat32", pure]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -545,21 +538,23 @@ fn clock*: float {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn print*(x: int) {
|
# TODO: Replace with generics
|
||||||
#pragma[magic: "PrintInt64"]
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fn print*(x: uint64) {
|
|
||||||
#pragma[magic: "PrintUInt64"]
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fn print*(x: float) {
|
fn print*(x: float) {
|
||||||
#pragma[magic: "PrintFloat64"]
|
#pragma[magic: "GenericPrint"]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn print*(x: int) {
|
||||||
|
#pragma[magic: "GenericPrint"]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn print*(x: string) {
|
fn print*(x: string) {
|
||||||
#pragma[magic: "PrintString"]
|
#pragma[magic: "GenericPrint"]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn print*(x: bool) {
|
||||||
|
#pragma[magic: "GenericPrint"]
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue