More work on pragmas, returning functions now works

This commit is contained in:
Mattia Giambirtone 2022-06-08 16:07:08 +02:00
parent dac0cca1bc
commit 11b15abc01
3 changed files with 69 additions and 30 deletions

View File

@ -27,7 +27,7 @@ when len(PEON_COMMIT_HASH) != 40:
const PEON_BRANCH* = "master"
when len(PEON_BRANCH) > 255:
{.fatal: "The git branch name's length must be less than or equal to 255 characters".}
const DEBUG_TRACE_VM* = false # Traces VM execution
const DEBUG_TRACE_VM* = true # Traces VM execution
const DEBUG_TRACE_GC* = false # Traces the garbage collector (TODO)
const DEBUG_TRACE_ALLOCATION* = false # Traces memory allocation/deallocation
const DEBUG_TRACE_COMPILER* = false # Traces the compiler

View File

@ -796,10 +796,10 @@ proc matchImpl(self: Compiler, name: string, kind: Type): Name =
return impl[0]
proc emitFunction(self: Compiler, node: Name) =
proc emitFunction(self: Compiler, name: Name) =
## Wrapper to emit LoadFunction instructions
self.emitByte(LoadFunction)
self.emitBytes((node.codePos + 4).toTriple())
self.emitBytes((name.codePos + 4).toTriple())
proc generateCall(self: Compiler, fn: Name, args: seq[Expression]) =
@ -994,6 +994,9 @@ proc identifier(self: Compiler, node: IdentExpr) =
# no matter the scope depth
self.emitConstant(node, self.inferType(node))
else:
if s.valueType.kind == Function:
self.emitByte(LoadFunction)
self.emitBytes(s.codePos.toTriple())
self.detectClosureVariable(s)
if not s.isClosedOver:
# Static name resolution, loads value at index in the stack. Very fast. Much wow.
@ -1006,6 +1009,8 @@ proc identifier(self: Compiler, node: IdentExpr) =
# not much slower than indexing our stack (since they're both dynamic arrays at runtime anyway)
self.emitByte(LoadClosure)
self.emitBytes(self.closedOver.high().toTriple())
if s.valueType.kind == Function:
self.emitByte(PopC)
proc assignment(self: Compiler, node: ASTNode) =
@ -1164,7 +1169,41 @@ proc whileStmt(self: Compiler, node: WhileStmt) =
self.emitLoop(start)
proc callExpr(self: Compiler, node: CallExpr) =
proc isPure(self: Compiler, node: ASTNode): bool =
## Checks if a function has any side effects
var pragmas: seq[Pragma]
case node.kind:
of lambdaExpr:
pragmas = LambdaExpr(node).pragmas
else:
pragmas = Declaration(node).pragmas
if pragmas.len() == 0:
return false
for pragma in pragmas:
if pragma.name.name.lexeme == "pure":
return true
return false
proc checkCallIsPure(self: Compiler, node: ASTnode): bool =
## Checks if a call has any side effects
if not self.isPure(node):
return true
var pragmas: seq[Pragma]
case node.kind:
of lambdaExpr:
pragmas = LambdaExpr(node).pragmas
else:
pragmas = Declaration(node).pragmas
if pragmas.len() == 0:
return false
for pragma in pragmas:
if pragma.name.name.lexeme == "pure":
return true
return false
proc callExpr(self: Compiler, node: CallExpr): Name =
## Compiles code to call a function
var args: seq[tuple[name: string, kind: Type]] = @[]
var argExpr: seq[Expression] = @[]
@ -1186,16 +1225,29 @@ proc callExpr(self: Compiler, node: CallExpr) =
case node.callee.kind:
of identExpr:
funct = self.matchImpl(IdentExpr(node.callee).name.lexeme, Type(kind: Function, returnType: Type(kind: Any), args: args))
of NodeKind.callExpr:
var node = node.callee
while node.kind == callExpr:
funct = self.callExpr(CallExpr(node))
node = CallExpr(node).callee
# funct = self.matchImpl(IdentExpr(node.callee).name.lexeme, Type(kind: Function, returnType: Type(kind: Any), args: args))
else:
discard # TODO: Lambdas
self.generateCall(funct, argExpr)
if self.scopeDepth > 0 and not self.checkCallIsPure(node.callee):
if not self.currentFunction.name.isNil():
self.error(&"cannot make sure that calls to '{self.currentFunction.name.token.lexeme}' are side-effect free")
else:
self.error(&"cannot make sure that call is side-effect free")
result = funct
proc expression(self: Compiler, node: Expression) =
## Compiles all expressions
case node.kind:
of NodeKind.callExpr:
self.callExpr(CallExpr(node)) # TODO
discard self.callExpr(CallExpr(node)) # TODO
of getItemExpr:
discard # TODO: Get rid of this
of pragmaExpr:

View File

@ -1047,7 +1047,7 @@ proc statement(self: Parser): Statement =
# TODO
# from module import a [, b, c as d]
discard self.step()
result = self.importStmt(fromStmt = true)
result = self.importStmt(fromStmt=true)
of While:
discard self.step()
result = self.whileStmt()
@ -1076,38 +1076,29 @@ proc statement(self: Parser): Statement =
result = self.expressionStatement()
proc parsePragma(self: Parser): tuple[global: bool, pragmas: seq[Pragma]] =
proc parsePragmas(self: Parser): seq[Pragma] =
## Parses pragmas
result.global = true
var
decl: Declaration = nil
found = false
for node in self.tree:
if node.token.line == self.peek(-1).line and node.kind in {NodeKind.varDecl, typeDecl, funDecl, lambdaExpr}:
decl = node
found = true
break
if not found:
# Dummy declaration
result.global = false
decl = Declaration(pragmas: @[])
var
name: IdentExpr
args: seq[LiteralExpr]
exp: Expression
names: seq[string]
while not self.match("]") and not self.done():
args = @[]
self.expect(Identifier, "expecting pragma name")
if self.peek(-1).lexeme in names:
self.error("duplicate pragmas are not allowed")
names.add(self.peek(-1).lexeme)
name = newIdentExpr(self.peek(-1))
if not self.match(":"):
if self.match("]"):
decl.pragmas.add(newPragma(name, @[]))
result.add(newPragma(name, @[]))
break
elif self.match("("):
while not self.match(")") and not self.done():
exp = self.primary()
if not exp.isLiteral():
self.error("invalid syntax")
self.error("pragma arguments can only be literals")
args.add(LiteralExpr(exp))
if not self.match(","):
break
@ -1115,12 +1106,11 @@ proc parsePragma(self: Parser): tuple[global: bool, pragmas: seq[Pragma]] =
else:
exp = self.primary()
if not exp.isLiteral():
self.error("invalid syntax")
self.error("pragma arguments can only be literals")
args.add(LiteralExpr(exp))
if self.match(","):
continue
decl.pragmas.add(newPragma(name, args))
result.pragmas = decl.pragmas
result.add(newPragma(name, args))
proc typeDecl(self: Parser): TypeDecl =
@ -1202,11 +1192,8 @@ proc declaration(self: Parser): Declaration =
result = self.funDecl(isOperator=true)
of TokenType.Pragma:
discard self.step()
let temp = self.parsePragma()
if not temp.global:
for p in temp.pragmas:
self.tree.add(p)
result = nil
for p in self.parsePragmas():
self.tree.add(p)
of Type:
discard self.step()
result = self.typeDecl()