Initial work on generics, fixed StoreVar. declareName no longer emits any bytecode (as it doesn't need to)
This commit is contained in:
parent
8d1699ff9e
commit
9c14bfae91
|
@ -227,6 +227,9 @@ proc dispatch*(self: PeonVM) =
|
|||
continue
|
||||
of Pop:
|
||||
discard self.pop()
|
||||
of PopN:
|
||||
for _ in 0..<int(self.readLong()):
|
||||
discard self.pop()
|
||||
of Jump:
|
||||
self.ip = int(self.readShort())
|
||||
of JumpForwards:
|
||||
|
|
|
@ -38,7 +38,7 @@ type
|
|||
Int8, UInt8, Int16, UInt16, Int32,
|
||||
UInt32, Int64, UInt64, Float32, Float64,
|
||||
Char, Byte, String, Function, CustomType,
|
||||
Nil, Nan, Bool, Inf
|
||||
Nil, Nan, Bool, Inf, Typedesc, Generic
|
||||
Type* = ref object
|
||||
## A wrapper around
|
||||
## compile-time types
|
||||
|
@ -489,6 +489,8 @@ proc toIntrinsic(name: string): Type =
|
|||
return Type(kind: Inf)
|
||||
elif name == "bool":
|
||||
return Type(kind: Bool)
|
||||
elif name == "type":
|
||||
return Type(kind: Typedesc)
|
||||
else:
|
||||
return nil
|
||||
|
||||
|
@ -799,14 +801,9 @@ proc declareName(self: Compiler, node: Declaration) =
|
|||
node.value).kind, node: node),
|
||||
codePos: self.chunk.code.len(),
|
||||
isLet: node.isLet))
|
||||
self.emitByte(StoreVar)
|
||||
self.emitBytes(self.names.high().toTriple())
|
||||
of NodeKind.funDecl:
|
||||
var node = FunDecl(node)
|
||||
# Declares the function's name in the
|
||||
# current scope but no StoreVar is emitted
|
||||
# because the name is only useful at compile time.
|
||||
# TODO: Maybe emit some optional debugging
|
||||
# TODO: Emit some optional debugging
|
||||
# metadata to let the VM know where a function's
|
||||
# code begins and ends (similar to what gcc does with
|
||||
# CFI in object files) to build stack traces
|
||||
|
@ -837,6 +834,15 @@ proc declareName(self: Compiler, node: Declaration) =
|
|||
codePos: self.chunk.code.len(),
|
||||
isLet: false))
|
||||
self.names[^1].valueType = self.inferType(argument.valueType)
|
||||
# We check if the argument's type is a generic
|
||||
if self.names[^1].valueType == nil and argument.valueType.kind == identExpr:
|
||||
for gen in node.generics:
|
||||
if gen.name == IdentExpr(argument.valueType):
|
||||
self.names[^1].valueType = Type(kind: Generic)
|
||||
break
|
||||
# If it's still nil, it's an error!
|
||||
if self.names[^1].valueType == nil:
|
||||
self.error(&"cannot determine the type of argument '{self.names[^1].name.token.lexeme}'")
|
||||
self.names[^1].valueType.node = argument.name
|
||||
fn.valueType.args.add(self.names[^1].valueType)
|
||||
else:
|
||||
|
@ -1103,10 +1109,10 @@ proc returnStmt(self: Compiler, node: ReturnStmt) =
|
|||
let returnType = self.inferType(node.value)
|
||||
let typ = self.inferType(self.currentFunction)
|
||||
## Having the return type
|
||||
if typ.returnType == nil and returnType != nil:
|
||||
self.error("non-empty return statement is not allowed in functions with an explicit return type")
|
||||
elif returnType == nil and typ.returnType != nil:
|
||||
if returnType == nil and typ.returnType != nil:
|
||||
self.error(&"expected return value of type '{self.typeToStr(typ.returnType)}', but expression has no type")
|
||||
elif typ.returnType == nil and returnType != nil:
|
||||
self.error("empty return statement is not allowed in non-void functions")
|
||||
elif not self.compareTypes(returnType, typ.returnType):
|
||||
self.error(&"expected return value of type '{self.typeToStr(typ.returnType)}', got '{self.typeToStr(returnType)}' instead")
|
||||
if node.value != nil:
|
||||
|
|
|
@ -672,7 +672,7 @@ proc `$`*(self: ASTNode): string =
|
|||
result &= &"Var(name={self.name}, value={self.value}, const={self.isConst}, private={self.isPrivate}, type={self.valueType})"
|
||||
of funDecl:
|
||||
var self = FunDecl(self)
|
||||
result &= &"""FunDecl(name={self.name}, body={self.body}, type={self.returnType}, arguments=[{self.arguments.join(", ")}], defaults=[{self.defaults.join(", ")}], async={self.isAsync}, generator={self.isGenerator}, private={self.isPrivate})"""
|
||||
result &= &"""FunDecl(name={self.name}, body={self.body}, type={self.returnType}, arguments=[{self.arguments.join(", ")}], defaults=[{self.defaults.join(", ")}], generics=[{self.generics.join(", ")}], async={self.isAsync}, generator={self.isGenerator}, private={self.isPrivate})"""
|
||||
of lambdaExpr:
|
||||
var self = LambdaExpr(self)
|
||||
result &= &"""Lambda(body={self.body}, type={self.returnType}, arguments=[{self.arguments.join(", ")}], defaults=[{self.defaults.join(", ")}], generator={self.isGenerator}, async={self.isAsync})"""
|
||||
|
|
|
@ -785,8 +785,6 @@ proc ifStmt(self: Parser): Statement =
|
|||
template checkDecl(self: Parser, isPrivate: bool) =
|
||||
## Handy utility template that avoids us from copy
|
||||
## pasting the same checks to all declaration handlers
|
||||
if not isPrivate and self.currentFunction != nil:
|
||||
self.error("cannot bind public names inside functions")
|
||||
if not isPrivate and self.scopeDepth > 0:
|
||||
self.error("cannot bind public names inside local scopes")
|
||||
|
||||
|
@ -895,6 +893,20 @@ proc parseFunExpr(self: Parser): LambdaExpr =
|
|||
result.returnType = self.expression()
|
||||
|
||||
|
||||
proc parseGenerics(self: Parser, decl: Declaration) =
|
||||
## Parses generics in declarations
|
||||
var gen: tuple[name: IdentExpr, cond: Expression]
|
||||
while not self.check(RightBracket) and not self.done():
|
||||
self.expect(Identifier, "expecting generic type name")
|
||||
gen.name = newIdentExpr(self.peek(-1))
|
||||
if self.match(":"):
|
||||
gen.cond = self.expression()
|
||||
decl.generics.add(gen)
|
||||
if not self.match(Comma):
|
||||
break
|
||||
self.expect(RightBracket)
|
||||
|
||||
|
||||
proc funDecl(self: Parser, isAsync: bool = false, isGenerator: bool = false,
|
||||
isLambda: bool = false, isOperator: bool = false): Declaration = # Can't use just FunDecl because it can also return LambdaExpr!
|
||||
## Parses all types of functions, coroutines, generators and operators
|
||||
|
@ -922,6 +934,8 @@ proc funDecl(self: Parser, isAsync: bool = false, isGenerator: bool = false,
|
|||
if self.match("*"):
|
||||
FunDecl(self.currentFunction).isPrivate = false
|
||||
self.checkDecl(FunDecl(self.currentFunction).isPrivate)
|
||||
if self.match(LeftBracket):
|
||||
self.parseGenerics(self.currentFunction)
|
||||
elif not isLambda and (self.check([LeftBrace, LeftParen]) or self.check(":")):
|
||||
# We do a bit of hacking to pretend we never
|
||||
# wanted to parse this as a declaration in
|
||||
|
@ -981,8 +995,6 @@ proc funDecl(self: Parser, isAsync: bool = false, isGenerator: bool = false,
|
|||
if isOperator:
|
||||
if arguments.len() == 0:
|
||||
self.error("cannot declare operator without arguments")
|
||||
elif FunDecl(result).returnType == nil:
|
||||
self.error("operators must have a return type")
|
||||
elif isLambda:
|
||||
self.error("cannot declare anonymous operator")
|
||||
for argument in arguments:
|
||||
|
|
Loading…
Reference in New Issue