More work on pragmas, returning functions now works
This commit is contained in:
parent
dac0cca1bc
commit
11b15abc01
|
@ -27,7 +27,7 @@ when len(PEON_COMMIT_HASH) != 40:
|
||||||
const PEON_BRANCH* = "master"
|
const PEON_BRANCH* = "master"
|
||||||
when len(PEON_BRANCH) > 255:
|
when len(PEON_BRANCH) > 255:
|
||||||
{.fatal: "The git branch name's length must be less than or equal to 255 characters".}
|
{.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_GC* = false # Traces the garbage collector (TODO)
|
||||||
const DEBUG_TRACE_ALLOCATION* = false # Traces memory allocation/deallocation
|
const DEBUG_TRACE_ALLOCATION* = false # Traces memory allocation/deallocation
|
||||||
const DEBUG_TRACE_COMPILER* = false # Traces the compiler
|
const DEBUG_TRACE_COMPILER* = false # Traces the compiler
|
||||||
|
|
|
@ -796,10 +796,10 @@ proc matchImpl(self: Compiler, name: string, kind: Type): Name =
|
||||||
return impl[0]
|
return impl[0]
|
||||||
|
|
||||||
|
|
||||||
proc emitFunction(self: Compiler, node: Name) =
|
proc emitFunction(self: Compiler, name: Name) =
|
||||||
## Wrapper to emit LoadFunction instructions
|
## Wrapper to emit LoadFunction instructions
|
||||||
self.emitByte(LoadFunction)
|
self.emitByte(LoadFunction)
|
||||||
self.emitBytes((node.codePos + 4).toTriple())
|
self.emitBytes((name.codePos + 4).toTriple())
|
||||||
|
|
||||||
|
|
||||||
proc generateCall(self: Compiler, fn: Name, args: seq[Expression]) =
|
proc generateCall(self: Compiler, fn: Name, args: seq[Expression]) =
|
||||||
|
@ -994,6 +994,9 @@ proc identifier(self: Compiler, node: IdentExpr) =
|
||||||
# no matter the scope depth
|
# no matter the scope depth
|
||||||
self.emitConstant(node, self.inferType(node))
|
self.emitConstant(node, self.inferType(node))
|
||||||
else:
|
else:
|
||||||
|
if s.valueType.kind == Function:
|
||||||
|
self.emitByte(LoadFunction)
|
||||||
|
self.emitBytes(s.codePos.toTriple())
|
||||||
self.detectClosureVariable(s)
|
self.detectClosureVariable(s)
|
||||||
if not s.isClosedOver:
|
if not s.isClosedOver:
|
||||||
# Static name resolution, loads value at index in the stack. Very fast. Much wow.
|
# 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)
|
# not much slower than indexing our stack (since they're both dynamic arrays at runtime anyway)
|
||||||
self.emitByte(LoadClosure)
|
self.emitByte(LoadClosure)
|
||||||
self.emitBytes(self.closedOver.high().toTriple())
|
self.emitBytes(self.closedOver.high().toTriple())
|
||||||
|
if s.valueType.kind == Function:
|
||||||
|
self.emitByte(PopC)
|
||||||
|
|
||||||
|
|
||||||
proc assignment(self: Compiler, node: ASTNode) =
|
proc assignment(self: Compiler, node: ASTNode) =
|
||||||
|
@ -1164,7 +1169,41 @@ proc whileStmt(self: Compiler, node: WhileStmt) =
|
||||||
self.emitLoop(start)
|
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
|
## Compiles code to call a function
|
||||||
var args: seq[tuple[name: string, kind: Type]] = @[]
|
var args: seq[tuple[name: string, kind: Type]] = @[]
|
||||||
var argExpr: seq[Expression] = @[]
|
var argExpr: seq[Expression] = @[]
|
||||||
|
@ -1186,16 +1225,29 @@ proc callExpr(self: Compiler, node: CallExpr) =
|
||||||
case node.callee.kind:
|
case node.callee.kind:
|
||||||
of identExpr:
|
of identExpr:
|
||||||
funct = self.matchImpl(IdentExpr(node.callee).name.lexeme, Type(kind: Function, returnType: Type(kind: Any), args: args))
|
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:
|
else:
|
||||||
discard # TODO: Lambdas
|
discard # TODO: Lambdas
|
||||||
self.generateCall(funct, argExpr)
|
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) =
|
proc expression(self: Compiler, node: Expression) =
|
||||||
## Compiles all expressions
|
## Compiles all expressions
|
||||||
case node.kind:
|
case node.kind:
|
||||||
of NodeKind.callExpr:
|
of NodeKind.callExpr:
|
||||||
self.callExpr(CallExpr(node)) # TODO
|
discard self.callExpr(CallExpr(node)) # TODO
|
||||||
of getItemExpr:
|
of getItemExpr:
|
||||||
discard # TODO: Get rid of this
|
discard # TODO: Get rid of this
|
||||||
of pragmaExpr:
|
of pragmaExpr:
|
||||||
|
|
|
@ -1047,7 +1047,7 @@ proc statement(self: Parser): Statement =
|
||||||
# TODO
|
# TODO
|
||||||
# from module import a [, b, c as d]
|
# from module import a [, b, c as d]
|
||||||
discard self.step()
|
discard self.step()
|
||||||
result = self.importStmt(fromStmt = true)
|
result = self.importStmt(fromStmt=true)
|
||||||
of While:
|
of While:
|
||||||
discard self.step()
|
discard self.step()
|
||||||
result = self.whileStmt()
|
result = self.whileStmt()
|
||||||
|
@ -1076,38 +1076,29 @@ proc statement(self: Parser): Statement =
|
||||||
result = self.expressionStatement()
|
result = self.expressionStatement()
|
||||||
|
|
||||||
|
|
||||||
proc parsePragma(self: Parser): tuple[global: bool, pragmas: seq[Pragma]] =
|
proc parsePragmas(self: Parser): seq[Pragma] =
|
||||||
## Parses pragmas
|
## 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
|
var
|
||||||
name: IdentExpr
|
name: IdentExpr
|
||||||
args: seq[LiteralExpr]
|
args: seq[LiteralExpr]
|
||||||
exp: Expression
|
exp: Expression
|
||||||
|
names: seq[string]
|
||||||
while not self.match("]") and not self.done():
|
while not self.match("]") and not self.done():
|
||||||
args = @[]
|
args = @[]
|
||||||
self.expect(Identifier, "expecting pragma name")
|
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))
|
name = newIdentExpr(self.peek(-1))
|
||||||
if not self.match(":"):
|
if not self.match(":"):
|
||||||
if self.match("]"):
|
if self.match("]"):
|
||||||
decl.pragmas.add(newPragma(name, @[]))
|
result.add(newPragma(name, @[]))
|
||||||
break
|
break
|
||||||
elif self.match("("):
|
elif self.match("("):
|
||||||
while not self.match(")") and not self.done():
|
while not self.match(")") and not self.done():
|
||||||
exp = self.primary()
|
exp = self.primary()
|
||||||
if not exp.isLiteral():
|
if not exp.isLiteral():
|
||||||
self.error("invalid syntax")
|
self.error("pragma arguments can only be literals")
|
||||||
args.add(LiteralExpr(exp))
|
args.add(LiteralExpr(exp))
|
||||||
if not self.match(","):
|
if not self.match(","):
|
||||||
break
|
break
|
||||||
|
@ -1115,12 +1106,11 @@ proc parsePragma(self: Parser): tuple[global: bool, pragmas: seq[Pragma]] =
|
||||||
else:
|
else:
|
||||||
exp = self.primary()
|
exp = self.primary()
|
||||||
if not exp.isLiteral():
|
if not exp.isLiteral():
|
||||||
self.error("invalid syntax")
|
self.error("pragma arguments can only be literals")
|
||||||
args.add(LiteralExpr(exp))
|
args.add(LiteralExpr(exp))
|
||||||
if self.match(","):
|
if self.match(","):
|
||||||
continue
|
continue
|
||||||
decl.pragmas.add(newPragma(name, args))
|
result.add(newPragma(name, args))
|
||||||
result.pragmas = decl.pragmas
|
|
||||||
|
|
||||||
|
|
||||||
proc typeDecl(self: Parser): TypeDecl =
|
proc typeDecl(self: Parser): TypeDecl =
|
||||||
|
@ -1202,11 +1192,8 @@ proc declaration(self: Parser): Declaration =
|
||||||
result = self.funDecl(isOperator=true)
|
result = self.funDecl(isOperator=true)
|
||||||
of TokenType.Pragma:
|
of TokenType.Pragma:
|
||||||
discard self.step()
|
discard self.step()
|
||||||
let temp = self.parsePragma()
|
for p in self.parsePragmas():
|
||||||
if not temp.global:
|
self.tree.add(p)
|
||||||
for p in temp.pragmas:
|
|
||||||
self.tree.add(p)
|
|
||||||
result = nil
|
|
||||||
of Type:
|
of Type:
|
||||||
discard self.step()
|
discard self.step()
|
||||||
result = self.typeDecl()
|
result = self.typeDecl()
|
||||||
|
|
Loading…
Reference in New Issue