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