More fixes for assigning builtin functions to variables

This commit is contained in:
Mattia Giambirtone 2022-06-14 23:34:42 +02:00
parent b974ba8ba3
commit 6f60f76270
2 changed files with 46 additions and 34 deletions

View File

@ -40,7 +40,7 @@ type
Int8, UInt8, Int16, UInt16, Int32,
UInt32, Int64, UInt64, Float32, Float64,
Char, Byte, String, Function, CustomType,
Nil, Nan, Bool, Inf, Typedesc, Generic,
Nil, Nan, Bool, Inf, Typevar, Generic,
Mutable, Reference, Pointer
Any # Any is used internally in a few cases,
# for example when looking for operators
@ -57,6 +57,8 @@ type
isCoroutine: bool
args: seq[tuple[name: string, kind: Type]]
returnType: Type
isBuiltinFunction: bool
builtinOp: string
of Mutable, Reference, Pointer:
value: Type
else:
@ -96,9 +98,6 @@ 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
@ -181,8 +180,8 @@ proc varDecl(self: Compiler, node: VarDecl)
proc inferType(self: Compiler, node: LiteralExpr): Type
proc inferType(self: Compiler, node: Expression): Type
proc findByName(self: Compiler, name: string): seq[Name]
proc findByType(self: Compiler, name: string, kind: Type): seq[Name]
proc compareTypes(self: Compiler, a, b: Type): bool
proc findByType(self: Compiler, name: string, kind: Type, strictRef: bool = true): seq[Name]
proc compareTypes(self: Compiler, a, b: Type, strictRef: bool = true): bool
proc patchReturnAddress(self: Compiler, pos: int)
proc handleMagicPragma(self: Compiler, pragma: Pragma, node: ASTnode)
proc handlePurePragma(self: Compiler, pragma: Pragma, node: ASTnode)
@ -430,7 +429,7 @@ proc detectClosureVariable(self: Compiler, name: Name, depth: int = self.scopeDe
name.isClosedOver = true
proc compareTypes(self: Compiler, a, b: Type): bool =
proc compareTypes(self: Compiler, a, b: Type, strictRef: bool = true): bool =
## Compares two type objects
## for equality (works with nil!)
@ -455,7 +454,17 @@ proc compareTypes(self: Compiler, a, b: Type): bool =
# Next, we see the type discriminant:
# If they're different, then they can't
# be the same type!
return false
if strictRef:
return false
else:
# Well... unless we don't care about
# whether it's a ref/value/mutable type
if a.kind in {Reference, Pointer, Mutable}:
return self.compareTypes(a.value, b, strictRef)
elif b.kind in {Reference, Pointer, Mutable}:
return self.compareTypes(a, b.value, strictRef)
else:
return false
case a.kind:
# If all previous checks pass, it's time
# to go through each possible type peon
@ -522,8 +531,8 @@ proc toIntrinsic(name: string): Type =
return Type(kind: Inf)
elif name == "bool":
return Type(kind: Bool)
elif name == "type":
return Type(kind: Typedesc)
elif name == "typevar":
return Type(kind: Typevar)
else:
return nil
@ -765,11 +774,11 @@ proc findByName(self: Compiler, name: string): seq[Name] =
result.add(obj)
proc findByType(self: Compiler, name: string, kind: Type): seq[Name] =
proc findByType(self: Compiler, name: string, kind: Type, strictRef: bool = true): seq[Name] =
## Looks for objects that have already been declared
## with the given name and type
for obj in self.findByName(name):
if self.compareTypes(obj.valueType, kind):
if self.compareTypes(obj.valueType, kind, strictRef):
result.add(obj)
@ -777,7 +786,7 @@ proc matchImpl(self: Compiler, name: string, kind: Type): Name =
## Tries to find a matching function implementation
## compatible with the given type and returns its
## name object
let impl = self.findByType(name, kind)
let impl = self.findByType(name, kind, strictRef=false)
if impl.len() == 0:
var msg = &"cannot find a suitable implementation for '{name}'"
let names = self.findByName(name)
@ -818,10 +827,10 @@ proc emitFunction(self: Compiler, name: Name) =
proc handleBuiltinFunction(self: Compiler, fn: Name, args: seq[Expression]) =
## Emits single instructions for builtin functions
## such as addition or subtraction
if fn.builtinOp notin ["GenericLogicalOr", "GenericLogicalAnd"]:
if fn.valueType.builtinOp notin ["GenericLogicalOr", "GenericLogicalAnd"]:
for argument in args:
self.expression(argument)
case fn.builtinOp:
case fn.valueType.builtinOp:
of "AddInt64":
self.emitByte(AddInt64)
of "SubInt64":
@ -924,7 +933,7 @@ proc handleBuiltinFunction(self: Compiler, fn: Name, args: seq[Expression]) =
proc generateCall(self: Compiler, fn: Name, args: seq[Expression]) =
## Small wrapper that abstracts emitting a call instruction
## for a given function
if fn.isBuiltinFunction:
if fn.valueType.isBuiltinFunction:
self.handleBuiltinFunction(fn, args)
return
self.emitFunction(fn)
@ -1021,13 +1030,14 @@ proc declareName(self: Compiler, node: Declaration, mutable: bool = false) =
isPrivate: node.isPrivate,
owner: self.currentModule,
isConst: node.isConst,
valueType: Type(kind: self.inferType(node.value).kind),
valueType: self.inferType(node.value),
codePos: self.chunk.code.len(),
isLet: node.isLet,
isClosedOver: false,
line: node.token.line))
if mutable:
self.names[^1].valueType = Type(kind: Mutable, value: self.names[^1].valueType)
# TODO:
# if mutable:
# self.names[^1].valueType = Type(kind: Mutable, value: self.names[^1].valueType)
# We emit a jump of 0 because this may become a
# StoreHeap instruction. If they variable is
# not closed over, we'll sadly be wasting a
@ -1116,8 +1126,11 @@ proc identifier(self: Compiler, node: IdentExpr) =
else:
self.detectClosureVariable(s)
if s.valueType.kind == Function:
self.emitByte(LoadFunctionObj)
self.emitBytes(s.codePos.toTriple())
if not s.valueType.isBuiltinFunction:
self.emitByte(LoadFunctionObj)
self.emitBytes(s.codePos.toTriple())
else:
self.emitByte(LoadNil)
elif not s.isClosedOver:
# Static name resolution, loads value at index in the stack. Very fast. Much wow.
self.emitByte(LoadVar)
@ -1352,12 +1365,12 @@ proc callExpr(self: Compiler, node: CallExpr) =
else:
discard # TODO: Calling expressions
if not funct.isNil():
self.generateCall(funct, argExpr)
else:
if funct.isBuiltinFunction:
if funct.valueType.isBuiltinFunction:
self.handleBuiltinFunction(funct, argExpr)
else:
self.generateObjCall(argExpr)
self.generateCall(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")
@ -1635,8 +1648,8 @@ proc handleMagicPragma(self: Compiler, pragma: Pragma, node: ASTNode) =
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]
fn.valueType.isBuiltinFunction = true
fn.valueType.builtinOp = pragma.args[0].token.lexeme[1..^2]
proc handlePurePragma(self: Compiler, pragma: Pragma, node: ASTNode) =
@ -1673,7 +1686,7 @@ proc funDecl(self: Compiler, node: FunDecl) =
self.dispatchPragmas(node)
let fn = self.names[^(node.arguments.len() + 1)]
var jmp: int
if not fn.isBuiltinFunction:
if not fn.valueType.isBuiltinFunction:
self.frames.add(self.names.high())
# A function's code is just compiled linearly
# and then jumped over
@ -1699,7 +1712,7 @@ 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 and not fn.isBuiltinFunction:
if BlockStmt(node.body).code.len() == 0 and not fn.valueType.isBuiltinFunction:
self.error("cannot declare function with empty body")
let fnType = self.inferType(node)
let impl = self.findByType(node.name.token.lexeme, fnType)
@ -1713,7 +1726,7 @@ proc funDecl(self: Compiler, node: FunDecl) =
# We store the current function
self.currentFunction = node
if not fn.isBuiltinFunction:
if not fn.valueType.isBuiltinFunction:
# Since the deferred array is a linear
# sequence of instructions and we want
# to keep track to whose function's each

View File

@ -6,12 +6,11 @@ fn getFunction: fn (n: int): int {
}
getFunction()(5);
operator `+`(a, b: int): int {
#pragma[magic: "AddInt64"]
}
`+`(1, 2);
getFunction()(5);
var x = `+`;
x(1, 2);