Compare commits

...

2 Commits

Author SHA1 Message Date
Nocturn9x 8ceea4e84f Initial dummy/template work on defer 2022-02-14 17:49:15 +01:00
Nocturn9x 28c6032458 Initial work on function and class declarations 2022-02-14 17:36:17 +01:00
1 changed files with 50 additions and 12 deletions

View File

@ -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())