More fixes for assigning builtin functions to variables
This commit is contained in:
parent
b974ba8ba3
commit
6f60f76270
|
@ -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
|
||||
|
|
|
@ -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);
|
Loading…
Reference in New Issue