Fixed issue with self-referencing variable declarations
This commit is contained in:
parent
ace04ee34c
commit
d1d5c10e49
|
@ -616,7 +616,7 @@ method infer*(self: Compiler, node: LiteralExpr): Type =
|
|||
discard # Unreachable
|
||||
|
||||
|
||||
method infer*(self: Compiler, node: Expression): Type =
|
||||
method infer*(self: Compiler, node: Expression): Type =
|
||||
## Infers the type of a given expression and
|
||||
## returns it
|
||||
if node.isNil():
|
||||
|
@ -1008,7 +1008,8 @@ proc declare*(self: Compiler, node: ASTNode): Name {.discardable.} =
|
|||
line: node.token.line,
|
||||
isPrivate: node.isPrivate,
|
||||
isReal: true,
|
||||
belongsTo: self.currentFunction
|
||||
belongsTo: self.currentFunction,
|
||||
valueType: Type(kind: CustomType)
|
||||
)
|
||||
)
|
||||
n = self.names[^1]
|
||||
|
|
|
@ -94,7 +94,7 @@ proc compile*(self: BytecodeCompiler, ast: seq[Declaration], file: string, lines
|
|||
mode: CompileMode = Debug): Chunk
|
||||
proc statement(self: BytecodeCompiler, node: Statement)
|
||||
proc declaration(self: BytecodeCompiler, node: Declaration)
|
||||
proc varDecl(self: BytecodeCompiler, node: VarDecl, name: Name)
|
||||
proc varDecl(self: BytecodeCompiler, node: VarDecl)
|
||||
proc specialize(self: BytecodeCompiler, typ: Type, args: seq[Expression]): Type {.discardable.}
|
||||
proc patchReturnAddress(self: BytecodeCompiler, pos: int)
|
||||
proc handleMagicPragma(self: BytecodeCompiler, pragma: Pragma, name: Name)
|
||||
|
@ -1194,19 +1194,22 @@ method identifier(self: BytecodeCompiler, node: IdentExpr, name: Name = nil, com
|
|||
return nil
|
||||
result = s.valueType
|
||||
if not compile:
|
||||
return
|
||||
return result
|
||||
var node = s.ident
|
||||
if s.isConst:
|
||||
# Constants are always emitted as Load* instructions
|
||||
# no matter the scope depth
|
||||
self.emitConstant(VarDecl(s.node).value, self.infer(node))
|
||||
if strict:
|
||||
self.emitConstant(VarDecl(s.node).value, self.inferOrError(node))
|
||||
else:
|
||||
self.emitConstant(VarDecl(s.node).value, self.infer(node))
|
||||
elif s.kind == NameKind.Function:
|
||||
# Functions have no runtime representation, they're just
|
||||
# a location to jump to, but we pretend they aren't and
|
||||
# resolve them to their address into our bytecode when
|
||||
# they're referenced
|
||||
self.emitByte(LoadUInt64, node.token.line)
|
||||
self.emitBytes(self.chunk.writeConstant(s.valueType.location.toLong()), node.token.line)
|
||||
self.emitBytes(self.chunk.writeConstant(s.codePos.toLong()), node.token.line)
|
||||
elif s.isBuiltin:
|
||||
case s.ident.token.lexeme:
|
||||
of "nil":
|
||||
|
@ -1782,7 +1785,7 @@ proc statement(self: BytecodeCompiler, node: Statement) =
|
|||
self.expression(Expression(node))
|
||||
|
||||
|
||||
proc varDecl(self: BytecodeCompiler, node: VarDecl, name: Name) =
|
||||
proc varDecl(self: BytecodeCompiler, node: VarDecl) =
|
||||
## Compiles variable declarations
|
||||
var typ: Type
|
||||
# Our parser guarantees that the variable declaration
|
||||
|
@ -1793,7 +1796,7 @@ proc varDecl(self: BytecodeCompiler, node: VarDecl, name: Name) =
|
|||
typ = self.inferOrError(node.valueType)
|
||||
if typ.kind == Auto:
|
||||
self.error("automatic types require initialization", node)
|
||||
elif node.valueType.isNil:
|
||||
elif node.valueType.isNil():
|
||||
# Variable has no type declaration: the type
|
||||
# of its value takes over
|
||||
typ = self.inferOrError(node.value)
|
||||
|
@ -1811,6 +1814,12 @@ proc varDecl(self: BytecodeCompiler, node: VarDecl, name: Name) =
|
|||
self.expression(node.value)
|
||||
self.emitByte(AddVar, node.token.line)
|
||||
inc(self.stackIndex)
|
||||
# We declare the name only now in order to make
|
||||
# sure that stuff like var n = n; works as expected.
|
||||
# If we declared it early, we'd have a duplicate with
|
||||
# no type that would shadow the original value, which
|
||||
# is no good
|
||||
var name = self.declare(node)
|
||||
name.position = self.stackIndex
|
||||
name.valueType = typ
|
||||
|
||||
|
@ -1909,6 +1918,13 @@ proc funDecl(self: BytecodeCompiler, node: FunDecl, name: Name) =
|
|||
self.stackIndex = stackIdx
|
||||
|
||||
|
||||
proc typeDecl(self: BytecodeCompiler, node: TypeDecl, name: Name) =
|
||||
## Compiles type declarations
|
||||
for field in node.fields:
|
||||
if self.compare(self.inferOrError(field.valueType), name.valueType) and not node.isRef:
|
||||
self.error(&"illegal type recursion for non-ref type '{name.ident.token.lexeme}'")
|
||||
|
||||
|
||||
proc declaration(self: BytecodeCompiler, node: Declaration) =
|
||||
## Compiles declarations, statements and expressions
|
||||
## recursively
|
||||
|
@ -1941,11 +1957,9 @@ proc declaration(self: BytecodeCompiler, node: Declaration) =
|
|||
if not name.valueType.returnType.isNil() and name.valueType.returnType.kind == Generic:
|
||||
name.valueType.returnType.asUnion = true
|
||||
of NodeKind.typeDecl:
|
||||
# Custom types don't do much other than
|
||||
# declaring a name in the given scope
|
||||
self.declare(node)
|
||||
self.typeDecl(TypeDecl(node), self.declare(node))
|
||||
of NodeKind.varDecl:
|
||||
self.varDecl(VarDecl(node), self.declare(node))
|
||||
self.varDecl(VarDecl(node))
|
||||
else:
|
||||
self.statement(Statement(node))
|
||||
|
||||
|
|
|
@ -757,7 +757,7 @@ proc `$`*(self: ASTNode): string =
|
|||
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}, template={self.isTemplate}, private={self.isPrivate}, pragmas={self.pragmas})"""
|
||||
of typeDecl:
|
||||
var self = TypeDecl(self)
|
||||
result &= &"""TypeDecl(name={self.name}, fields={self.fields}, defaults={self.defaults}, private={self.isPrivate}, pragmas={self.pragmas}, generics={self.generics}, parent={self.parent}, ref={self.isRef}, enum={self.isEnum})"""
|
||||
result &= &"""TypeDecl(name={self.name}, fields={self.fields}, defaults={self.defaults}, private={self.isPrivate}, pragmas={self.pragmas}, generics={self.generics}, parent={self.parent}, ref={self.isRef}, enum={self.isEnum}, value={self.value})"""
|
||||
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}, pragmas={self.pragmas})"""
|
||||
|
|
Loading…
Reference in New Issue