diff --git a/src/backend/vm.nim b/src/backend/vm.nim index 5dfbb3c..c45e100 100644 --- a/src/backend/vm.nim +++ b/src/backend/vm.nim @@ -17,6 +17,7 @@ import std/monotimes import std/math import std/segfaults import std/strutils +import std/sequtils import std/sets @@ -81,6 +82,7 @@ type pointers: HashSet[uint64] objects: seq[ptr HeapObject] + # Implementation of peon's memory manager proc newPeonGC*: PeonGC = @@ -96,10 +98,9 @@ proc collect*(self: PeonGC) proc reallocate*(self: PeonGC, p: pointer, oldSize: int, newSize: int): pointer = - ## Simple wrapper around realloc/dealloc + ## Simple wrapper around realloc/dealloc with + ## built-in garbage collection self.bytesAllocated.current += newSize - oldSize - if self.bytesAllocated.current > self.nextGC: - self.collect() try: if newSize == 0 and not p.isNil(): when debugMem: @@ -112,6 +113,9 @@ proc reallocate*(self: PeonGC, p: pointer, oldSize: int, newSize: int): pointer 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: @@ -166,7 +170,7 @@ proc allocate*(self: PeonGC, kind: ObjectKind, size: typedesc, count: int): ptr proc mark(self: ptr HeapObject): bool = ## Marks a single object - if self.isNil() or self.marked: + if self.marked: return false self.marked = true return true @@ -186,17 +190,20 @@ proc markRoots(self: PeonGC): seq[ptr HeapObject] = # 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 a hash set so + # 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 + # 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: @@ -213,10 +220,11 @@ proc markRoots(self: PeonGC): seq[ptr HeapObject] = for p in live: obj = cast[ptr HeapObject](p) if obj.mark(): - result.add(obj) - when debugMem: - if obj.marked: + 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]) = @@ -224,24 +232,34 @@ proc trace(self: PeonGC, roots: seq[ptr HeapObject]) = ## objects starting from the ## roots. The second argument ## is the output of the mark - ## phase + ## 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 # No additional references + discard # Strings hold no additional references else: - discard # TODO + 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 - self.freeArray(char, obj.str, obj.len) + if obj.len > 0 and not obj.str.isNil(): + self.freeArray(char, obj.str, obj.len) else: discard # TODO self.free(HeapObject, obj) @@ -254,9 +272,15 @@ proc sweep(self: PeonGC) = ## during the mark phase. ## This is more convoluted ## than it needs to be because - ## nim disallows + ## 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: @@ -264,27 +288,34 @@ proc sweep(self: PeonGC) = # but reset its mark so that it doesn't # stay alive forever self.objects[j].marked = false - continue + 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) - idx += 1 + 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 = self.bytesAllocated.current + let before {.used.} = self.bytesAllocated.current + let time {.used.} = getMonoTime().ticks().float() / 1_000_000 when debugGC: - echo "DEBUG - GC: Starting collection cycle" + 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, collected {before - self.bytesAllocated.current} bytes of memory in total" + 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) = @@ -303,11 +334,13 @@ proc newPeonVM*: PeonVM = ## for executing Peon bytecode new(result) result.ip = 0 - result.frames = @[] - result.calls = newSeq[uint64]() - result.operands = newSeq[uint64]() result.initCache() result.gc = newPeonGC() + result.frames = @[] + result.calls = @[] + result.operands = @[] + result.results = @[] + result.closedOver = @[] result.gc.vm = result @@ -373,7 +406,7 @@ proc peek(self: PeonVM, distance: int = 0): uint64 = ## given distance from the top of ## the operand stack without consuming it if distance < 0: - return self.peekb(^(-distance)) + return self.peekb(^(-int(distance))) return self.operands[self.operands.high() + distance] @@ -396,7 +429,7 @@ proc peekc(self: PeonVM, distance: int = 0): uint64 {.used.} = return self.calls[self.calls.high() + distance] -proc getc(self: PeonVM, idx: uint): uint64 = +proc getc(self: PeonVM, idx: uint64): uint64 = ## Accessor method that abstracts ## indexing our call stack through stack ## frames @@ -550,6 +583,8 @@ proc constReadString(self: PeonVM, size, idx: int): ptr HeapObject = result = self.gc.allocate(String, char, len(str)) for i, c in str: result.str[i] = c + when debugAlloc: + echo &"DEBUG - GC: Allocated new object: {result[]}" {.pop.} @@ -576,7 +611,7 @@ when debugVM: # So nim shuts up styledEcho fgMagenta, "]" if self.frames.len() !> 0: stdout.styledWrite(fgCyan, "Current Frame: ", fgMagenta, "[") - for i, e in self.calls[self.frames[^1]..^1]: + for i, e in self.calls[self.frames[^1]..self.calls.high()]: stdout.styledWrite(fgYellow, $e) if i < self.calls.high(): stdout.styledWrite(fgYellow, ", ") @@ -722,7 +757,7 @@ proc dispatch*(self: PeonVM) = # into the given call stack index let idx = self.readLong() when debugVM: - assert idx.int - self.calls.high() <= 1, "StoreVar index is bigger than the length of the call stack" + assert idx - self.calls.high() <= 1, "StoreVar index is bigger than the length of the call stack" if idx + self.frames[^1] <= self.calls.high().uint: self.setc(idx, self.pop()) else: @@ -786,16 +821,17 @@ proc dispatch*(self: PeonVM) = self.ip += self.readLong() of JumpIfTrue: # Conditional positive jump + let ip = self.readLong() if self.peek().bool: - self.ip += self.readLong() + self.ip += ip of JumpIfFalsePop: + let ip = self.readLong() + if not self.pop().bool: + self.ip += ip + of JumpIfFalseOrPop: let ip = self.readLong() if not self.peek().bool: self.ip += ip - discard self.pop() - of JumpIfFalseOrPop: - if not self.peek().bool: - self.ip += self.readLong() else: discard self.pop() # Built-in operations on primitive types. @@ -934,7 +970,32 @@ proc run*(self: PeonVM, chunk: Chunk) = self.frames = @[] self.calls = @[] self.operands = @[] + self.results = @[] 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.} diff --git a/src/config.nim b/src/config.nim index 381e067..0e1df3f 100644 --- a/src/config.nim +++ b/src/config.nim @@ -14,18 +14,19 @@ import strformat -# Debug various components of peon -const debugLexer* {.booldefine.} = false -const debugParser* {.booldefine.} = false -const debugCompiler* {.booldefine.} = false -const debugVM* {.booldefine.} = false -const debugGC* {.booldefine.} = false -const debugMem* {.booldefine.} = false -const debugSerializer* {.booldefine.} = false -const debugStressGC* {.booldefine.} = false -const PeonBytecodeMarker* = "PEON_BYTECODE" -const HeapGrowFactor* = 2 # How much extra memory to allocate for dynamic arrays and garbage collection when resizing -const FirstGC* = 1024 * 1024; +# These variables can be tweaked to debug and test various components of the toolchain +const debugLexer* {.booldefine.} = false # Print the tokenizer's output +const debugParser* {.booldefine.} = false # Print the AST generated by the parser +const debugCompiler* {.booldefine.} = false # Disassemble and print the bytecode generated by the compiler +const debugVM* {.booldefine.} = false # Run the VM in debug mode and show stack and instruction info +const debugGC* {.booldefine.} = false # Debug the Garbage Collector (extremely verbose) +const debugAlloc* {.booldefine.} = false # Trace object allocation (extremely verbose) +const debugMem* {.booldefine.} = false # Debug the memory allocator (extremely verbose) +const debugSerializer* {.booldefine.} = false # Validate the bytecode serializer's output +const debugStressGC* {.booldefine.} = false # Make the GC run a collection at every allocation (VERY SLOW!) +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: {.fatal: "Heap growth factor must be > 1".} const PeonVersion* = (major: 0, minor: 1, patch: 0) diff --git a/src/frontend/compiler.nim b/src/frontend/compiler.nim index 6b948ef..fa3ad75 100644 --- a/src/frontend/compiler.nim +++ b/src/frontend/compiler.nim @@ -296,17 +296,26 @@ proc emitBytes(self: Compiler, bytarr: openarray[OpCode | uint8]) {.inline.} = proc makeConstant(self: Compiler, val: Expression, typ: Type): array[3, uint8] = ## Adds a constant to the current chunk's constant table ## and returns its index as a 3-byte array of uint8s - var v: int - discard parseInt(val.token.lexeme, v) + var lit: string + if typ.kind in [UInt8, Int8, Int16, UInt16, Int32, UInt32, Int64, UInt64]: + 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: of UInt8, Int8: - result = self.chunk.writeConstant([uint8(v)]) + result = self.chunk.writeConstant([uint8(parseInt(lit))]) of Int16, UInt16: - result = self.chunk.writeConstant(v.toDouble()) + result = self.chunk.writeConstant(parseInt(lit).toDouble()) of Int32, UInt32: - result = self.chunk.writeConstant(v.toQuad()) - of Int64, UInt64: - result = self.chunk.writeConstant(v.toLong()) + result = self.chunk.writeConstant(parseInt(lit).toQuad()) + of Int64: + result = self.chunk.writeConstant(parseInt(lit).toLong()) + of UInt64: + result = self.chunk.writeConstant(parseBiggestUInt(lit).toLong()) of String: result = self.chunk.writeConstant(val.token.lexeme[1..^1].toBytes()) of Float32: @@ -372,10 +381,16 @@ proc patchJump(self: Compiler, offset: int) = var jump: int = self.chunk.code.len() - offset if jump > 16777215: self.error("cannot jump more than 16777215 instructions") - # We subtract 4 because that's the size of our jump instruction - # which the caller of patchJump doesn't take into account (and - # that's by design) - let offsetArray = (jump - 4).toTriple() + case OpCode(self.chunk.code[offset]): + of JumpBackwards, Jump, JumpIfFalsePop, JumpIfFalse: + # We subtract 4 because backwards + # and absolute jumps don't take + # 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 + 2] = offsetArray[1] self.chunk.code[offset + 3] = offsetArray[2] @@ -852,14 +867,21 @@ proc literal(self: Compiler, node: ASTNode) = of strExpr: self.emitConstant(LiteralExpr(node), Type(kind: String)) of intExpr: - var x: int - var y = IntExpr(node) - try: - discard parseInt(y.literal.lexeme, x) - except ValueError: - self.error("integer value out of range") - - self.emitConstant(y, self.inferType(y)) + let y = IntExpr(node) + let kind = self.inferType(y) + if kind.kind in [Int64, Int32, Int16, Int8]: + var x: int + try: + discard parseInt(y.literal.lexeme, x) + except ValueError: + self.error("integer value out of range") + 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: var x: int var y = HexExpr(node) @@ -903,7 +925,7 @@ proc literal(self: Compiler, node: ASTNode) = var x: float var y = FloatExpr(node) try: - discard parseFloat(y.literal.lexeme, x) + discard parseFloat(y.literal.lexeme) except ValueError: self.error("floating point value out of range") self.emitConstant(y, self.inferType(y)) @@ -919,7 +941,7 @@ proc literal(self: Compiler, node: ASTNode) = proc handleBuiltinFunction(self: Compiler, fn: Name, args: seq[Expression]) = ## Emits instructions for builtin functions ## such as addition or subtraction - if fn.valueType.builtinOp notin ["GenericLogicalOr", "GenericLogicalAnd"]: + if fn.valueType.builtinOp notin ["LogicalOr", "LogicalAnd"]: if len(args) == 2: self.expression(args[1]) self.expression(args[0]) @@ -1314,8 +1336,8 @@ proc whileStmt(self: Compiler, node: WhileStmt) = self.expression(node.condition) let jump = self.emitJump(JumpIfFalsePop) self.statement(node.body) - self.patchJump(jump) self.emitLoop(start) + self.patchJump(jump) proc checkCallIsPure(self: Compiler, node: ASTnode): bool = diff --git a/src/frontend/parser.nim b/src/frontend/parser.nim index 3339736..149bc91 100644 --- a/src/frontend/parser.nim +++ b/src/frontend/parser.nim @@ -451,7 +451,7 @@ proc call(self: Parser): Expression = proc unary(self: Parser): Expression = ## Parses unary expressions - if self.peek().kind == Symbol and self.peek().lexeme in self.operators.tokens: + if self.peek().kind in [Identifier, Symbol] and self.peek().lexeme in self.operators.tokens: result = newUnaryExpr(self.step(), self.unary()) else: result = self.call() @@ -462,7 +462,7 @@ proc parsePow(self: Parser): Expression = result = self.unary() var operator: Token var right: Expression - while self.peek().kind == Symbol and self.operators.getPrecedence(self.peek().lexeme) == Power: + while self.peek().kind in [Identifier, Symbol] and self.operators.getPrecedence(self.peek().lexeme) == Power: operator = self.step() right = self.unary() result = newBinaryExpr(result, operator, right) @@ -474,7 +474,7 @@ proc parseMul(self: Parser): Expression = result = self.parsePow() var operator: Token var right: Expression - while self.peek().kind == Symbol and self.operators.getPrecedence(self.peek().lexeme) == Multiplication: + while self.peek().kind in [Identifier, Symbol] and self.operators.getPrecedence(self.peek().lexeme) == Multiplication: operator = self.step() right = self.parsePow() result = newBinaryExpr(result, operator, right) @@ -486,7 +486,7 @@ proc parseAdd(self: Parser): Expression = result = self.parseMul() var operator: Token var right: Expression - while self.peek().kind == Symbol and self.operators.getPrecedence(self.peek().lexeme) == Addition: + while self.peek().kind in [Identifier, Symbol] and self.operators.getPrecedence(self.peek().lexeme) == Addition: operator = self.step() right = self.parseMul() result = newBinaryExpr(result, operator, right) @@ -497,7 +497,7 @@ proc parseCmp(self: Parser): Expression = result = self.parseAdd() var operator: Token var right: Expression - while self.peek().kind == Symbol and self.operators.getPrecedence(self.peek().lexeme) == Compare: + while self.peek().kind in [Identifier, Symbol] and self.operators.getPrecedence(self.peek().lexeme) == Compare: operator = self.step() right = self.parseAdd() result = newBinaryExpr(result, operator, right) @@ -508,7 +508,7 @@ proc parseAnd(self: Parser): Expression = result = self.parseCmp() var operator: Token var right: Expression - while self.peek().kind == Symbol and self.operators.getPrecedence(self.peek().lexeme) == Precedence.And: + while self.peek().kind in [Identifier, Symbol] and self.operators.getPrecedence(self.peek().lexeme) == Precedence.And: operator = self.step() right = self.parseCmp() result = newBinaryExpr(result, operator, right) @@ -519,7 +519,7 @@ proc parseOr(self: Parser): Expression = result = self.parseAnd() var operator: Token var right: Expression - while self.peek().kind == Symbol and self.operators.getPrecedence(self.peek().lexeme) == Precedence.Or: + while self.peek().kind in [Identifier, Symbol] and self.operators.getPrecedence(self.peek().lexeme) == Precedence.Or: operator = self.step() right = self.parseAnd() result = newBinaryExpr(result, operator, right) @@ -528,7 +528,7 @@ proc parseOr(self: Parser): Expression = proc parseAssign(self: Parser): Expression = ## Parses assignment expressions result = self.parseOr() - if self.peek().kind == Symbol and self.operators.getPrecedence(self.peek().lexeme) == Assign: + if self.peek().kind in [Identifier, Symbol] and self.operators.getPrecedence(self.peek().lexeme) == Assign: let tok = self.step() var value = self.expression() case result.kind: @@ -545,7 +545,7 @@ proc parseArrow(self: Parser): Expression = result = self.parseAssign() var operator: Token var right: Expression - while self.peek().kind == Symbol and self.operators.getPrecedence(self.peek().lexeme) == Precedence.Or: + while self.peek().kind in [Identifier, Symbol] and self.operators.getPrecedence(self.peek().lexeme) == Precedence.Or: operator = self.step() right = self.parseAssign() result = newBinaryExpr(result, operator, right) diff --git a/src/util/multibyte.nim b/src/util/multibyte.nim index 139a871..951a085 100644 --- a/src/util/multibyte.nim +++ b/src/util/multibyte.nim @@ -75,9 +75,11 @@ proc toBytes*(s: int): array[8, uint8] = proc fromBytes*(input: seq[byte]): string = ## Converts a sequence of bytes to ## a string - for b in input: - result.add(char(b)) - + var i = 0 + while i < input.len(): + result.add(char(input[i])) + inc(i) + proc extend*[T](s: var seq[T], a: openarray[T]) = ## Extends s with the elements of a diff --git a/tests/gc.pn b/tests/gc.pn new file mode 100644 index 0000000..0d49abe --- /dev/null +++ b/tests/gc.pn @@ -0,0 +1,16 @@ +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); +""; \ No newline at end of file diff --git a/tests/import_a.pn b/tests/import_a.pn new file mode 100644 index 0000000..9e688a5 --- /dev/null +++ b/tests/import_a.pn @@ -0,0 +1,6 @@ +# Tests importing another module and executing it + +import std; +import import_b; + +print("a"); diff --git a/tests/import_b.pn b/tests/import_b.pn new file mode 100644 index 0000000..1807405 --- /dev/null +++ b/tests/import_b.pn @@ -0,0 +1,3 @@ +import std; + +print("b"); diff --git a/tests/loops.pn b/tests/loops.pn new file mode 100644 index 0000000..dda0ef3 --- /dev/null +++ b/tests/loops.pn @@ -0,0 +1,22 @@ +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!"); + + diff --git a/tests/std.pn b/tests/std.pn index 0a7980d..2216cc2 100644 --- a/tests/std.pn +++ b/tests/std.pn @@ -8,8 +8,10 @@ # - It makes the implementation easier and more flexible +# TODO: Use generics + operator `+`*(a, b: int): int { - #pragma[magic: "SignedAdd", pure] + #pragma[magic: "Add", pure] } @@ -19,7 +21,7 @@ operator `+`*(a, b: uint64): uint64 { operator `+`*(a, b: int32): int32 { - #pragma[magic: "SignedAdd", pure] + #pragma[magic: "Add", pure] } @@ -29,7 +31,7 @@ operator `+`*(a, b: uint32): uint32 { operator `+`*(a, b: int16): int16 { - #pragma[magic: "SignedAdd", pure] + #pragma[magic: "Add", pure] } @@ -44,157 +46,157 @@ operator `+`*(a, b: int8): int8 { operator `+`*(a, b: uint8): uint8 { - #pragma[magic: "AddUInt8", pure] + #pragma[magic: "Add", pure] } operator `+`*(a, b: float64): float64 { - #pragma[magic: "AddFloat64", pure] + #pragma[magic: "Add", pure] } operator `+`*(a, b: float32): float32 { - #pragma[magic: "AddFloat32", pure] + #pragma[magic: "Add", pure] } operator `-`*(a, b: int): int { - #pragma[magic: "SubInt64", pure] + #pragma[magic: "Subtract", pure] } operator `-`*(a, b: uint64): uint64 { - #pragma[magic: "SubUInt64", pure] + #pragma[magic: "Subtract", pure] } operator `-`*(a, b: int32): int32 { - #pragma[magic: "SubInt32", pure] + #pragma[magic: "Subtract", pure] } operator `-`*(a, b: uint32): uint32 { - #pragma[magic: "SubUInt32", pure] + #pragma[magic: "Subtract", pure] } operator `-`*(a, b: int16): int16 { - #pragma[magic: "SubInt16", pure] + #pragma[magic: "Subtract", pure] } operator `-`*(a, b: uint16): uint16 { - #pragma[magic: "SubUInt16", pure] + #pragma[magic: "Subtract", pure] } operator `-`*(a, b: int8): int8 { - #pragma[magic: "SubInt8", pure] + #pragma[magic: "Subtract", pure] } operator `-`*(a, b: uint8): uint8 { - #pragma[magic: "SubUInt8", pure] + #pragma[magic: "Subtract", pure] } operator `-`*(a, b: float64): float64 { - #pragma[magic: "SubFloat64", pure] + #pragma[magic: "SubtractFloat64", pure] } operator `-`*(a, b: float32): float32 { - #pragma[magic: "SubFloat32", pure] + #pragma[magic: "SubtractFloat32", pure] } operator `*`*(a, b: int): int { - #pragma[magic: "SignedMultiply", pure] + #pragma[magic: "Multiply", pure] } operator `*`*(a, b: uint64): uint64 { - #pragma[magic: "MulUInt64", pure] + #pragma[magic: "Multiply", pure] } operator `*`*(a, b: int32): int32 { - #pragma[magic: "SignedMultiply", pure] + #pragma[magic: "Multiply", pure] } operator `*`*(a, b: uint32): uint32 { - #pragma[magic: "MulUInt32", pure] + #pragma[magic: "Multiply", pure] } operator `*`*(a, b: int16): int16 { - #pragma[magic: "SignedMultiply", pure] + #pragma[magic: "Multiply", pure] } operator `*`*(a, b: uint16): uint16 { - #pragma[magic: "MulUInt16", pure] + #pragma[magic: "Multiply", pure] } operator `*`*(a, b: int8): int8 { - #pragma[magic: "SignedMultiply", pure] + #pragma[magic: "Multiply", pure] } operator `*`*(a, b: uint8): uint8 { - #pragma[magic: "MulUInt8", pure] + #pragma[magic: "Multiply", pure] } operator `*`*(a, b: float64): float64 { - #pragma[magic: "MulFloat64", pure] + #pragma[magic: "MultiplyFloat64", pure] } operator `*`*(a, b: float32): float32 { - #pragma[magic: "MulFloat32", pure] + #pragma[magic: "MultiplyFloat32", pure] } operator `/`*(a, b: int): int { - #pragma[magic: "DivInt64", pure] + #pragma[magic: "SignedDivide", pure] } operator `/`*(a, b: uint64): uint64 { - #pragma[magic: "DivUInt64", pure] + #pragma[magic: "Divide", pure] } operator `/`*(a, b: int32): int32 { - #pragma[magic: "DivInt32", pure] + #pragma[magic: "SignedDivide", pure] } operator `/`*(a, b: uint32): uint32 { - #pragma[magic: "DivUInt32", pure] + #pragma[magic: "Divide", pure] } operator `/`*(a, b: int16): int16 { - #pragma[magic: "DivInt16", pure] + #pragma[magic: "SignedDivide", pure] } operator `/`*(a, b: uint16): uint16 { - #pragma[magic: "DivUInt16", pure] + #pragma[magic: "Divide", pure] } operator `/`*(a, b: int8): int8 { - #pragma[magic: "DivInt8", pure] + #pragma[magic: "SignedDivide", pure] } operator `/`*(a, b: uint8): uint8 { - #pragma[magic: "DivUInt8", pure] + #pragma[magic: "Divide", pure] } @@ -209,308 +211,313 @@ operator `/`*(a, b: float32): float32 { operator `**`*(a, b: int64): int64 { - #pragma[magic: "PowInt64", pure] + #pragma[magic: "SignedPow", pure] +} + + +operator `**`*(a, b: uint64): uint64 { + #pragma[magic: "Pow", pure] } # Comparison operators operator `>`*(a, b: int): bool { - #pragma[magic: "GreaterThanInt64", pure] + #pragma[magic: "GreaterThan", pure] } operator `<`*(a, b: int): bool { - #pragma[magic: "LessThanInt64", pure] + #pragma[magic: "LessThan", pure] } operator `==`*(a, b: int): bool { - #pragma[magic: "EqualInt64", pure] + #pragma[magic: "Equal", pure] } operator `!=`*(a, b: int): bool { - #pragma[magic: "NotEqualInt64", pure] + #pragma[magic: "NotEqual", pure] } operator `>`*(a, b: uint64): bool { - #pragma[magic: "GreaterThanUInt64", pure] + #pragma[magic: "GreaterThan", pure] } operator `<`*(a, b: uint64): bool { - #pragma[magic: "LessThanUInt64", pure] + #pragma[magic: "LessThan", pure] } operator `==`*(a, b: uint64): bool { - #pragma[magic: "EqualUInt64", pure] + #pragma[magic: "Equal", pure] } operator `!=`*(a, b: uint64): bool { - #pragma[magic: "NotEqualUInt64", pure] + #pragma[magic: "NotEqual", pure] } operator `>`*(a, b: int32): bool { - #pragma[magic: "GreaterThanInt32", pure] + #pragma[magic: "GreaterThan", pure] } operator `<`*(a, b: int32): bool { - #pragma[magic: "LessThanInt32", pure] + #pragma[magic: "LessThan", pure] } operator `==`*(a, b: int32): bool { - #pragma[magic: "EqualInt32", pure] + #pragma[magic: "Equal", pure] } operator `!=`*(a, b: int32): bool { - #pragma[magic: "NotEqualInt32", pure] + #pragma[magic: "NotEqual", pure] } operator `>`*(a, b: uint32): bool { - #pragma[magic: "GreaterThanUInt32", pure] + #pragma[magic: "GreaterThan", pure] } operator `<`*(a, b: uint32): bool { - #pragma[magic: "LessThanUInt32", pure] + #pragma[magic: "LessThan", pure] } operator `==`*(a, b: uint32): bool { - #pragma[magic: "EqualUInt32", pure] + #pragma[magic: "Equal", pure] } operator `!=`*(a, b: uint32): bool { - #pragma[magic: "NotEqualUInt32", pure] + #pragma[magic: "NotEqual", pure] } operator `>`*(a, b: int16): bool { - #pragma[magic: "GreaterThanInt16", pure] + #pragma[magic: "GreaterThan", pure] } operator `<`*(a, b: int16): bool { - #pragma[magic: "LessThanInt16", pure] + #pragma[magic: "LessThan", pure] } operator `==`*(a, b: int16): bool { - #pragma[magic: "EqualInt16", pure] + #pragma[magic: "Equal", pure] } operator `!=`*(a, b: int16): bool { - #pragma[magic: "NotEqualInt16", pure] + #pragma[magic: "NotEqual", pure] } operator `>`*(a, b: uint16): bool { - #pragma[magic: "GreaterThanUInt16", pure] + #pragma[magic: "GreaterThan", pure] } operator `<`*(a, b: uint16): bool { - #pragma[magic: "LessThanUInt16", pure] + #pragma[magic: "LessThan", pure] } operator `==`*(a, b: uint16): bool { - #pragma[magic: "EqualUInt16", pure] + #pragma[magic: "Equal", pure] } operator `!=`*(a, b: uint16): bool { - #pragma[magic: "NotEqualUInt16", pure] + #pragma[magic: "NotEqual", pure] } operator `>`*(a, b: int8): bool { - #pragma[magic: "GreaterThanInt8", pure] + #pragma[magic: "GreaterThan", pure] } operator `<`*(a, b: int8): bool { - #pragma[magic: "LessThanInt8", pure] + #pragma[magic: "LessThan", pure] } operator `==`*(a, b: int8): bool { - #pragma[magic: "EqualInt8", pure] + #pragma[magic: "Equal", pure] } operator `!=`*(a, b: int8): bool { - #pragma[magic: "NotEqualInt8", pure] + #pragma[magic: "NotEqual", pure] } operator `>`*(a, b: uint8): bool { - #pragma[magic: "GreaterThanUInt8", pure] + #pragma[magic: "GreaterThan", pure] } operator `<`*(a, b: uint8): bool { - #pragma[magic: "LessThanUInt8", pure] + #pragma[magic: "LessThan", pure] } operator `==`*(a, b: uint8): bool { - #pragma[magic: "EqualUInt8", pure] + #pragma[magic: "Equal", pure] } operator `!=`*(a, b: uint8): bool { - #pragma[magic: "NotEqualUInt8", pure] + #pragma[magic: "NotEqual", pure] } operator `>`*(a, b: float): bool { - #pragma[magic: "GreaterThanFloat64", pure] + #pragma[magic: "GreaterThan", pure] } operator `<`*(a, b: float): bool { - #pragma[magic: "LessThanFloat64", pure] + #pragma[magic: "LessThan", pure] } operator `==`*(a, b: float): bool { - #pragma[magic: "EqualFloat64", pure] + #pragma[magic: "Equal", pure] } operator `!=`*(a, b: float): bool { - #pragma[magic: "NotEqualFloat64", pure] + #pragma[magic: "NotEqual", pure] } operator `>`*(a, b: float32): bool { - #pragma[magic: "GreaterThanFloat32", pure] + #pragma[magic: "GreaterThan", pure] } operator `<`*(a, b: float32): bool { - #pragma[magic: "LessThanFloat32", pure] + #pragma[magic: "LessThan", pure] } operator `==`*(a, b: float32): bool { - #pragma[magic: "EqualFloat32", pure] + #pragma[magic: "Equal", pure] } operator `!=`*(a, b: float32): bool { - #pragma[magic: "NotEqualFloat32", pure] + #pragma[magic: "NotEqual", pure] } operator `>=`*(a, b: int): bool { - #pragma[magic: "GreaterOrEqualInt64", pure] + #pragma[magic: "GreaterOrEqual", pure] } operator `<=`*(a, b: int): bool { - #pragma[magic: "LessOrEqualInt64", pure] + #pragma[magic: "LessOrEqual", pure] } operator `>=`*(a, b: uint64): bool { - #pragma[magic: "GreaterOrEqualUInt64", pure] + #pragma[magic: "GreaterOrEqual", pure] } operator `<=`*(a, b: uint64): bool { - #pragma[magic: "LessOrEqualUInt64", pure] + #pragma[magic: "LessOrEqual", pure] } operator `>=`*(a, b: int32): bool { - #pragma[magic: "GreaterOrEqualInt32", pure] + #pragma[magic: "GreaterOrEqual", pure] } operator `<=`*(a, b: int32): bool { - #pragma[magic: "LessOrEqualInt32", pure] + #pragma[magic: "LessOrEqual", pure] } operator `>=`*(a, b: uint32): bool { - #pragma[magic: "GreaterOrEqualUInt32", pure] + #pragma[magic: "GreaterOrEqual", pure] } operator `<=`*(a, b: uint32): bool { - #pragma[magic: "LessOrEqualUInt32", pure] + #pragma[magic: "LessOrEqual", pure] } operator `>=`*(a, b: int16): bool { - #pragma[magic: "GreaterOrEqualInt16", pure] + #pragma[magic: "GreaterOrEqual", pure] } operator `<=`*(a, b: int16): bool { - #pragma[magic: "LessOrEqualInt16", pure] + #pragma[magic: "LessOrEqual", pure] } operator `>=`*(a, b: uint16): bool { - #pragma[magic: "GreaterOrEqualUInt16", pure] + #pragma[magic: "GreaterOrEqual", pure] } operator `<=`*(a, b: uint16): bool { - #pragma[magic: "LessOrEqualUInt16", pure] + #pragma[magic: "LessOrEqual", pure] } operator `>=`*(a, b: int8): bool { - #pragma[magic: "GreaterOrEqualInt8", pure] + #pragma[magic: "GreaterOrEqual", pure] } operator `<=`*(a, b: int8): bool { - #pragma[magic: "LessOrEqualInt8", pure] + #pragma[magic: "LessOrEqual", pure] } operator `>=`*(a, b: uint8): bool { - #pragma[magic: "GreaterOrEqualUInt8", pure] + #pragma[magic: "GreaterOrEqual", pure] } operator `<=`*(a, b: uint8): bool { - #pragma[magic: "LessOrEqualUInt8", pure] + #pragma[magic: "LessOrEqual", pure] } operator `>=`*(a, b: float): bool { - #pragma[magic: "GreaterOrEqualFloat64", pure] + #pragma[magic: "GreaterOrEqual", pure] } operator `<=`*(a, b: float): bool { - #pragma[magic: "LessOrEqualFloat64", pure] + #pragma[magic: "LessOrEqual", pure] } operator `>=`*(a, b: float32): bool { - #pragma[magic: "GreaterOrEqualFloat32", pure] + #pragma[magic: "GreaterOrEqual", pure] } operator `<=`*(a, b: float32): bool { - #pragma[magic: "LessOrEqualFloat32", pure] + #pragma[magic: "LessOrEqual", pure] } @@ -538,23 +545,21 @@ fn clock*: float { } -# TODO: Replace with generics - -fn print*(x: float) { - #pragma[magic: "GenericPrint"] +fn print*(x: int) { + #pragma[magic: "PrintInt64"] } -fn print*(x: int) { - #pragma[magic: "GenericPrint"] +fn print*(x: uint64) { + #pragma[magic: "PrintUInt64"] +} + + +fn print*(x: float) { + #pragma[magic: "PrintFloat64"] } fn print*(x: string) { - #pragma[magic: "GenericPrint"] -} - - -fn print*(x: bool) { - #pragma[magic: "GenericPrint"] + #pragma[magic: "PrintString"] }