Merge
This commit is contained in:
parent
7bae3ad249
commit
20da594116
|
@ -68,7 +68,8 @@ type
|
|||
## this system and is not handled
|
||||
## manually by the VM
|
||||
bytesAllocated: tuple[total, current: int]
|
||||
cycles: int
|
||||
when debugGC or debugAlloc:
|
||||
cycles: int
|
||||
nextGC: int
|
||||
pointers: HashSet[uint64]
|
||||
PeonVM* = object
|
||||
|
@ -93,9 +94,10 @@ type
|
|||
frames: seq[uint64] # Stores the bottom of stack frames
|
||||
results: seq[uint64] # Stores function return values
|
||||
gc: PeonGC # A reference to the VM's garbage collector
|
||||
breakpoints: seq[uint64] # Breakpoints where we call our debugger
|
||||
debugNext: bool # Whether to debug the next instruction
|
||||
lastDebugCommand: string # The last debugging command input by the user
|
||||
when debugVM:
|
||||
breakpoints: seq[uint64] # Breakpoints where we call our debugger
|
||||
debugNext: bool # Whether to debug the next instruction
|
||||
lastDebugCommand: string # The last debugging command input by the user
|
||||
|
||||
|
||||
# Implementation of peon's memory manager
|
||||
|
@ -105,7 +107,8 @@ proc newPeonGC*: PeonGC =
|
|||
## garbage collector
|
||||
result.bytesAllocated = (0, 0)
|
||||
result.nextGC = FirstGC
|
||||
result.cycles = 0
|
||||
when debugGC or debugAlloc:
|
||||
result.cycles = 0
|
||||
|
||||
|
||||
proc collect*(self: var PeonVM)
|
||||
|
@ -214,6 +217,16 @@ proc markRoots(self: var PeonVM): HashSet[ptr HeapObject] =
|
|||
# will mistakenly assume the object to be reachable, potentially
|
||||
# leading to a nasty memory leak. Let's just hope a 48+ bit address
|
||||
# space makes this occurrence rare enough not to be a problem
|
||||
# handles a single type (uint64), while Lox has a stack
|
||||
# of heap-allocated structs (which is convenient, but slow).
|
||||
# What we do instead is store all pointers allocated by us
|
||||
# in a hash set and then check if any source of roots contained
|
||||
# any of the integer values that we're keeping track of. Note
|
||||
# that this means that if a primitive object's value happens to
|
||||
# collide with an active pointer, the GC will mistakenly assume
|
||||
# the object to be reachable (potentially leading to a nasty
|
||||
# memory leak). Hopefully, in a 64-bit address space, this
|
||||
# occurrence is rare enough for us to ignore
|
||||
var result = initHashSet[uint64](self.gc.pointers.len())
|
||||
for obj in self.calls:
|
||||
if obj in self.gc.pointers:
|
||||
|
@ -285,7 +298,6 @@ proc sweep(self: var PeonVM) =
|
|||
## during the mark phase.
|
||||
when debugGC:
|
||||
echo "DEBUG - GC: Beginning sweeping phase"
|
||||
when debugGC:
|
||||
var count = 0
|
||||
var current: ptr HeapObject
|
||||
var freed: HashSet[uint64]
|
||||
|
@ -1050,10 +1062,11 @@ proc run*(self: var PeonVM, chunk: Chunk, breakpoints: seq[uint64] = @[], repl:
|
|||
self.frames = @[]
|
||||
self.calls = @[]
|
||||
self.operands = @[]
|
||||
self.breakpoints = breakpoints
|
||||
self.results = @[]
|
||||
self.ip = 0
|
||||
self.lastDebugCommand = ""
|
||||
when debugVM:
|
||||
self.breakpoints = breakpoints
|
||||
self.lastDebugCommand = ""
|
||||
try:
|
||||
self.dispatch()
|
||||
except NilAccessDefect:
|
||||
|
|
|
@ -124,11 +124,11 @@ type
|
|||
of Reference:
|
||||
# A managed reference
|
||||
nullable*: bool # Is null a valid value for this type? (false by default)
|
||||
value*: Type # The type the reference points to
|
||||
value*: TypedNode # The type the reference points to
|
||||
of Pointer:
|
||||
# An unmanaged reference. Much
|
||||
# like a raw pointer in C
|
||||
data*: Type # The type we point to
|
||||
data*: TypedNode # The type we point to
|
||||
of TypeDecl:
|
||||
# A user-defined type
|
||||
fields*: seq[TypedArgument] # List of fields in the object. May be empty
|
||||
|
@ -317,17 +317,17 @@ proc step*(self: Compiler): ASTNode {.inline.} =
|
|||
|
||||
# Some forward declarations
|
||||
proc compareUnions*(self: Compiler, a, b: seq[tuple[match: bool, kind: Type]]): bool
|
||||
proc expression*(self: Compiler, node: Expression, compile: bool = true): Type {.discardable.} = nil
|
||||
proc identifier*(self: Compiler, node: IdentExpr, name: Name = nil, compile: bool = true, strict: bool = true): Type {.discardable.} = nil
|
||||
proc call*(self: Compiler, node: CallExpr, compile: bool = true): Type {.discardable.} = nil
|
||||
proc getItemExpr*(self: Compiler, node: GetItemExpr, compile: bool = true, matching: Type = nil): Type {.discardable.} = nil
|
||||
proc unary*(self: Compiler, node: UnaryExpr, compile: bool = true): Type {.discardable.} = nil
|
||||
proc binary*(self: Compiler, node: BinaryExpr, compile: bool = true): Type {.discardable.} = nil
|
||||
proc lambdaExpr*(self: Compiler, node: LambdaExpr, compile: bool = true): Type {.discardable.} = nil
|
||||
proc literal*(self: Compiler, node: ASTNode, compile: bool = true): Type {.discardable.} = nil
|
||||
proc infer*(self: Compiler, node: LiteralExpr): Type
|
||||
proc infer*(self: Compiler, node: Expression): Type
|
||||
proc inferOrError*(self: Compiler, node: Expression): Type
|
||||
proc expression*(self: Compiler, node: Expression, compile: bool = true): TypedNode {.discardable.} = nil
|
||||
proc identifier*(self: Compiler, node: IdentExpr, name: Name = nil, compile: bool = true, strict: bool = true): TypedNode {.discardable.} = nil
|
||||
proc call*(self: Compiler, node: CallExpr, compile: bool = true): TypedNode {.discardable.} = nil
|
||||
proc getItemExpr*(self: Compiler, node: GetItemExpr, compile: bool = true, matching: Type = nil): TypedNode {.discardable.} = nil
|
||||
proc unary*(self: Compiler, node: UnaryExpr, compile: bool = true): TypedNode {.discardable.} = nil
|
||||
proc binary*(self: Compiler, node: BinaryExpr, compile: bool = true): TypedNode {.discardable.} = nil
|
||||
proc lambdaExpr*(self: Compiler, node: LambdaExpr, compile: bool = true): TypedNode {.discardable.} = nil
|
||||
proc literal*(self: Compiler, node: ASTNode, compile: bool = true): TypedNode {.discardable.} = nil
|
||||
proc infer*(self: Compiler, node: LiteralExpr): TypedNode
|
||||
proc infer*(self: Compiler, node: Expression): TypedNode
|
||||
proc inferOrError*(self: Compiler, node: Expression): TypedNode
|
||||
proc findByName*(self: Compiler, name: string): seq[Name]
|
||||
proc findInModule*(self: Compiler, name: string, module: Name): seq[Name]
|
||||
proc findByType*(self: Compiler, name: string, kind: Type): seq[Name]
|
||||
|
@ -420,7 +420,7 @@ proc compare*(self: Compiler, a, b: Type): bool =
|
|||
# a and b are of either of the two
|
||||
# types in this branch, so we just need
|
||||
# to compare their values
|
||||
return self.compare(a.value, b.value)
|
||||
return self.compare(a.value.value, b.value.value)
|
||||
of Function:
|
||||
# Functions are a bit trickier to compare
|
||||
if a.arguments.len() != b.arguments.len():
|
||||
|
@ -569,7 +569,7 @@ proc toIntrinsic*(name: string): Type =
|
|||
return Type(kind: String)
|
||||
|
||||
|
||||
proc infer*(self: Compiler, node: LiteralExpr): Type =
|
||||
proc infer*(self: Compiler, node: LiteralExpr): TypedNode =
|
||||
## Infers the type of a given literal expression
|
||||
if node.isNil():
|
||||
return nil
|
||||
|
@ -577,32 +577,32 @@ proc infer*(self: Compiler, node: LiteralExpr): Type =
|
|||
of intExpr, binExpr, octExpr, hexExpr:
|
||||
let size = node.token.lexeme.split("'")
|
||||
if size.len() == 1:
|
||||
return Type(kind: Int64)
|
||||
return TypedNode(node: node, value: Type(kind: Int64))
|
||||
let typ = size[1].toIntrinsic()
|
||||
if not self.compare(typ, nil):
|
||||
return typ
|
||||
return TypedNode(node: node, value: typ)
|
||||
else:
|
||||
self.error(&"invalid type specifier '{size[1]}' for int", node)
|
||||
of floatExpr:
|
||||
let size = node.token.lexeme.split("'")
|
||||
if size.len() == 1:
|
||||
return Type(kind: Float64)
|
||||
return TypedNode(node: node, value: Type(kind: Float64))
|
||||
let typ = size[1].toIntrinsic()
|
||||
if not typ.isNil():
|
||||
return typ
|
||||
return TypedNode(node: node, value: typ)
|
||||
else:
|
||||
self.error(&"invalid type specifier '{size[1]}' for float", node)
|
||||
of trueExpr:
|
||||
return Type(kind: Bool)
|
||||
return TypedNode(node: node, value: Type(kind: Bool))
|
||||
of falseExpr:
|
||||
return Type(kind: Bool)
|
||||
return TypedNode(node: node, value: Type(kind: Bool))
|
||||
of strExpr:
|
||||
return Type(kind: String)
|
||||
return TypedNode(node: node, value: Type(kind: String))
|
||||
else:
|
||||
discard # Unreachable
|
||||
|
||||
|
||||
proc infer*(self: Compiler, node: Expression): Type =
|
||||
proc infer*(self: Compiler, node: Expression): TypedNode =
|
||||
## Infers the type of a given expression and
|
||||
## returns it
|
||||
if node.isNil():
|
||||
|
@ -621,9 +621,9 @@ proc infer*(self: Compiler, node: Expression): Type =
|
|||
of NodeKind.callExpr:
|
||||
result = self.call(CallExpr(node), compile=false)
|
||||
of NodeKind.refExpr:
|
||||
result = Type(kind: Reference, value: self.infer(Ref(node).value))
|
||||
result = TypedNode(node: node, value: Type(kind: Reference, value: self.infer(Ref(node).value)))
|
||||
of NodeKind.ptrExpr:
|
||||
result = Type(kind: Pointer, data: self.infer(Ptr(node).value))
|
||||
result = TypedNode(node: node, value: Type(kind: Pointer, data: self.infer(Ptr(node).value)))
|
||||
of NodeKind.groupingExpr:
|
||||
result = self.infer(GroupingExpr(node).expression)
|
||||
of NodeKind.getItemExpr:
|
||||
|
@ -634,7 +634,7 @@ proc infer*(self: Compiler, node: Expression): Type =
|
|||
discard # TODO
|
||||
|
||||
|
||||
proc inferOrError*(self: Compiler, node: Expression): Type =
|
||||
proc inferOrError*(self: Compiler, node: Expression): TypedNode =
|
||||
## Attempts to infer the type of
|
||||
## the given expression and raises an
|
||||
## error if it fails
|
||||
|
@ -648,16 +648,16 @@ proc stringify*(self: Compiler, typ: Type): string =
|
|||
## type object
|
||||
if typ.isNil():
|
||||
return "nil"
|
||||
case typ.value.kind:
|
||||
case typ.kind:
|
||||
of Int8, UInt8, Int16, UInt16, Int32,
|
||||
UInt32, Int64, UInt64, Float32, Float64,
|
||||
Char, Byte, String, Nil, TypeKind.Nan, Bool,
|
||||
TypeKind.Inf, Auto:
|
||||
result &= ($typ.value.kind).toLowerAscii()
|
||||
result &= ($typ.kind).toLowerAscii()
|
||||
of Pointer:
|
||||
result &= &"ptr {self.stringify(typ.value)}"
|
||||
result &= &"ptr {self.stringify(typ)}"
|
||||
of Reference:
|
||||
result &= &"ref {self.stringify(typ.value)}"
|
||||
result &= &"ref {self.stringify(typ)}"
|
||||
of Any:
|
||||
return "any"
|
||||
of Union:
|
||||
|
@ -770,9 +770,9 @@ proc check*(self: Compiler, term: Expression, kind: Type) {.inline.} =
|
|||
## Raises an error if appropriate and returns
|
||||
## otherwise
|
||||
let k = self.inferOrError(term)
|
||||
if not self.compare(k, kind):
|
||||
if not self.compare(k.value, kind):
|
||||
self.error(&"expecting value of type {self.stringify(kind)}, got {self.stringify(k)}", term)
|
||||
elif k.kind == Any and kind.kind != Any:
|
||||
elif k.value.kind == Any and kind.kind != Any:
|
||||
self.error(&"any is not a valid type in this context")
|
||||
|
||||
|
||||
|
@ -857,7 +857,7 @@ proc unpackGenerics*(self: Compiler, condition: Expression, list: var seq[tuple[
|
|||
## Recursively unpacks a type constraint in a generic type
|
||||
case condition.kind:
|
||||
of identExpr:
|
||||
list.add((accept, self.inferOrError(condition)))
|
||||
list.add((accept, self.inferOrError(condition).value))
|
||||
if list[^1].kind.kind == Auto:
|
||||
self.error("automatic types cannot be used within generics", condition)
|
||||
of binaryExpr:
|
||||
|
@ -883,7 +883,7 @@ proc unpackUnion*(self: Compiler, condition: Expression, list: var seq[tuple[mat
|
|||
## Recursively unpacks a type union
|
||||
case condition.kind:
|
||||
of identExpr:
|
||||
list.add((accept, self.inferOrError(condition)))
|
||||
list.add((accept, self.inferOrError(condition).value))
|
||||
of binaryExpr:
|
||||
let condition = BinaryExpr(condition)
|
||||
case condition.operator.lexeme:
|
||||
|
@ -966,13 +966,13 @@ proc declare*(self: Compiler, node: ASTNode): Name {.discardable.} =
|
|||
n.isGeneric = true
|
||||
var typ: Type
|
||||
for argument in node.arguments:
|
||||
typ = self.infer(argument.valueType)
|
||||
typ = self.infer(argument.valueType).value
|
||||
if not typ.isNil() and typ.kind == Auto:
|
||||
n.obj.value.isAuto = true
|
||||
if n.isGeneric:
|
||||
self.error("automatic types cannot be used within generics", argument.valueType)
|
||||
break
|
||||
typ = self.infer(node.returnType)
|
||||
typ = self.infer(node.returnType).value
|
||||
if not typ.isNil() and typ.kind == Auto:
|
||||
n.obj.value.isAuto = true
|
||||
if n.isGeneric:
|
||||
|
@ -1023,7 +1023,7 @@ proc declare*(self: Compiler, node: ASTNode): Name {.discardable.} =
|
|||
else:
|
||||
case node.value.kind:
|
||||
of identExpr:
|
||||
n.obj.value = self.inferOrError(node.value)
|
||||
n.obj.value = self.inferOrError(node.value).value
|
||||
of binaryExpr:
|
||||
# Type union
|
||||
n.obj.value = Type(kind: Union, types: @[])
|
||||
|
|
Loading…
Reference in New Issue