Compare commits
2 Commits
65053b7a05
...
8ceea4e84f
Author | SHA1 | Date |
---|---|---|
Nocturn9x | 8ceea4e84f | |
Nocturn9x | 28c6032458 |
|
@ -65,6 +65,7 @@ type
|
|||
currentFunction: FunDecl
|
||||
enableOptimizations*: bool
|
||||
currentLoop: Loop
|
||||
currentModule: string
|
||||
# Each time a defer statement is
|
||||
# compiled, its code is emitted
|
||||
# here. Later, if there is any code
|
||||
|
@ -90,7 +91,7 @@ proc initCompiler*(enableOptimizations: bool = true): Compiler =
|
|||
result.scopeDepth = 0
|
||||
result.currentFunction = nil
|
||||
result.enableOptimizations = enableOptimizations
|
||||
|
||||
result.currentModule = ""
|
||||
|
||||
|
||||
## Forward declarations
|
||||
|
@ -483,8 +484,8 @@ proc resolveStatic(self: Compiler, name: IdentExpr,
|
|||
|
||||
proc deleteStatic(self: Compiler, name: IdentExpr,
|
||||
depth: int = self.scopeDepth) =
|
||||
## Traverses self.staticNames backwards and returns the
|
||||
## deletes name object with the given name at the given
|
||||
## Traverses self.staticNames backwards and deletes the
|
||||
## a name object with the given name at the given
|
||||
## depth. The default depth is the current one. Does
|
||||
## nothing when the name can't be found
|
||||
for i, obj in reversed(self.names):
|
||||
|
@ -516,10 +517,10 @@ proc identifier(self: Compiler, node: IdentExpr) =
|
|||
else:
|
||||
let index = self.getStaticIndex(node)
|
||||
if index != -1:
|
||||
self.emitByte(LoadFast) # Static name resolution, loads value at index in the stack
|
||||
self.emitByte(LoadFast) # Static name resolution, loads value at index in the stack. Very fast. Much wow.
|
||||
self.emitBytes(index.toTriple())
|
||||
else:
|
||||
self.emitByte(LoadName) # Resolves by name, at runtime, in a global hashmap
|
||||
self.emitByte(LoadName) # Resolves by name, at runtime, in a global hashmap. Slower
|
||||
self.emitBytes(self.identifierConstant(node))
|
||||
|
||||
|
||||
|
@ -532,7 +533,6 @@ proc assignment(self: Compiler, node: ASTNode) =
|
|||
let r = self.resolveStatic(name)
|
||||
if r != nil and r.isConst:
|
||||
self.error("cannot assign to constant")
|
||||
|
||||
self.expression(node.value)
|
||||
let index = self.getStaticIndex(name)
|
||||
case node.token.kind:
|
||||
|
@ -568,12 +568,12 @@ proc assignment(self: Compiler, node: ASTNode) =
|
|||
# TODO: A better optimization would
|
||||
# be to have everything in one opcode,
|
||||
# but that requires variants for stack,
|
||||
# heap, and closure variables
|
||||
# heap, and closure variables and I cba
|
||||
if index != -1:
|
||||
self.emitByte(StoreFast)
|
||||
self.emitBytes(index.toTriple())
|
||||
else:
|
||||
# Assignment only encompasses variable assignments
|
||||
# Assignment only encompasses variable assignments,
|
||||
# so we can ensure the name is a constant (i.e. an
|
||||
# IdentExpr) instead of an object (which would be
|
||||
# the case with setItemExpr)
|
||||
|
@ -692,7 +692,7 @@ proc expression(self: Compiler, node: ASTNode) =
|
|||
## Compiles all expressions
|
||||
case node.kind:
|
||||
of getItemExpr:
|
||||
discard
|
||||
discard # TODO
|
||||
# Note that for setItem and assign we don't convert
|
||||
# the node to its true type because that type information
|
||||
# would be lost in the call anyway. The differentiation
|
||||
|
@ -832,7 +832,7 @@ proc statement(self: Compiler, node: ASTNode) =
|
|||
case node.kind:
|
||||
of exprStmt:
|
||||
self.expression(ExprStmt(node).expression)
|
||||
self.emitByte(Pop) # Expression statements discard their value. Their main use case is side effects in function calls
|
||||
self.emitByte(Pop) # Expression statements discard their value. Their main use case is side effects in function calls
|
||||
of NodeKind.ifStmt:
|
||||
self.ifStmt(IfStmt(node))
|
||||
of NodeKind.delStmt:
|
||||
|
@ -876,13 +876,50 @@ proc statement(self: Compiler, node: ASTNode) =
|
|||
self.expression(node)
|
||||
|
||||
|
||||
proc funDecl(self: Compiler, node: FunDecl) =
|
||||
## Compiles function declarations
|
||||
self.declareName(node.name)
|
||||
# Since the deferred array is a linear
|
||||
# sequence of instructions and we want
|
||||
# to keep track to whose function's each
|
||||
# set of deferred instruction belongs,
|
||||
# we record the length of the deferred
|
||||
# array before compiling the function
|
||||
# and use this info later to compile
|
||||
# the try/finally block with the deferred
|
||||
# code
|
||||
var deferStart = self.deferred.len()
|
||||
self.blockStmt(BlockStmt(node.body))
|
||||
# Yup, we're done. That was easy, huh?
|
||||
# But after all functions are just named
|
||||
# scopes, and we compile them just like that:
|
||||
# we declare their name (before compiling them
|
||||
# so recursion & co. works) and then just compile
|
||||
# their body as a block statement (which takes
|
||||
# care of incrementing self.scopeDepth so locals
|
||||
# are resolved properly). Yay!
|
||||
|
||||
# Currently defer is not functional so we
|
||||
# just pop the instructions
|
||||
for i in countup(deferStart, self.deferred.len(), 1):
|
||||
self.deferred.delete(i)
|
||||
|
||||
|
||||
proc classDecl(self: Compiler, node: ClassDecl) =
|
||||
## Compiles class declarations
|
||||
self.declareName(node.name)
|
||||
self.blockStmt(BlockStmt(node.body))
|
||||
|
||||
|
||||
proc declaration(self: Compiler, node: ASTNode) =
|
||||
## Compiles all declarations
|
||||
case node.kind:
|
||||
of NodeKind.varDecl:
|
||||
self.varDecl(VarDecl(node))
|
||||
of funDecl, classDecl:
|
||||
discard # TODO
|
||||
of NodeKind.funDecl:
|
||||
self.funDecl(FunDecl(node))
|
||||
of NodeKind.classDecl:
|
||||
self.classDecl(ClassDecl(node))
|
||||
else:
|
||||
self.statement(node)
|
||||
|
||||
|
@ -896,6 +933,7 @@ proc compile*(self: Compiler, ast: seq[ASTNode], file: string): Chunk =
|
|||
self.names = @[]
|
||||
self.scopeDepth = 0
|
||||
self.currentFunction = nil
|
||||
self.currentModule = "<main>"
|
||||
self.current = 0
|
||||
while not self.done():
|
||||
self.declaration(self.step())
|
||||
|
|
Loading…
Reference in New Issue