split up expression.nim
This commit is contained in:
parent
960be5f0dd
commit
d4a6921302
|
@ -0,0 +1,76 @@
|
||||||
|
import strformat
|
||||||
|
import strutils
|
||||||
|
import bitops # needed for value
|
||||||
|
|
||||||
|
import ../scanner
|
||||||
|
import ../chunk
|
||||||
|
import ../types/value
|
||||||
|
import ../config
|
||||||
|
|
||||||
|
# the following order of imports here is important
|
||||||
|
# it defines the allowed dependency precedence between the compiler files
|
||||||
|
import types
|
||||||
|
import utils
|
||||||
|
import precedence
|
||||||
|
import jumps
|
||||||
|
import scope
|
||||||
|
|
||||||
|
# lists
|
||||||
|
|
||||||
|
proc parseList(comp: Compiler) =
|
||||||
|
var count: int
|
||||||
|
while comp.current.tokenType != tkRightBracket:
|
||||||
|
comp.expression()
|
||||||
|
count.inc()
|
||||||
|
if comp.current.tokenType != tkRightBracket:
|
||||||
|
comp.consume(tkComma, "Comma expected after list member.")
|
||||||
|
comp.consume(tkRightBracket, "Right bracket expected after list members.")
|
||||||
|
if count > argMax:
|
||||||
|
comp.error("Maximum list length exceeded.")
|
||||||
|
comp.writeChunk(1 - count, opCreateList)
|
||||||
|
comp.writeChunk(0, count.toDU8())
|
||||||
|
|
||||||
|
|
||||||
|
tkStartList.genRule(parseList, nop, pcNone)
|
||||||
|
|
||||||
|
# tables
|
||||||
|
|
||||||
|
proc parseTable(comp: Compiler) =
|
||||||
|
var count: int
|
||||||
|
while comp.current.tokenType != tkRightBrace:
|
||||||
|
comp.expression()
|
||||||
|
comp.consume(tkEqual, "Equal sign expected after key.")
|
||||||
|
comp.expression()
|
||||||
|
count.inc()
|
||||||
|
if comp.current.tokenType != tkRightBrace:
|
||||||
|
comp.consume(tkComma, "Comma expected after key-value pair.")
|
||||||
|
|
||||||
|
comp.consume(tkRightBrace, "Right brace expected after table members.")
|
||||||
|
if count > argMax:
|
||||||
|
comp.error("Maximum table length exceeded.")
|
||||||
|
comp.writeChunk(1 - 2 * count, opCreateTable)
|
||||||
|
comp.writeChunk(0, count.toDU8())
|
||||||
|
|
||||||
|
tkStartTable.genRule(parseTable, nop, pcNone)
|
||||||
|
|
||||||
|
# len op
|
||||||
|
|
||||||
|
proc parseLen(comp: Compiler) =
|
||||||
|
comp.expression()
|
||||||
|
comp.writeChunk(0, opLen)
|
||||||
|
|
||||||
|
tkHashtag.genRule(parseLen, nop, pcNone)
|
||||||
|
|
||||||
|
# get/set index
|
||||||
|
|
||||||
|
proc parseIndex(comp: Compiler) =
|
||||||
|
# the index
|
||||||
|
comp.expression()
|
||||||
|
comp.consume(tkRightBracket, "Right bracket expected after index.")
|
||||||
|
if comp.match(tkEqual):
|
||||||
|
comp.parsePrecedence(pcNonAssignTop)
|
||||||
|
comp.writeChunk(-2, opSetIndex)
|
||||||
|
else:
|
||||||
|
comp.writeChunk(-1, opGetIndex)
|
||||||
|
|
||||||
|
tkLeftBracket.genRule(nop, parseIndex, pcIndex)
|
|
@ -2,17 +2,15 @@ import ../scanner
|
||||||
import ../chunk
|
import ../chunk
|
||||||
import ../config
|
import ../config
|
||||||
|
|
||||||
# the following order of imports here is important
|
|
||||||
# it defines the allowed dependency precedence between the compiler files
|
|
||||||
import types
|
import types
|
||||||
import utils
|
import utils
|
||||||
#import precedence
|
|
||||||
#import jumps
|
|
||||||
#import scope
|
|
||||||
#import variables
|
|
||||||
#import expressions
|
|
||||||
import statement
|
|
||||||
|
|
||||||
|
# the following modify precedence by being imported
|
||||||
|
import expressions
|
||||||
|
import controlflow
|
||||||
|
import collections
|
||||||
|
import functions
|
||||||
|
import statement
|
||||||
|
|
||||||
proc compile*(comp: Compiler) =
|
proc compile*(comp: Compiler) =
|
||||||
comp.scanner = newScanner(comp.source)
|
comp.scanner = newScanner(comp.source)
|
||||||
|
|
|
@ -0,0 +1,92 @@
|
||||||
|
import strformat
|
||||||
|
import strutils
|
||||||
|
import bitops # needed for value
|
||||||
|
|
||||||
|
import ../scanner
|
||||||
|
import ../chunk
|
||||||
|
import ../types/value
|
||||||
|
import ../config
|
||||||
|
|
||||||
|
# the following order of imports here is important
|
||||||
|
# it defines the allowed dependency precedence between the compiler files
|
||||||
|
import types
|
||||||
|
import utils
|
||||||
|
import precedence
|
||||||
|
import jumps
|
||||||
|
import scope
|
||||||
|
|
||||||
|
proc ifExpr(comp: Compiler) =
|
||||||
|
# if expressions return the body if condition is truthy,
|
||||||
|
# the else expression otherwise, unless there is no else:
|
||||||
|
# if there is no else, it returns the condition if it is falsey
|
||||||
|
comp.consume(tkLeftParen, "Expect '(' after 'if'.")
|
||||||
|
comp.expression()
|
||||||
|
comp.consume(tkRightParen, "Expect ')' after condition.")
|
||||||
|
|
||||||
|
let thenJump = comp.emitJump(0, opJumpIfFalse)
|
||||||
|
|
||||||
|
# conditional code that can be jumped over must leave the stack in tact!
|
||||||
|
|
||||||
|
comp.writeChunk(-1, opPop)
|
||||||
|
comp.expression()
|
||||||
|
# net change to stack: -1 + 1 = 0
|
||||||
|
|
||||||
|
let elseJump = comp.emitJump(0, opJump)
|
||||||
|
comp.patchJump(thenJump)
|
||||||
|
|
||||||
|
if comp.match(tkElse):
|
||||||
|
comp.writeChunk(-1, opPop)
|
||||||
|
comp.expression()
|
||||||
|
|
||||||
|
comp.patchJump(elseJump)
|
||||||
|
|
||||||
|
|
||||||
|
tkIf.genRule(ifExpr, nop, pcNone)
|
||||||
|
|
||||||
|
proc andExpr(comp: Compiler) =
|
||||||
|
let endJump = comp.emitJump(0, opJumpIfFalse)
|
||||||
|
|
||||||
|
comp.writeChunk(-1, opPop)
|
||||||
|
comp.parsePrecedence(pcAnd)
|
||||||
|
# net effect on stack: -1 + 1 = 0
|
||||||
|
|
||||||
|
comp.patchJump(endJump)
|
||||||
|
|
||||||
|
tkAnd.genRule(nop, andExpr, pcAnd)
|
||||||
|
|
||||||
|
proc orExpr(comp: Compiler) =
|
||||||
|
let elseJump = comp.emitJump(0, opJumpIfFalse)
|
||||||
|
let endJump = comp.emitJump(0, opJump)
|
||||||
|
|
||||||
|
comp.patchJump(elseJump)
|
||||||
|
|
||||||
|
comp.writeChunk(-1, opPop)
|
||||||
|
comp.parsePrecedence(pcOr)
|
||||||
|
# net effect on stack: -1 + 1 = 0
|
||||||
|
|
||||||
|
comp.patchJump(endJump)
|
||||||
|
|
||||||
|
tkOr.genRule(nop, orExpr, pcOr)
|
||||||
|
|
||||||
|
proc parseWhile(comp: Compiler) =
|
||||||
|
|
||||||
|
comp.writeChunk(1, opNil) # return value
|
||||||
|
let loopStart = comp.chunk.len
|
||||||
|
comp.consume(tkLeftParen, "Expect '(' after 'while'.")
|
||||||
|
# condition
|
||||||
|
comp.expression()
|
||||||
|
comp.consume(tkRightParen, "Expect ')' after condition.")
|
||||||
|
|
||||||
|
let exitJump = comp.emitJump(-1, opJumpIfFalsePop)
|
||||||
|
# this cannot be handled with just opPop, since the net change in the
|
||||||
|
# stack size inside code that is conditional must be 0!
|
||||||
|
|
||||||
|
# body
|
||||||
|
comp.writeChunk(-1, opPop) # pop the old return value
|
||||||
|
comp.expression()
|
||||||
|
# net stack change: 1 + -1 = 0
|
||||||
|
|
||||||
|
comp.emitLoop(loopstart = loopStart, delta = 0, op = opLoop)
|
||||||
|
comp.patchJump(exitJump)
|
||||||
|
|
||||||
|
tkWhile.genRule(parseWhile, nop, pcNone)
|
|
@ -16,8 +16,6 @@ import utils
|
||||||
import precedence
|
import precedence
|
||||||
import jumps
|
import jumps
|
||||||
import scope
|
import scope
|
||||||
import variables
|
|
||||||
|
|
||||||
|
|
||||||
# EXPRESSIONS
|
# EXPRESSIONS
|
||||||
|
|
||||||
|
@ -53,35 +51,6 @@ proc expString(comp: Compiler) =
|
||||||
|
|
||||||
tkString.genRule(expString, nop, pcNone)
|
tkString.genRule(expString, nop, pcNone)
|
||||||
|
|
||||||
proc grouping(comp: Compiler) =
|
|
||||||
# assume initial '(' is already consumed
|
|
||||||
comp.expression()
|
|
||||||
comp.consume(tkRightParen, "Expect ')' after expression.")
|
|
||||||
|
|
||||||
proc parseCall(comp: Compiler) =
|
|
||||||
# ( consumed
|
|
||||||
|
|
||||||
# create the call env
|
|
||||||
# current stack before opCall:
|
|
||||||
# ... <funct obj> <arg1> <arg2> <arg3>
|
|
||||||
# opCall converts it to this
|
|
||||||
# ... <ret val> <arg1> <arg2> <arg3>
|
|
||||||
|
|
||||||
var argcount = 0
|
|
||||||
# put args on stack
|
|
||||||
while comp.current.tokenType notin {tkRightParen, tkEof}:
|
|
||||||
comp.expression()
|
|
||||||
inc argcount
|
|
||||||
if comp.current.tokenType != tkRightParen:
|
|
||||||
comp.consume(tkComma, "Expected ',' between arguments in function calls.")
|
|
||||||
comp.consume(tkRightParen, "Expected ')' after arguments in function calls.")
|
|
||||||
|
|
||||||
# emit call
|
|
||||||
comp.writeChunk(-argcount, opCall)
|
|
||||||
comp.writeChunk(0, argcount.uint8)
|
|
||||||
|
|
||||||
tkLeftParen.genRule(grouping, parseCall, pcCall)
|
|
||||||
|
|
||||||
proc unary(comp: Compiler) =
|
proc unary(comp: Compiler) =
|
||||||
let opType = comp.previous.tokenType
|
let opType = comp.previous.tokenType
|
||||||
|
|
||||||
|
@ -142,201 +111,6 @@ tkGreaterEqual.genRule(nop, binary, pcComparison)
|
||||||
tkLess.genRule(nop, binary, pcComparison)
|
tkLess.genRule(nop, binary, pcComparison)
|
||||||
tkLessEqual.genRule(nop, binary, pcComparison)
|
tkLessEqual.genRule(nop, binary, pcComparison)
|
||||||
|
|
||||||
proc ifExpr(comp: Compiler) =
|
|
||||||
# if expressions return the body if condition is truthy,
|
|
||||||
# the else expression otherwise, unless there is no else:
|
|
||||||
# if there is no else, it returns the condition if it is falsey
|
|
||||||
comp.consume(tkLeftParen, "Expect '(' after 'if'.")
|
|
||||||
comp.expression()
|
|
||||||
comp.consume(tkRightParen, "Expect ')' after condition.")
|
|
||||||
|
|
||||||
let thenJump = comp.emitJump(0, opJumpIfFalse)
|
|
||||||
|
|
||||||
# conditional code that can be jumped over must leave the stack in tact!
|
|
||||||
|
|
||||||
comp.writeChunk(-1, opPop)
|
|
||||||
comp.expression()
|
|
||||||
# net change to stack: -1 + 1 = 0
|
|
||||||
|
|
||||||
let elseJump = comp.emitJump(0, opJump)
|
|
||||||
comp.patchJump(thenJump)
|
|
||||||
|
|
||||||
if comp.match(tkElse):
|
|
||||||
comp.writeChunk(-1, opPop)
|
|
||||||
comp.expression()
|
|
||||||
|
|
||||||
comp.patchJump(elseJump)
|
|
||||||
|
|
||||||
|
|
||||||
tkIf.genRule(ifExpr, nop, pcNone)
|
|
||||||
|
|
||||||
proc andExpr(comp: Compiler) =
|
|
||||||
let endJump = comp.emitJump(0, opJumpIfFalse)
|
|
||||||
|
|
||||||
comp.writeChunk(-1, opPop)
|
|
||||||
comp.parsePrecedence(pcAnd)
|
|
||||||
# net effect on stack: -1 + 1 = 0
|
|
||||||
|
|
||||||
comp.patchJump(endJump)
|
|
||||||
|
|
||||||
tkAnd.genRule(nop, andExpr, pcAnd)
|
|
||||||
|
|
||||||
proc orExpr(comp: Compiler) =
|
|
||||||
let elseJump = comp.emitJump(0, opJumpIfFalse)
|
|
||||||
let endJump = comp.emitJump(0, opJump)
|
|
||||||
|
|
||||||
comp.patchJump(elseJump)
|
|
||||||
|
|
||||||
comp.writeChunk(-1, opPop)
|
|
||||||
comp.parsePrecedence(pcOr)
|
|
||||||
# net effect on stack: -1 + 1 = 0
|
|
||||||
|
|
||||||
comp.patchJump(endJump)
|
|
||||||
|
|
||||||
tkOr.genRule(nop, orExpr, pcOr)
|
|
||||||
|
|
||||||
proc parseWhile(comp: Compiler) =
|
|
||||||
|
|
||||||
comp.writeChunk(1, opNil) # return value
|
|
||||||
let loopStart = comp.chunk.len
|
|
||||||
comp.consume(tkLeftParen, "Expect '(' after 'while'.")
|
|
||||||
# condition
|
|
||||||
comp.expression()
|
|
||||||
comp.consume(tkRightParen, "Expect ')' after condition.")
|
|
||||||
|
|
||||||
let exitJump = comp.emitJump(-1, opJumpIfFalsePop)
|
|
||||||
# this cannot be handled with just opPop, since the net change in the
|
|
||||||
# stack size inside code that is conditional must be 0!
|
|
||||||
|
|
||||||
# body
|
|
||||||
comp.writeChunk(-1, opPop) # pop the old return value
|
|
||||||
comp.expression()
|
|
||||||
# net stack change: 1 + -1 = 0
|
|
||||||
|
|
||||||
comp.emitLoop(loopstart = loopStart, delta = 0, op = opLoop)
|
|
||||||
comp.patchJump(exitJump)
|
|
||||||
|
|
||||||
|
|
||||||
tkWhile.genRule(parseWhile, nop, pcNone)
|
|
||||||
|
|
||||||
proc parseFunct(comp: Compiler) =
|
|
||||||
|
|
||||||
# jump over
|
|
||||||
let jumpOverBody = comp.emitJump(1, opFunctionDef)
|
|
||||||
|
|
||||||
comp.consume(tkLeftParen, "Expected '(' after keyword 'funct'.")
|
|
||||||
|
|
||||||
var params: seq[string]
|
|
||||||
# parameters
|
|
||||||
while comp.current.tokenType == tkIdentifier:
|
|
||||||
comp.advance()
|
|
||||||
params.add(comp.previous.text)
|
|
||||||
if comp.current.tokenType == tkRightParen:
|
|
||||||
break
|
|
||||||
comp.consume(tkComma, "Expected ',' to separate items in the parameter list.")
|
|
||||||
|
|
||||||
comp.consume(tkRightParen, "Expected ')' after parameter list.")
|
|
||||||
|
|
||||||
# function body:
|
|
||||||
let functII = comp.chunk.len
|
|
||||||
comp.beginScope(function = true) # this saves the old stackindex, sets it to 0, :function and :result at index 0
|
|
||||||
# assumption:
|
|
||||||
# the caller will create the following stack for the function to run in:
|
|
||||||
# [0] = return value placeholder
|
|
||||||
# [1] = arg #1
|
|
||||||
# [2] = arg #2
|
|
||||||
# [3] = arg #3
|
|
||||||
|
|
||||||
if params.len > shortArgMax:
|
|
||||||
comp.error("Too many parameters.")
|
|
||||||
|
|
||||||
comp.writeChunk(0, opCheckArity) # runtime arity check
|
|
||||||
comp.writeChunk(0, params.len.uint8)
|
|
||||||
|
|
||||||
for i in countup(1, params.len):
|
|
||||||
comp.stackIndex = i
|
|
||||||
comp.addLocal(params[i-1], 0)
|
|
||||||
comp.expression()
|
|
||||||
when assertionsCompiler:
|
|
||||||
let shouldbeStackIndex = params.len + 1
|
|
||||||
if shouldbeStackIndex != comp.stackIndex:
|
|
||||||
comp.error(&"Assertion failed: wrong stackindex ({comp.stackIndex}) in function declaration (should be {shouldbeStackIndex}).")
|
|
||||||
let f = comp.endScope()
|
|
||||||
dec comp.stackIndex # the previous end scope did not put anything on the stack, it is jumped over
|
|
||||||
|
|
||||||
# end of function declaration:
|
|
||||||
comp.patchJump(jumpOverBody)
|
|
||||||
# closures are implemented in a way, where the vm pops the function from the stack
|
|
||||||
# and reads the upvalue details from the following bytes
|
|
||||||
if f.upvalues.len() > 0:
|
|
||||||
comp.writeChunk(0, opClosure)
|
|
||||||
comp.writeChunk(0, f.upvalues.len().toDU8())
|
|
||||||
for upval in f.upvalues:
|
|
||||||
comp.writeChunk(0, upval.index.toDU8())
|
|
||||||
comp.writeChunk(0, if upval.isLocal: 0'u8 else: 1'u8)
|
|
||||||
|
|
||||||
tkFunct.genRule(parseFunct, nop, pcNone)
|
|
||||||
|
|
||||||
# lists
|
|
||||||
|
|
||||||
proc parseList(comp: Compiler) =
|
|
||||||
var count: int
|
|
||||||
while comp.current.tokenType != tkRightBracket:
|
|
||||||
comp.expression()
|
|
||||||
count.inc()
|
|
||||||
if comp.current.tokenType != tkRightBracket:
|
|
||||||
comp.consume(tkComma, "Comma expected after list member.")
|
|
||||||
comp.consume(tkRightBracket, "Right bracket expected after list members.")
|
|
||||||
if count > argMax:
|
|
||||||
comp.error("Maximum list length exceeded.")
|
|
||||||
comp.writeChunk(1 - count, opCreateList)
|
|
||||||
comp.writeChunk(0, count.toDU8())
|
|
||||||
|
|
||||||
|
|
||||||
tkStartList.genRule(parseList, nop, pcNone)
|
|
||||||
|
|
||||||
# tables
|
|
||||||
|
|
||||||
proc parseTable(comp: Compiler) =
|
|
||||||
var count: int
|
|
||||||
while comp.current.tokenType != tkRightBrace:
|
|
||||||
comp.expression()
|
|
||||||
comp.consume(tkEqual, "Equal sign expected after key.")
|
|
||||||
comp.expression()
|
|
||||||
count.inc()
|
|
||||||
if comp.current.tokenType != tkRightBrace:
|
|
||||||
comp.consume(tkComma, "Comma expected after key-value pair.")
|
|
||||||
|
|
||||||
comp.consume(tkRightBrace, "Right brace expected after table members.")
|
|
||||||
if count > argMax:
|
|
||||||
comp.error("Maximum table length exceeded.")
|
|
||||||
comp.writeChunk(1 - 2 * count, opCreateTable)
|
|
||||||
comp.writeChunk(0, count.toDU8())
|
|
||||||
|
|
||||||
tkStartTable.genRule(parseTable, nop, pcNone)
|
|
||||||
|
|
||||||
# len op
|
|
||||||
|
|
||||||
proc parseLen(comp: Compiler) =
|
|
||||||
comp.expression()
|
|
||||||
comp.writeChunk(0, opLen)
|
|
||||||
|
|
||||||
tkHashtag.genRule(parseLen, nop, pcNone)
|
|
||||||
|
|
||||||
# get/set index
|
|
||||||
|
|
||||||
proc parseIndex(comp: Compiler) =
|
|
||||||
# the index
|
|
||||||
comp.expression()
|
|
||||||
comp.consume(tkRightBracket, "Right bracket expected after index.")
|
|
||||||
if comp.match(tkEqual):
|
|
||||||
comp.parsePrecedence(pcNonAssignTop)
|
|
||||||
comp.writeChunk(-2, opSetIndex)
|
|
||||||
else:
|
|
||||||
comp.writeChunk(-1, opGetIndex)
|
|
||||||
|
|
||||||
tkLeftBracket.genRule(nop, parseIndex, pcIndex)
|
|
||||||
|
|
||||||
proc parseAmpersand(comp: Compiler) =
|
proc parseAmpersand(comp: Compiler) =
|
||||||
# just a simple expression separator
|
# just a simple expression separator
|
||||||
discard
|
discard
|
||||||
|
|
|
@ -0,0 +1,103 @@
|
||||||
|
import strformat
|
||||||
|
import strutils
|
||||||
|
import bitops # needed for value
|
||||||
|
|
||||||
|
import ../scanner
|
||||||
|
import ../chunk
|
||||||
|
import ../types/value
|
||||||
|
import ../config
|
||||||
|
|
||||||
|
# the following order of imports here is important
|
||||||
|
# it defines the allowed dependency precedence between the compiler files
|
||||||
|
import types
|
||||||
|
import utils
|
||||||
|
import precedence
|
||||||
|
import jumps
|
||||||
|
import scope
|
||||||
|
|
||||||
|
proc grouping(comp: Compiler) =
|
||||||
|
# assume initial '(' is already consumed
|
||||||
|
comp.expression()
|
||||||
|
comp.consume(tkRightParen, "Expect ')' after expression.")
|
||||||
|
|
||||||
|
proc parseCall(comp: Compiler) =
|
||||||
|
# ( consumed
|
||||||
|
|
||||||
|
# create the call env
|
||||||
|
# current stack before opCall:
|
||||||
|
# ... <funct obj> <arg1> <arg2> <arg3>
|
||||||
|
# opCall converts it to this
|
||||||
|
# ... <ret val> <arg1> <arg2> <arg3>
|
||||||
|
|
||||||
|
var argcount = 0
|
||||||
|
# put args on stack
|
||||||
|
while comp.current.tokenType notin {tkRightParen, tkEof}:
|
||||||
|
comp.expression()
|
||||||
|
inc argcount
|
||||||
|
if comp.current.tokenType != tkRightParen:
|
||||||
|
comp.consume(tkComma, "Expected ',' between arguments in function calls.")
|
||||||
|
comp.consume(tkRightParen, "Expected ')' after arguments in function calls.")
|
||||||
|
|
||||||
|
# emit call
|
||||||
|
comp.writeChunk(-argcount, opCall)
|
||||||
|
comp.writeChunk(0, argcount.uint8)
|
||||||
|
|
||||||
|
tkLeftParen.genRule(grouping, parseCall, pcCall)
|
||||||
|
|
||||||
|
proc parseFunct(comp: Compiler) =
|
||||||
|
|
||||||
|
# jump over
|
||||||
|
let jumpOverBody = comp.emitJump(1, opFunctionDef)
|
||||||
|
|
||||||
|
comp.consume(tkLeftParen, "Expected '(' after keyword 'funct'.")
|
||||||
|
|
||||||
|
var params: seq[string]
|
||||||
|
# parameters
|
||||||
|
while comp.current.tokenType == tkIdentifier:
|
||||||
|
comp.advance()
|
||||||
|
params.add(comp.previous.text)
|
||||||
|
if comp.current.tokenType == tkRightParen:
|
||||||
|
break
|
||||||
|
comp.consume(tkComma, "Expected ',' to separate items in the parameter list.")
|
||||||
|
|
||||||
|
comp.consume(tkRightParen, "Expected ')' after parameter list.")
|
||||||
|
|
||||||
|
# function body:
|
||||||
|
let functII = comp.chunk.len
|
||||||
|
comp.beginScope(function = true) # this saves the old stackindex, sets it to 0, :function and :result at index 0
|
||||||
|
# assumption:
|
||||||
|
# the caller will create the following stack for the function to run in:
|
||||||
|
# [0] = return value placeholder
|
||||||
|
# [1] = arg #1
|
||||||
|
# [2] = arg #2
|
||||||
|
# [3] = arg #3
|
||||||
|
|
||||||
|
if params.len > shortArgMax:
|
||||||
|
comp.error("Too many parameters.")
|
||||||
|
|
||||||
|
comp.writeChunk(0, opCheckArity) # runtime arity check
|
||||||
|
comp.writeChunk(0, params.len.uint8)
|
||||||
|
|
||||||
|
for i in countup(1, params.len):
|
||||||
|
comp.stackIndex = i
|
||||||
|
comp.addLocal(params[i-1], 0)
|
||||||
|
comp.expression()
|
||||||
|
when assertionsCompiler:
|
||||||
|
let shouldbeStackIndex = params.len + 1
|
||||||
|
if shouldbeStackIndex != comp.stackIndex:
|
||||||
|
comp.error(&"Assertion failed: wrong stackindex ({comp.stackIndex}) in function declaration (should be {shouldbeStackIndex}).")
|
||||||
|
let f = comp.endScope()
|
||||||
|
dec comp.stackIndex # the previous end scope did not put anything on the stack, it is jumped over
|
||||||
|
|
||||||
|
# end of function declaration:
|
||||||
|
comp.patchJump(jumpOverBody)
|
||||||
|
# closures are implemented in a way, where the vm pops the function from the stack
|
||||||
|
# and reads the upvalue details from the following bytes
|
||||||
|
if f.upvalues.len() > 0:
|
||||||
|
comp.writeChunk(0, opClosure)
|
||||||
|
comp.writeChunk(0, f.upvalues.len().toDU8())
|
||||||
|
for upval in f.upvalues:
|
||||||
|
comp.writeChunk(0, upval.index.toDU8())
|
||||||
|
comp.writeChunk(0, if upval.isLocal: 0'u8 else: 1'u8)
|
||||||
|
|
||||||
|
tkFunct.genRule(parseFunct, nop, pcNone)
|
Loading…
Reference in New Issue