Super clunky lambda implementation
This commit is contained in:
parent
97698b28af
commit
e926696953
|
@ -543,6 +543,8 @@ proc toIntrinsic*(name: string): Type =
|
||||||
## otherwise
|
## otherwise
|
||||||
if name == "any":
|
if name == "any":
|
||||||
return Type(kind: Any)
|
return Type(kind: Any)
|
||||||
|
elif name == "all":
|
||||||
|
return Type(kind: All)
|
||||||
elif name == "auto":
|
elif name == "auto":
|
||||||
return Type(kind: Auto)
|
return Type(kind: Auto)
|
||||||
elif name in ["int", "int64", "i64"]:
|
elif name in ["int", "int64", "i64"]:
|
||||||
|
|
|
@ -86,6 +86,7 @@ type
|
||||||
# The topmost occupied stack slot
|
# The topmost occupied stack slot
|
||||||
# in the current frame (0-indexed)
|
# in the current frame (0-indexed)
|
||||||
stackIndex: int
|
stackIndex: int
|
||||||
|
lambdas: seq[LambdaExpr]
|
||||||
|
|
||||||
|
|
||||||
# Forward declarations
|
# Forward declarations
|
||||||
|
@ -119,6 +120,7 @@ proc newBytecodeCompiler*(replMode: bool = false): BytecodeCompiler =
|
||||||
result.depth = 0
|
result.depth = 0
|
||||||
result.lines = @[]
|
result.lines = @[]
|
||||||
result.jumps = @[]
|
result.jumps = @[]
|
||||||
|
result.lambdas = @[]
|
||||||
result.currentFunction = nil
|
result.currentFunction = nil
|
||||||
result.replMode = replMode
|
result.replMode = replMode
|
||||||
result.currentModule = nil
|
result.currentModule = nil
|
||||||
|
@ -719,10 +721,10 @@ proc handleMagicPragma(self: BytecodeCompiler, pragma: Pragma, name: Name) =
|
||||||
name.valueType.builtinOp = pragma.args[0].token.lexeme[1..^2]
|
name.valueType.builtinOp = pragma.args[0].token.lexeme[1..^2]
|
||||||
elif name.node.kind == NodeKind.typeDecl:
|
elif name.node.kind == NodeKind.typeDecl:
|
||||||
name.valueType = pragma.args[0].token.lexeme[1..^2].toIntrinsic()
|
name.valueType = pragma.args[0].token.lexeme[1..^2].toIntrinsic()
|
||||||
if name.valueType.isNil():
|
|
||||||
self.error("'magic' pragma: wrong argument value", pragma.args[0])
|
|
||||||
if name.valueType.kind == All:
|
if name.valueType.kind == All:
|
||||||
self.error("don't even think about it (compiler-chan is angry at you)", pragma)
|
self.error("don't even think about it (compiler-chan is angry at you)", pragma)
|
||||||
|
if name.valueType.isNil():
|
||||||
|
self.error("'magic' pragma: wrong argument value", pragma.args[0])
|
||||||
name.isBuiltin = true
|
name.isBuiltin = true
|
||||||
else:
|
else:
|
||||||
self.error("'magic' pragma is not valid in this context")
|
self.error("'magic' pragma is not valid in this context")
|
||||||
|
@ -1337,13 +1339,11 @@ method call(self: BytecodeCompiler, node: CallExpr, compile: bool = true): Type
|
||||||
result = self.specialize(result, argExpr)
|
result = self.specialize(result, argExpr)
|
||||||
if impl.valueType.isAuto:
|
if impl.valueType.isAuto:
|
||||||
impl = self.prepareAutoFunction(impl, args)
|
impl = self.prepareAutoFunction(impl, args)
|
||||||
result = impl.valueType
|
result = impl.valueType
|
||||||
if not impl.valueType.compiled:
|
if result.fun.kind == NodeKind.lambdaExpr:
|
||||||
case result.fun.kind:
|
self.lambdaExpr(LambdaExpr(result.fun), compile=compile)
|
||||||
of NodeKind.lambdaExpr:
|
elif not impl.valueType.compiled:
|
||||||
self.lambdaExpr(LambdaExpr(result.fun), compile=compile)
|
self.funDecl(FunDecl(result.fun), impl)
|
||||||
else:
|
|
||||||
self.funDecl(FunDecl(result.fun), impl)
|
|
||||||
result = result.returnType
|
result = result.returnType
|
||||||
if compile:
|
if compile:
|
||||||
if impl.valueType.fun.kind == funDecl and FunDecl(impl.valueType.fun).isTemplate:
|
if impl.valueType.fun.kind == funDecl and FunDecl(impl.valueType.fun).isTemplate:
|
||||||
|
@ -1391,14 +1391,13 @@ method call(self: BytecodeCompiler, node: CallExpr, compile: bool = true): Type
|
||||||
self.generateCall(impl, argExpr, node.token.line)
|
self.generateCall(impl, argExpr, node.token.line)
|
||||||
of NodeKind.lambdaExpr:
|
of NodeKind.lambdaExpr:
|
||||||
var node = LambdaExpr(node.callee)
|
var node = LambdaExpr(node.callee)
|
||||||
var impl = self.lambdaExpr(node, compile=false)
|
var impl = self.lambdaExpr(node, compile=compile)
|
||||||
if impl.isAuto:
|
if impl.isAuto:
|
||||||
impl = self.prepareAutoLambda(impl, args)
|
impl = self.prepareAutoLambda(impl, args)
|
||||||
result = impl
|
result = impl
|
||||||
result = result.returnType
|
result = result.returnType
|
||||||
if compile:
|
if compile:
|
||||||
self.generateCall(impl, argExpr, node.token.line)
|
self.generateCall(impl, argExpr, node.token.line)
|
||||||
# TODO: Calling lambdas on-the-fly (i.e. on the same line)
|
|
||||||
else:
|
else:
|
||||||
let typ = self.infer(node)
|
let typ = self.infer(node)
|
||||||
if typ.isNil():
|
if typ.isNil():
|
||||||
|
@ -1459,30 +1458,17 @@ proc blockStmt(self: BytecodeCompiler, node: BlockStmt, compile: bool = true) =
|
||||||
|
|
||||||
method lambdaExpr(self: BytecodeCompiler, node: LambdaExpr, compile: bool = true): Type {.discardable.} =
|
method lambdaExpr(self: BytecodeCompiler, node: LambdaExpr, compile: bool = true): Type {.discardable.} =
|
||||||
## Compiles lambda functions as expressions
|
## Compiles lambda functions as expressions
|
||||||
result = Type(kind: Function, isLambda: true, fun: node, location: 0)
|
result = Type(kind: Function, isLambda: true, fun: node, location: 0, compiled: true)
|
||||||
let function = self.currentFunction
|
let function = self.currentFunction
|
||||||
self.beginScope()
|
|
||||||
var constraints: seq[tuple[match: bool, kind: Type]] = @[]
|
|
||||||
for gen in node.generics:
|
|
||||||
self.unpackGenerics(gen.cond, constraints)
|
|
||||||
self.names.add(Name(depth: self.depth,
|
|
||||||
isPrivate: true,
|
|
||||||
valueType: Type(kind: Generic, name: gen.name.token.lexeme, cond: constraints),
|
|
||||||
codePos: 0,
|
|
||||||
isLet: false,
|
|
||||||
line: node.token.line,
|
|
||||||
belongsTo: nil, # TODO
|
|
||||||
ident: gen.name,
|
|
||||||
owner: self.currentModule,
|
|
||||||
file: self.file))
|
|
||||||
constraints = @[]
|
|
||||||
var default: Expression
|
var default: Expression
|
||||||
var name: Name
|
var name: Name
|
||||||
var i = 0
|
var i = 0
|
||||||
|
let stackIdx = self.stackIndex
|
||||||
|
self.stackIndex = 2
|
||||||
for argument in node.arguments:
|
for argument in node.arguments:
|
||||||
if self.names.high() > 16777215:
|
if self.names.high() > 16777215:
|
||||||
self.error("cannot declare more than 16777215 variables at a time")
|
self.error("cannot declare more than 16777215 variables at a time")
|
||||||
name = Name(depth: self.depth,
|
name = Name(depth: self.depth + 1,
|
||||||
isPrivate: true,
|
isPrivate: true,
|
||||||
owner: self.currentModule,
|
owner: self.currentModule,
|
||||||
file: self.currentModule.file,
|
file: self.currentModule.file,
|
||||||
|
@ -1494,10 +1480,12 @@ method lambdaExpr(self: BytecodeCompiler, node: LambdaExpr, compile: bool = true
|
||||||
line: argument.name.token.line,
|
line: argument.name.token.line,
|
||||||
belongsTo: nil, # TODO
|
belongsTo: nil, # TODO
|
||||||
kind: NameKind.Argument,
|
kind: NameKind.Argument,
|
||||||
node: argument.name
|
node: argument.name,
|
||||||
|
position: self.stackIndex
|
||||||
)
|
)
|
||||||
if compile:
|
if compile:
|
||||||
self.names.add(name)
|
self.names.add(name)
|
||||||
|
inc(self.stackIndex)
|
||||||
if node.arguments.high() - node.defaults.high() <= node.arguments.high():
|
if node.arguments.high() - node.defaults.high() <= node.arguments.high():
|
||||||
# There's a default argument!
|
# There's a default argument!
|
||||||
result.args.add((name.ident.token.lexeme, name.valueType, node.defaults[i]))
|
result.args.add((name.ident.token.lexeme, name.valueType, node.defaults[i]))
|
||||||
|
@ -1513,23 +1501,16 @@ method lambdaExpr(self: BytecodeCompiler, node: LambdaExpr, compile: bool = true
|
||||||
isConst: false,
|
isConst: false,
|
||||||
owner: self.currentModule,
|
owner: self.currentModule,
|
||||||
file: self.file,
|
file: self.file,
|
||||||
valueType: Type(kind: Function,
|
valueType: result,
|
||||||
returnType: result.returnType,
|
|
||||||
args: result.args,
|
|
||||||
fun: node,
|
|
||||||
forwarded: false,
|
|
||||||
isAuto: false),
|
|
||||||
ident: nil,
|
ident: nil,
|
||||||
node: node,
|
node: node,
|
||||||
isLet: false,
|
isLet: false,
|
||||||
line: node.token.line,
|
line: node.token.line,
|
||||||
kind: NameKind.Function,
|
kind: NameKind.Function,
|
||||||
belongsTo: self.currentFunction,
|
belongsTo: function,
|
||||||
isReal: true)
|
isReal: true)
|
||||||
if compile:
|
if compile and node notin self.lambdas:
|
||||||
result.compiled = true
|
self.lambdas.add(node)
|
||||||
let stackIdx = self.stackIndex
|
|
||||||
self.stackIndex = name.position
|
|
||||||
let jmp = self.emitJump(JumpForwards, node.token.line)
|
let jmp = self.emitJump(JumpForwards, node.token.line)
|
||||||
if BlockStmt(node.body).code.len() == 0:
|
if BlockStmt(node.body).code.len() == 0:
|
||||||
self.error("cannot construct lambda with empty body")
|
self.error("cannot construct lambda with empty body")
|
||||||
|
@ -1560,7 +1541,6 @@ method lambdaExpr(self: BytecodeCompiler, node: LambdaExpr, compile: bool = true
|
||||||
hasVal = hasVal and not typ.isNil()
|
hasVal = hasVal and not typ.isNil()
|
||||||
for jump in self.currentFunction.valueType.retJumps:
|
for jump in self.currentFunction.valueType.retJumps:
|
||||||
self.patchJump(jump)
|
self.patchJump(jump)
|
||||||
self.endScope()
|
|
||||||
# Terminates the function's context
|
# Terminates the function's context
|
||||||
self.emitByte(OpCode.Return, self.peek().token.line)
|
self.emitByte(OpCode.Return, self.peek().token.line)
|
||||||
if hasVal:
|
if hasVal:
|
||||||
|
@ -1570,13 +1550,13 @@ method lambdaExpr(self: BytecodeCompiler, node: LambdaExpr, compile: bool = true
|
||||||
# Well, we've compiled everything: time to patch
|
# Well, we've compiled everything: time to patch
|
||||||
# the jump offset
|
# the jump offset
|
||||||
self.patchJump(jmp)
|
self.patchJump(jmp)
|
||||||
# Restores the enclosing function (if any).
|
|
||||||
# Makes nested calls work (including recursion)
|
|
||||||
self.currentFunction = function
|
|
||||||
self.stackIndex = stackIdx
|
|
||||||
self.endScope()
|
|
||||||
self.emitByte(LoadUInt64, node.token.line)
|
self.emitByte(LoadUInt64, node.token.line)
|
||||||
self.emitBytes(self.chunk.writeConstant(result.location.toLong()), node.token.line)
|
self.emitBytes(self.chunk.writeConstant(result.location.toLong()), node.token.line)
|
||||||
|
self.endScope()
|
||||||
|
# Restores the enclosing function (if any).
|
||||||
|
# Makes nested calls work (including recursion)
|
||||||
|
self.currentFunction = function
|
||||||
|
self.stackIndex = stackIdx
|
||||||
|
|
||||||
|
|
||||||
method expression(self: BytecodeCompiler, node: Expression, compile: bool = true): Type {.discardable.} =
|
method expression(self: BytecodeCompiler, node: Expression, compile: bool = true): Type {.discardable.} =
|
||||||
|
|
Loading…
Reference in New Issue