From 4591e5ca0ec46038bb32a68bc63fbfaca03bdae6 Mon Sep 17 00:00:00 2001 From: Mattia Giambirtone Date: Tue, 14 Jun 2022 18:10:13 +0200 Subject: [PATCH] Added built-in operators as a single instruction (src/peon/stdlib/arithmetics.pn is now fully functional) --- src/backend/vm.nim | 101 ++++++++++++ src/frontend/compiler.nim | 287 ++++++++++++++++++++++++--------- src/frontend/meta/bytecode.nim | 13 +- src/frontend/parser.nim | 2 +- src/peon/stdlib/arithmetics.pn | 146 +++++++++-------- 5 files changed, 402 insertions(+), 147 deletions(-) diff --git a/src/backend/vm.nim b/src/backend/vm.nim index e5712bf..6c2e590 100644 --- a/src/backend/vm.nim +++ b/src/backend/vm.nim @@ -500,6 +500,107 @@ proc dispatch*(self: PeonVM) = self.ip += self.readLong() else: discard self.pop() + # Built-in operations on primitive types + of AddInt64: + self.push(PeonObject(kind: Int64, long: self.pop().long + self.pop().long)) + of SubInt64: + let second = self.pop() + self.push(PeonObject(kind: Int64, long: self.pop().long - second.long)) + of MulInt64: + self.push(PeonObject(kind: Int64, long: self.pop().long * self.pop().long)) + of DivInt64: + let second = self.pop() + self.push(PeonObject(kind: Int64, long: self.pop().long div second.long)) + of AddUInt64: + self.push(PeonObject(kind: UInt64, uLong: self.pop().uLong + self.pop().uLong)) + of SubUInt64: + let second = self.pop() + self.push(PeonObject(kind: UInt64, uLong: self.pop().uLong - second.uLong)) + of MulUInt64: + self.push(PeonObject(kind: UInt64, uLong: self.pop().uLong * self.pop().uLong)) + of DivUInt64: + let second = self.pop() + self.push(PeonObject(kind: UInt64, uLong: self.pop().uLong div second.uLong)) + of AddInt32: + self.push(PeonObject(kind: Int32, `int`: self.pop().`int` + self.pop().`int`)) + of SubInt32: + let second = self.pop() + self.push(PeonObject(kind: Int32, `int`: self.pop().`int` - second.`int`)) + of MulInt32: + self.push(PeonObject(kind: Int32, `int`: self.pop().`int` * self.pop().`int`)) + of DivInt32: + let second = self.pop() + self.push(PeonObject(kind: Int32, `int`: self.pop().`int` div second.`int`)) + of AddUInt32: + self.push(PeonObject(kind: UInt32, uInt: self.pop().uInt + self.pop().uInt)) + of SubUInt32: + let second = self.pop() + self.push(PeonObject(kind: UInt32, uInt: self.pop().uInt - second.uInt)) + of MulUInt32: + self.push(PeonObject(kind: UInt32, uInt: self.pop().uInt * self.pop().uInt)) + of DivUInt32: + let second = self.pop() + self.push(PeonObject(kind: UInt32, uInt: self.pop().uInt div second.uInt)) + of AddInt16: + self.push(PeonObject(kind: Int16, short: self.pop().short + self.pop().short)) + of SubInt16: + let second = self.pop() + self.push(PeonObject(kind: Int16, short: self.pop().short - second.short)) + of MulInt16: + self.push(PeonObject(kind: Int16, short: self.pop().short * self.pop().short)) + of DivInt16: + let second = self.pop() + self.push(PeonObject(kind: Int16, short: self.pop().short div second.short)) + of AddUInt16: + self.push(PeonObject(kind: UInt16, uShort: self.pop().uShort + self.pop().uShort)) + of SubUInt16: + let second = self.pop() + self.push(PeonObject(kind: UInt16, uShort: self.pop().uShort - second.uShort)) + of MulUInt16: + self.push(PeonObject(kind: UInt16, uShort: self.pop().uShort * self.pop().uShort)) + of DivUInt16: + let second = self.pop() + self.push(PeonObject(kind: UInt16, uShort: self.pop().uShort div second.uShort)) + of AddInt8: + self.push(PeonObject(kind: Int8, tiny: self.pop().tiny + self.pop().tiny)) + of SubInt8: + let second = self.pop() + self.push(PeonObject(kind: Int8, tiny: self.pop().tiny - second.tiny)) + of MulInt8: + self.push(PeonObject(kind: Int8, tiny: self.pop().tiny * self.pop().tiny)) + of DivInt8: + let second = self.pop() + self.push(PeonObject(kind: Int8, tiny: self.pop().tiny div second.tiny)) + of AddUInt8: + self.push(PeonObject(kind: UInt8, uTiny: self.pop().uTiny + self.pop().uTiny)) + of SubUInt8: + let second = self.pop() + self.push(PeonObject(kind: UInt8, uTiny: self.pop().uTiny - second.uTiny)) + of MulUInt8: + self.push(PeonObject(kind: UInt8, uTiny: self.pop().uTiny * self.pop().uTiny)) + of DivUInt8: + let second = self.pop() + self.push(PeonObject(kind: UInt8, uTiny: self.pop().uTiny div second.uTiny)) + of AddFloat64: + self.push(PeonObject(kind: Float64, `float`: self.pop().`float` + self.pop().`float`)) + of SubFloat64: + let second = self.pop() + self.push(PeonObject(kind: Float64, `float`: self.pop().`float` - second.`float`)) + of MulFloat64: + self.push(PeonObject(kind: Float64, `float`: self.pop().`float` * self.pop().`float`)) + of DivFloat64: + let second = self.pop() + self.push(PeonObject(kind: Float64, `float`: self.pop().`float` / second.`float`)) + of AddFloat32: + self.push(PeonObject(kind: Float32, halfFloat: self.pop().halfFloat + self.pop().halfFloat)) + of SubFloat32: + let second = self.pop() + self.push(PeonObject(kind: Float32, halfFloat: self.pop().halfFloat - second.halfFloat)) + of MulFloat32: + self.push(PeonObject(kind: Float32, halfFloat: self.pop().halfFloat * self.pop().halfFloat)) + of DivFloat32: + let second = self.pop() + self.push(PeonObject(kind: Float32, halfFloat: self.pop().halfFloat / second.halfFloat)) else: discard diff --git a/src/frontend/compiler.nim b/src/frontend/compiler.nim index 753fd89..24813d0 100644 --- a/src/frontend/compiler.nim +++ b/src/frontend/compiler.nim @@ -96,6 +96,9 @@ type isFunctionArgument: bool # Where is this node declared in the file? line: int + # is this a builtin function? + isBuiltinFunction: bool + builtinOp: string Loop = object ## A "loop object" used ## by the compiler to emit @@ -183,7 +186,7 @@ proc compareTypes(self: Compiler, a, b: Type): bool proc patchReturnAddress(self: Compiler, pos: int) proc handleMagicPragma(self: Compiler, pragma: Pragma, node: ASTnode) proc handlePurePragma(self: Compiler, pragma: Pragma, node: ASTnode) - +proc dispatchPragmas(self: Compiler, node: ASTnode) ## End of forward declarations @@ -809,9 +812,102 @@ proc emitFunction(self: Compiler, name: Name) = self.emitBytes(name.codePos.toTriple()) +proc handleBuiltinFunction(self: Compiler, fn: Name, args: seq[Expression]) = + ## Emits single instructions for builtin functions + ## such as addition or subtraction + for argument in args: + self.expression(argument) + case fn.builtinOp: + of "AddInt64": + self.emitByte(AddInt64) + of "SubInt64": + self.emitByte(SubInt64) + of "DivInt64": + self.emitByte(DivInt64) + of "MulInt64": + self.emitByte(MulInt64) + of "AddInt32": + self.emitByte(AddInt32) + of "SubInt32": + self.emitByte(SubInt32) + of "DivInt32": + self.emitByte(DivInt32) + of "MulInt32": + self.emitByte(MulInt32) + of "AddInt16": + self.emitByte(AddInt16) + of "SubInt16": + self.emitByte(SubInt16) + of "DivInt16": + self.emitByte(DivInt16) + of "MulInt16": + self.emitByte(MulInt16) + of "AddInt8": + self.emitByte(AddInt8) + of "SubInt8": + self.emitByte(SubInt8) + of "DivInt8": + self.emitByte(DivInt8) + of "MulInt8": + self.emitByte(MulInt8) + of "AddUInt64": + self.emitByte(AddUInt64) + of "SubUInt64": + self.emitByte(SubUInt64) + of "DivUInt64": + self.emitByte(DivUInt64) + of "MulUInt64": + self.emitByte(MulUInt64) + of "AddUInt32": + self.emitByte(AddUInt32) + of "SubUInt32": + self.emitByte(SubUInt32) + of "DivUInt32": + self.emitByte(DivUInt32) + of "MulUInt32": + self.emitByte(MulUInt32) + of "AddUInt16": + self.emitByte(AddUInt16) + of "SubUInt16": + self.emitByte(SubUInt16) + of "DivUInt16": + self.emitByte(DivUInt16) + of "MulUInt16": + self.emitByte(MulUInt16) + of "AddUInt8": + self.emitByte(AddUInt8) + of "SubUInt8": + self.emitByte(SubUInt8) + of "DivUInt8": + self.emitByte(DivUInt8) + of "MulUInt8": + self.emitByte(MulUInt8) + of "AddFloat64": + self.emitByte(AddInt8) + of "SubFloat64": + self.emitByte(SubInt8) + of "DivFloat64": + self.emitByte(DivInt8) + of "MulFloat64": + self.emitByte(MulInt8) + of "AddFloat32": + self.emitByte(AddFloat32) + of "SubFloat32": + self.emitByte(SubFloat32) + of "DivFloat32": + self.emitByte(DivFloat32) + of "MulFloat32": + self.emitByte(MulFloat32) + else: + discard # Unreachable + + proc generateCall(self: Compiler, fn: Name, args: seq[Expression]) = ## Small wrapper that abstracts emitting a call instruction ## for a given function + if fn.isBuiltinFunction: + self.handleBuiltinFunction(fn, args) + return self.emitFunction(fn) self.emitByte(LoadReturnAddress) let pos = self.chunk.code.len() @@ -834,6 +930,7 @@ proc generateCall(self: Compiler, fn: Name, args: seq[Expression]) = proc generateObjCall(self: Compiler, args: seq[Expression]) = ## Small wrapper that abstracts emitting a call instruction ## for a given function already loaded on the operand stack + self.emitByte(PushC) # Pops the function off the operand stack onto the call stack self.emitByte(LoadReturnAddress) let pos = self.chunk.code.len() @@ -1263,7 +1360,10 @@ proc callExpr(self: Compiler, node: CallExpr) = if not funct.isNil(): self.generateCall(funct, argExpr) else: - self.generateObjCall(argExpr) + if funct.isBuiltinFunction: + self.handleBuiltinFunction(funct, argExpr) + else: + self.generateObjCall(argExpr) if self.scopeDepth > 0 and not self.checkCallIsPure(node.callee): if not self.currentFunction.name.isNil(): self.error(&"cannot make sure that calls to '{self.currentFunction.name.token.lexeme}' are side-effect free") @@ -1529,28 +1629,65 @@ proc typeDecl(self: Compiler, node: TypeDecl) = proc handleMagicPragma(self: Compiler, pragma: Pragma, node: ASTNode) = - ## Handles the "magic" pragma + ## Handles the "magic" pragma. Assumes the given name is already + ## declared + if pragma.args.len() != 1: + self.error("'magic' pragma: wrong number of arguments") + elif pragma.args[0].kind != strExpr: + self.error("'magic' pragma: wrong type of argument (string expected)") + elif node.kind != NodeKind.funDecl: + self.error("'magic' pragma is not valid in this context") + var node = FunDecl(node) + var fn = self.resolve(node.name) + fn.isBuiltinFunction = true + fn.builtinOp = pragma.args[0].token.lexeme[1..^2] proc handlePurePragma(self: Compiler, pragma: Pragma, node: ASTNode) = ## Handles the "pure" pragma + case node.kind: + of funDecl: + FunDecl(node).isPure = true + of lambdaExpr: + LambdaExpr(node).isPure = true + else: + self.error("'pure' pragma: invalid usage") + + +proc dispatchPragmas(self: Compiler, node: ASTnode) = + ## Dispatches pragmas bound to objects + var pragmas: seq[Pragma] = @[] + case node.kind: + of funDecl, NodeKind.typeDecl, NodeKind.varDecl: + pragmas = Declaration(node).pragmas + of lambdaExpr: + pragmas = LambdaExpr(node).pragmas + else: + discard # Unreachable + for pragma in pragmas: + if pragma.name.token.lexeme notin self.compilerProcs: + self.error(&"unknown pragma '{pragma.name.token.lexeme}'") + self.compilerProcs[pragma.name.token.lexeme](self, pragma, node) proc funDecl(self: Compiler, node: FunDecl) = ## Compiles function declarations var function = self.currentFunction self.declareName(node) - self.frames.add(self.names.high()) + self.dispatchPragmas(node) let fn = self.names[^(node.arguments.len() + 1)] - # A function's code is just compiled linearly - # and then jumped over - let jmp = self.emitJump(JumpForwards) - # Function's code starts after the jump - fn.codePos = self.chunk.code.len() - for argument in node.arguments: - # Pops off the operand stack onto the - # call stack - self.emitByte(LoadArgument) + var jmp: int + if not fn.isBuiltinFunction: + self.frames.add(self.names.high()) + # A function's code is just compiled linearly + # and then jumped over + jmp = self.emitJump(JumpForwards) + # Function's code starts after the jump + fn.codePos = self.chunk.code.len() + for argument in node.arguments: + # Pops off the operand stack onto the + # call stack + self.emitByte(LoadArgument) if not node.returnType.isNil() and self.inferType(node.returnType).isNil(): # Are we returning a generic type? var isGeneric = false @@ -1566,11 +1703,8 @@ proc funDecl(self: Compiler, node: FunDecl) = self.error(&"cannot infer the type of '{node.returnType.token.lexeme}'") # TODO: Forward declarations if not node.body.isNil(): - if BlockStmt(node.body).code.len() == 0: - if node.pragmas.len() > 0: - discard - else: - self.error("cannot declare function with empty body") + if BlockStmt(node.body).code.len() == 0 and not fn.isBuiltinFunction: + self.error("cannot declare function with empty body") let fnType = self.inferType(node) let impl = self.findByType(node.name.token.lexeme, fnType) if impl.len() > 1: @@ -1583,67 +1717,68 @@ proc funDecl(self: Compiler, node: FunDecl) = # We store the current function self.currentFunction = node - # Since the deferred array is a linear - # sequence of instructions and we want - # to keep track to whose function's each - # set of deferred instruction belongs, - # we record the length of the deferred - # array before compiling the function - # and use this info later to compile - # the try/finally block with the deferred - # code - var deferStart = self.deferred.len() - # We let our debugger know a function is starting - let start = self.chunk.code.high() - self.beginScope() - for decl in BlockStmt(node.body).code: - self.declaration(decl) - var typ: Type - var hasVal: bool = false - case self.currentFunction.kind: - of NodeKind.funDecl: - typ = self.inferType(self.currentFunction) - hasVal = self.currentFunction.hasExplicitReturn - of NodeKind.lambdaExpr: - typ = self.inferType(LambdaExpr(Declaration(self.currentFunction))) - hasVal = LambdaExpr(Declaration(self.currentFunction)).hasExplicitReturn + if not fn.isBuiltinFunction: + # Since the deferred array is a linear + # sequence of instructions and we want + # to keep track to whose function's each + # set of deferred instruction belongs, + # we record the length of the deferred + # array before compiling the function + # and use this info later to compile + # the try/finally block with the deferred + # code + var deferStart = self.deferred.len() + # We let our debugger know a function is starting + let start = self.chunk.code.high() + self.beginScope() + for decl in BlockStmt(node.body).code: + self.declaration(decl) + var typ: Type + var hasVal: bool = false + case self.currentFunction.kind: + of NodeKind.funDecl: + typ = self.inferType(self.currentFunction) + hasVal = self.currentFunction.hasExplicitReturn + of NodeKind.lambdaExpr: + typ = self.inferType(LambdaExpr(Declaration(self.currentFunction))) + hasVal = LambdaExpr(Declaration(self.currentFunction)).hasExplicitReturn + else: + discard # Unreachable + if hasVal and self.currentFunction.returnType.isNil() and not typ.returnType.isNil(): + self.error("non-empty return statement is not allowed in void functions") + elif not hasVal and not self.currentFunction.returnType.isNil(): + self.error("function has an explicit return type, but no return statement was found") + self.endFunctionBeforeReturn() + hasVal = hasVal and not typ.returnType.isNil() + self.endScope(deleteNames=true, fromFunc=true) + # Terminates the function's context + self.emitByte(OpCode.Return) + if hasVal: + self.emitByte(1) else: - discard # Unreachable - if hasVal and self.currentFunction.returnType.isNil() and not typ.returnType.isNil(): - self.error("non-empty return statement is not allowed in void functions") - elif not hasVal and not self.currentFunction.returnType.isNil(): - self.error("function has an explicit return type, but no return statement was found") - self.endFunctionBeforeReturn() - hasVal = hasVal and not typ.returnType.isNil() - self.endScope(deleteNames=true, fromFunc=true) - # Terminates the function's context - self.emitByte(OpCode.Return) - if hasVal: - self.emitByte(1) - else: - self.emitByte(0) - # Function is ending! - self.chunk.cfi.add(start.toTriple()) - self.chunk.cfi.add(self.chunk.code.high().toTriple()) - self.chunk.cfi.add(self.frames[^1].toTriple()) - self.chunk.cfi.add(uint8(node.arguments.len())) - if not node.name.isNil(): - self.chunk.cfi.add(node.name.token.lexeme.len().toDouble()) - var s = node.name.token.lexeme - if node.name.token.lexeme.len() >= uint16.high().int: - s = node.name.token.lexeme[0..uint16.high()] - self.chunk.cfi.add(s.toBytes()) - else: - self.chunk.cfi.add(0.toDouble()) - # Currently defer is not functional so we - # just pop the instructions - for i in countup(deferStart, self.deferred.len() - 1, 1): - self.deferred.delete(i) + self.emitByte(0) + # Function is ending! + self.chunk.cfi.add(start.toTriple()) + self.chunk.cfi.add(self.chunk.code.high().toTriple()) + self.chunk.cfi.add(self.frames[^1].toTriple()) + self.chunk.cfi.add(uint8(node.arguments.len())) + if not node.name.isNil(): + self.chunk.cfi.add(node.name.token.lexeme.len().toDouble()) + var s = node.name.token.lexeme + if node.name.token.lexeme.len() >= uint16.high().int: + s = node.name.token.lexeme[0..uint16.high()] + self.chunk.cfi.add(s.toBytes()) + else: + self.chunk.cfi.add(0.toDouble()) + # Currently defer is not functional so we + # just pop the instructions + for i in countup(deferStart, self.deferred.len() - 1, 1): + self.deferred.delete(i) - self.patchJump(jmp) - # This makes us compile nested functions correctly + self.patchJump(jmp) + # This makes us compile nested functions correctly + discard self.frames.pop() self.currentFunction = function - discard self.frames.pop() proc patchReturnAddress(self: Compiler, pos: int) = diff --git a/src/frontend/meta/bytecode.nim b/src/frontend/meta/bytecode.nim index ccff299..35917e2 100644 --- a/src/frontend/meta/bytecode.nim +++ b/src/frontend/meta/bytecode.nim @@ -123,6 +123,14 @@ type DivUInt16, DivInt8, DivUInt8, + AddFloat64, + SubFloat64, + DivFloat64, + MulFloat64, + AddFloat32, + SubFloat32, + DivFloat32, + MulFloat32, ## Basic stack operations Pop, # Pops an element off the stack and discards it PopRepl, # Same as Pop, but also prints the value of what's popped (used in REPL mode) @@ -184,7 +192,10 @@ const simpleInstructions* = {Return, LoadNil, MulUInt16, MulInt8, MulUInt8, DivInt64, DivUInt64, DivInt32, DivUInt32, DivInt16, DivUInt16, - DivInt8, DivUInt8 + DivInt8, DivUInt8, AddFloat64, + SubFloat64, DivFloat64, MulFloat64, + AddFloat32, SubFloat32, DivFloat32, + MulFloat32 } # Constant instructions are instructions that operate on the bytecode constant table diff --git a/src/frontend/parser.nim b/src/frontend/parser.nim index 098b4d7..e46003f 100644 --- a/src/frontend/parser.nim +++ b/src/frontend/parser.nim @@ -1226,7 +1226,7 @@ proc declaration(self: Parser): Declaration = proc parse*(self: Parser, tokens: seq[Token], file: string): seq[Declaration] = ## Parses a sequence of tokens into a sequence of AST nodes - self.tokens = @[] + self.tokens = tokens self.file = file self.current = 0 self.currentLoop = LoopContext.None diff --git a/src/peon/stdlib/arithmetics.pn b/src/peon/stdlib/arithmetics.pn index 63768f1..baf4850 100644 --- a/src/peon/stdlib/arithmetics.pn +++ b/src/peon/stdlib/arithmetics.pn @@ -2,192 +2,200 @@ operator `+`(a, b: int): int { - #pragma[magic: AddInt64, pure] - return; + #pragma[magic: "AddInt64", pure] } -operator `+`(a, b: uint): uint { - #pragma[magic: AddUInt64, pure] - return; +operator `+`(a, b: uint64): uint64 { + #pragma[magic: "AddUInt64", pure] } operator `+`(a, b: int32): int32 { - #pragma[magic: AddInt32, pure] - return; + #pragma[magic: "AddInt32", pure] } operator `+`(a, b: uint32): uint32 { - #pragma[magic: AddUInt32, pure] - return; + #pragma[magic: "AddUInt32", pure] } operator `+`(a, b: int16): int16 { - #pragma[magic: AddInt16, pure] - return; + #pragma[magic: "AddInt16", pure] } operator `+`(a, b: uint16): uint16 { - #pragma[magic: AddUInt16, pure] - return; + #pragma[magic: "AddUInt16", pure] } operator `+`(a, b: int8): int8 { - #pragma[magic: AddInt8, pure] - return; + #pragma[magic: "AddInt8", pure] } operator `+`(a, b: uint8): uint8 { - #pragma[magic: AddUInt8, pure] - return; + #pragma[magic: "AddUInt8", pure] +} + + +operator `+`(a, b: float64): float64 { + #pragma[magic: "AddFloat64", pure] +} + + +operator `+`(a, b: float32): float32 { + #pragma[magic: "AddFloat32", pure] } operator `-`(a, b: int): int { - #pragma[magic: SubInt64, pure] - return; + #pragma[magic: "SubInt64", pure] } -operator `-`(a, b: uint): uint { - #pragma[magic: SubUInt64, pure] - return; +operator `-`(a, b: uint64): uint64 { + #pragma[magic: "SubUInt64", pure] } operator `-`(a, b: int32): int32 { - #pragma[magic: SubInt32, pure] - return; + #pragma[magic: "SubInt32", pure] } operator `-`(a, b: uint32): uint32 { - #pragma[magic: SubUInt32, pure] - return; + #pragma[magic: "SubUInt32", pure] } operator `-`(a, b: int16): int16 { - #pragma[magic: SubInt16, pure] - return; + #pragma[magic: "SubInt16", pure] } operator `-`(a, b: uint16): uint16 { - #pragma[magic: SubUInt16, pure] - return; + #pragma[magic: "SubUInt16", pure] } operator `-`(a, b: int8): int8 { - #pragma[magic: SubInt8, pure] - return; + #pragma[magic: "SubInt8", pure] } operator `-`(a, b: uint8): uint8 { - #pragma[magic: SubUInt8, pure] - return; + #pragma[magic: "SubUInt8", pure] +} + + +operator `-`(a, b: float64): float64 { + #pragma[magic: "SubFloat64", pure] +} + + +operator `-`(a, b: float32): float32 { + #pragma[magic: "SubFloat32", pure] } operator `*`(a, b: int): int { - #pragma[magic: MulInt64, pure] - return; + #pragma[magic: "MulInt64", pure] } -operator `*`(a, b: uint): uint { - #pragma[magic: MulUInt64, pure] - return; +operator `*`(a, b: uint64): uint64 { + #pragma[magic: "MulUInt64", pure] } operator `*`(a, b: int32): int32 { - #pragma[magic: MulInt32, pure] - return; + #pragma[magic: "MulInt32", pure] } operator `*`(a, b: uint32): uint32 { - #pragma[magic: MulUInt32, pure] - return; + #pragma[magic: "MulUInt32", pure] } operator `*`(a, b: int16): int16 { - #pragma[magic: MulInt16, pure] - return; + #pragma[magic: "MulInt16", pure] } operator `*`(a, b: uint16): uint16 { - #pragma[magic: MulUInt16, pure] - return; + #pragma[magic: "MulUInt16", pure] } operator `*`(a, b: int8): int8 { - #pragma[magic: MulInt8, pure] - return; + #pragma[magic: "MulInt8", pure] } operator `*`(a, b: uint8): uint8 { - #pragma[magic: MulUInt8, pure] - return; + #pragma[magic: "MulUInt8", pure] +} + + +operator `*`(a, b: float64): float64 { + #pragma[magic: "MulFloat64", pure] +} + + +operator `*`(a, b: float32): float32 { + #pragma[magic: "MulFloat32", pure] } operator `/`(a, b: int): int { - #pragma[magic: DivInt64, pure] - return; + #pragma[magic: "DivInt64", pure] } -operator `/`(a, b: uint): uint { - #pragma[magic: DivUInt64, pure] - return; +operator `/`(a, b: uint64): uint64 { + #pragma[magic: "DivUInt64", pure] } operator `/`(a, b: int32): int32 { - #pragma[magic: DivInt32, pure] - return; + #pragma[magic: "DivInt32", pure] } operator `/`(a, b: uint32): uint32 { - #pragma[magic: DivUInt32, pure] - return; + #pragma[magic: "DivUInt32", pure] } operator `/`(a, b: int16): int16 { - #pragma[magic: DivInt16, pure] - return; + #pragma[magic: "DivInt16", pure] } operator `/`(a, b: uint16): uint16 { - #pragma[magic: DivUInt16, pure] - return; + #pragma[magic: "DivUInt16", pure] } operator `/`(a, b: int8): int8 { - #pragma[magic: DivInt8, pure] - return; + #pragma[magic: "DivInt8", pure] } operator `/`(a, b: uint8): uint8 { - #pragma[magic: DivUInt8, pure] - return; -} \ No newline at end of file + #pragma[magic: "DivUInt8", pure] +} + + +operator `/`(a, b: float64): float64 { + #pragma[magic: "DivFloat64", pure] +} + + +operator `/`(a, b: float32): float32 { + #pragma[magic: "DivFloat32", pure] +}