From b589f8109a208141d7d4529cb8faf280c95077e9 Mon Sep 17 00:00:00 2001 From: Mattia Giambirtone Date: Wed, 23 Nov 2022 09:29:42 +0100 Subject: [PATCH] Added missing files --- src/backend/dstack.nim | 219 ++++++++++++++++++++++++++++++++++++++++ src/backend/gc.nim | 17 ++++ src/peon/stdlib/math.pn | 16 +++ src/util/fmterr.nim | 100 ++++++++++++++++++ tests/local.pn | 12 +++ tests/math_test.pn | 6 ++ 6 files changed, 370 insertions(+) create mode 100644 src/backend/dstack.nim create mode 100644 src/backend/gc.nim create mode 100644 src/peon/stdlib/math.pn create mode 100644 src/util/fmterr.nim create mode 100644 tests/local.pn create mode 100644 tests/math_test.pn diff --git a/src/backend/dstack.nim b/src/backend/dstack.nim new file mode 100644 index 0000000..e7fc2fa --- /dev/null +++ b/src/backend/dstack.nim @@ -0,0 +1,219 @@ +## A simple, dynamically-growing stack implementation + +import strformat +import ../config + + +type Stack*[T] = object + ## A stack for use in the + ## peon runtime environment + container: ptr UncheckedArray[T] + capacity*: int + length: int + + +proc newStack*[T]: ptr Stack[T] = + ## Allocates a new, empty stack + ## with a starting capacity of 8 + result = cast[ptr Stack[T]](alloc(sizeof(Stack))) + result.capacity = 8 + result.container = cast[ptr UncheckedArray[T]](alloc(sizeof(T) * 8)) + result.length = 0 + + +proc push*[T](self: ptr Stack[T], elem: T) = + ## Pushes an object onto the stack + if self.capacity <= self.length: + self.capacity *= HeapGrowFactor + self.container = cast[ptr UncheckedArray[T]](realloc(self.container, self.capacity)) + self.container[self.length] = elem + self.length += 1 + + +proc pop*[T](self: ptr Stack[T], idx: int = -1): T = + ## Pops an item off the stack. By default, the last + ## element is popped, in which case the operation's + ## time complexity is O(1). When an arbitrary element + ## is popped, the complexity rises to O(k) where k + ## is the number of elements that had to be shifted + ## by 1 to avoid empty slots + var idx = idx + if self.length == 0: + raise newException(IndexDefect, "pop from empty Stack") + if idx == -1: + idx = self.length - 1 + if idx notin 0..self.length - 1: + raise newException(IndexDefect, &"Stack index out of bounds: {idx} notin 0..{self.length - 1}") + result = self.container[idx] + if idx != self.length - 1: + for i in countup(idx, self.length - 1): + self.container[i] = self.container[i + 1] + self.capacity -= 1 + self.length -= 1 + + +proc pop*[T](self: ptr Stack[T], idx: uint64): T = + ## Pops an item off the stack + var idx = idx + if self.length == 0: + raise newException(IndexDefect, "pop from empty Stack") + if idx notin 0'u64..uint64(self.length - 1): + raise newException(IndexDefect, &"Stack index out of bounds: {idx} notin 0..{self.length - 1}") + result = self.container[idx] + if idx != uint64(self.length - 1): + for i in countup(idx, uint64(self.length - 1)): + self.container[i] = self.container[i + 1] + self.capacity -= 1 + self.length -= 1 + + +proc `[]`*[T](self: ptr Stack[T], idx: int): T = + ## Retrieves an item from the stack, in constant + ## time + if self.length == 0: + raise newException(IndexDefect, &"Stack index out of bounds: : {idx} notin 0..{self.length - 1}") + if idx notin 0..self.length - 1: + raise newException(IndexDefect, &"Stack index out of bounds: {idx} notin 0..{self.length - 1}") + result = self.container[idx] + + +proc `[]`*[T](self: ptr Stack[T], idx: uint64): T = + ## Retrieves an item from the stack, in constant + ## time + if self.length == 0: + raise newException(IndexDefect, &"Stack index out of bounds: : {idx} notin 0..{self.length - 1}") + if idx notin 0'u64..uint64(self.length - 1): + raise newException(IndexDefect, &"Stack index out of bounds: {idx} notin 0..{self.length - 1}") + result = self.container[idx] + + +proc `[]`*[T](self: ptr Stack[T], idx: BackwardsIndex): T = + ## Retrieves an item from the stack, in constant + ## time + result = self[self.len() - int(idx)] + + +proc `[]`*[T](self: ptr Stack[T], slice: Hslice[int, int]): ptr Stack[T] = + ## Retrieves a subset of the stack, in O(k) time where k is the size + ## of the slice + if self.length == 0: + raise newException(IndexDefect, "Stack index out of bounds") + if slice.a notin 0..self.length - 1 or slice.b notin 0..self.length: + raise newException(IndexDefect, "Stack index out of bounds") + result = newStack() + for i in countup(slice.a, slice.b - 1): + result.push(self.container[i]) + + +proc `[]=`*[T](self: ptr Stack[T], idx: int, obj: T) = + ## Assigns an object to the given index, in constant + ## time + if self.length == 0: + raise newException(IndexDefect, "Stack is empty") + if idx notin 0..self.length - 1: + raise newException(IndexDefect, "Stack index out of bounds") + self.container[idx] = obj + + +proc `[]=`*[T](self: ptr Stack[T], idx: uint64, obj: T) = + ## Assigns an object to the given index, in constant + ## time + if self.length == 0: + raise newException(IndexDefect, "Stack is empty") + if idx notin 0'u64..uint64(self.length - 1): + raise newException(IndexDefect, "Stack index out of bounds") + self.container[idx] = obj + + +proc delete*[T](self: ptr Stack[T], idx: int) = + ## Deletes an object from the given index. + ## uint64his method shares the time complexity + ## of self.pop() + if self.length == 0: + raise newException(IndexDefect, "delete from empty Stack") + if idx notin 0..self.length - 1: + raise newException(IndexDefect, &"Stack index out of bounds: {idx} notin 0..{self.length - 1}") + discard self.pop(idx) + + +proc delete*[T](self: ptr Stack[T], idx: uint64) = + ## Deletes an object from the given index. + ## uint64his method shares the time complexity + ## of self.pop() + if self.length == 0: + raise newException(IndexDefect, "delete from empty Stack") + if idx notin 0'u64..uint64(self.length - 1): + raise newException(IndexDefect, &"Stack index out of bounds: {idx} notin 0..{self.length - 1}") + discard self.pop(idx) + + +proc contains*[T](self: ptr Stack[T], elem: T): bool = + ## Returns true if the given object is present + ## in the list, false otherwise. O(n) complexity + if self.length > 0: + for i in 0..self.length - 1: + if self[i] == elem: + return true + return false + + +proc high*[T](self: ptr Stack[T]): int = + ## Returns the index of the last + ## element in the list, in constant time + result = self.length - 1 + + +proc len*[T](self: ptr Stack[T]): int = + ## Returns the length of the list + ## in constant time + result = self.length + + +iterator pairs*[T](self: ptr Stack[T]): tuple[key: int, val: T] = + ## Implements pairwise iteration (similar to python's enumerate) + for i in countup(0, self.length - 1): + yield (key: i, val: self[i]) + + +iterator items*[T](self: ptr Stack[T]): T = + ## Implements iteration + for i in countup(0, self.length - 1): + yield self[i] + + +proc reversed*[T](self: ptr Stack[T], first: int = -1, last: int = 0): ptr Stack[T] = + ## Returns a reversed version of the given stack, from first to last. + ## First defaults to -1 (the end of the list) and last defaults to 0 (the + ## beginning of the list) + var first = first + if first == -1: + first = self.length - 1 + result = newStack() + for i in countdown(first, last): + result.push(self[i]) + + +proc extend*[T](self: ptr Stack[T], other: seq[T]) = + ## Iteratively calls self.push() with the elements + ## from a nim sequence + for elem in other: + self.push(elem) + + +proc extend*[T](self: ptr Stack[T], other: ptr Stack[T]) = + ## Iteratively calls self.push() with the elements + ## from another Stack + for elem in other: + self.push(elem) + + +proc `$`*[T](self: ptr Stack[T]): string = + ## Returns a string representation + ## of self + result = "[" + if self.length > 0: + for i in 0..self.length - 1: + result = result & $self.container[i] + if i < self.length - 1: + result = result & ", " + result = result & "]" \ No newline at end of file diff --git a/src/backend/gc.nim b/src/backend/gc.nim new file mode 100644 index 0000000..4ee28d1 --- /dev/null +++ b/src/backend/gc.nim @@ -0,0 +1,17 @@ +# Copyright 2022 Mattia Giambirtone & All Contributors +# +# 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. + +## The peon garbage collector and memory manager + + diff --git a/src/peon/stdlib/math.pn b/src/peon/stdlib/math.pn new file mode 100644 index 0000000..6c4a2a3 --- /dev/null +++ b/src/peon/stdlib/math.pn @@ -0,0 +1,16 @@ +## Peon's math module +import std; + + +const pi* = 3.141592653589793; +const e* = 2.718281828459045; +const tau* = 6.283185307179586; + + +fn abs*[T: int64 | int32 | int16 | int8](n: T): T { + ## Returns the absolute value of the given number + if n < 0 { + return -n; + } + return n; +} \ No newline at end of file diff --git a/src/util/fmterr.nim b/src/util/fmterr.nim new file mode 100644 index 0000000..8aec4a5 --- /dev/null +++ b/src/util/fmterr.nim @@ -0,0 +1,100 @@ +# Copyright 2022 Mattia Giambirtone & All Contributors +# +# 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. + +## Utilities to print formatted error messages to stderr +import ../frontend/compiler +import ../frontend/parser +import ../frontend/lexer +import ../util/serializer + + +import std/os +import std/terminal +import std/strutils +import std/strformat + + +proc print*(exc: CompileError) = + ## Prints a formatted error message + ## for compilation errors to stderr + var file = exc.file + if file notin ["", ""]: + file = relativePath(exc.file, getCurrentDir()) + let line = exc.compiler.getSource().splitLines()[exc.line - 1].strip(chars={'\n'}) + let fn = exc.compiler.getCurrentFunction() + let node = exc.node + let pos = node.getRelativeBoundaries() + stderr.styledWrite(fgRed, styleBright, "Error in ", fgYellow, &"{file}:{exc.line}:{pos.start}") + if not fn.isNil() and fn.kind == funDecl: + stderr.styledWrite(fgRed, styleBright, " in function ", fgYellow, FunDecl(fn).name.token.lexeme) + stderr.styledWriteLine(styleBright, fgDefault, ": ", exc.msg) + stderr.styledWrite(fgRed, styleBright, "Source line: ", resetStyle, fgDefault, line[0..", ""]: + file = relativePath(exc.file, getCurrentDir()) + let line = exc.parser.getSource().splitLines()[exc.line - 1].strip(chars={'\n'}) + let pos = exc.token.relPos + stderr.styledWriteLine(fgRed, styleBright, "Error in ", fgYellow, &"{file}:{exc.line}:{pos.start}", fgDefault, ": " & exc.msg) + stderr.styledWrite(fgRed, styleBright, "Source line: ", resetStyle, fgDefault, line[0..", ""]: + file = relativePath(exc.file, getCurrentDir()) + let line = exc.lexer.getSource().splitLines()[exc.line - 1].strip(chars={'\n'}) + let pos = exc.pos + stderr.styledWriteLine(fgRed, styleBright, "Error in ", fgYellow, &"{file}:{exc.line}:{pos.start}", fgDefault, ": " & exc.msg) + stderr.styledWrite(fgRed, styleBright, "Source line: ", resetStyle, fgDefault, line[0..", ""]: + file = relativePath(exc.file, getCurrentDir()) + stderr.styledWriteLine(fgRed, styleBright, "Error while (de-)serializing ", fgYellow, file, fgDefault, &": {exc.msg}") + + +proc print*(exc: IOError, file: string) = + ## Prints a formatted error message + ## for nim I/O errors to stderr + var file = file + if file notin ["", ""]: + file = relativePath(file, getCurrentDir()) + stderr.styledWriteLine(fgRed, styleBright, "Error while trying to read ", fgYellow, file, fgDefault, &": {exc.msg}") + + +proc print*(exc: OSError, file: string, errno: OSErrorCode) = + ## Prints a formatted error message + ## for nim OS errors to stderr + var file = file + if file notin ["", ""]: + file = relativePath(file, getCurrentDir()) + stderr.styledWriteLine(fgRed, styleBright, "Error while trying to read ", fgYellow, file, fgDefault, &": {exc.msg} ({osErrorMsg(errno)})", + fgRed, "[errno ", fgYellow, $errno, fgRed, "]") diff --git a/tests/local.pn b/tests/local.pn new file mode 100644 index 0000000..cd2ec87 --- /dev/null +++ b/tests/local.pn @@ -0,0 +1,12 @@ +import std; + + +var a = 5; +fn f { + a = 6; +} + + +print(a); +f(); +#print(a); diff --git a/tests/math_test.pn b/tests/math_test.pn new file mode 100644 index 0000000..27a9cd7 --- /dev/null +++ b/tests/math_test.pn @@ -0,0 +1,6 @@ +import std; +import math; + + +print("Testing math module"); +print(math.abs(-5) == 5); \ No newline at end of file