diff --git a/src/frontend/compiler/compiler.nim b/src/frontend/compiler/compiler.nim index 73a0d94..041134e 100644 --- a/src/frontend/compiler/compiler.nim +++ b/src/frontend/compiler/compiler.nim @@ -543,6 +543,8 @@ proc toIntrinsic*(name: string): Type = ## otherwise if name == "any": return Type(kind: Any) + elif name == "all": + return Type(kind: All) elif name == "auto": return Type(kind: Auto) elif name in ["int", "int64", "i64"]: diff --git a/src/frontend/compiler/targets/bytecode/target.nim b/src/frontend/compiler/targets/bytecode/target.nim index dd09b45..1ded887 100644 --- a/src/frontend/compiler/targets/bytecode/target.nim +++ b/src/frontend/compiler/targets/bytecode/target.nim @@ -86,6 +86,7 @@ type # The topmost occupied stack slot # in the current frame (0-indexed) stackIndex: int + lambdas: seq[LambdaExpr] # Forward declarations @@ -119,6 +120,7 @@ proc newBytecodeCompiler*(replMode: bool = false): BytecodeCompiler = result.depth = 0 result.lines = @[] result.jumps = @[] + result.lambdas = @[] result.currentFunction = nil result.replMode = replMode 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] elif name.node.kind == NodeKind.typeDecl: 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: 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 else: 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) if impl.valueType.isAuto: impl = self.prepareAutoFunction(impl, args) - result = impl.valueType - if not impl.valueType.compiled: - case result.fun.kind: - of NodeKind.lambdaExpr: - self.lambdaExpr(LambdaExpr(result.fun), compile=compile) - else: - self.funDecl(FunDecl(result.fun), impl) + result = impl.valueType + if result.fun.kind == NodeKind.lambdaExpr: + self.lambdaExpr(LambdaExpr(result.fun), compile=compile) + elif not impl.valueType.compiled: + self.funDecl(FunDecl(result.fun), impl) result = result.returnType if compile: 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) of NodeKind.lambdaExpr: var node = LambdaExpr(node.callee) - var impl = self.lambdaExpr(node, compile=false) + var impl = self.lambdaExpr(node, compile=compile) if impl.isAuto: impl = self.prepareAutoLambda(impl, args) result = impl result = result.returnType if compile: self.generateCall(impl, argExpr, node.token.line) - # TODO: Calling lambdas on-the-fly (i.e. on the same line) else: let typ = self.infer(node) 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.} = ## 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 - 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 name: Name var i = 0 + let stackIdx = self.stackIndex + self.stackIndex = 2 for argument in node.arguments: if self.names.high() > 16777215: self.error("cannot declare more than 16777215 variables at a time") - name = Name(depth: self.depth, + name = Name(depth: self.depth + 1, isPrivate: true, owner: self.currentModule, file: self.currentModule.file, @@ -1494,10 +1480,12 @@ method lambdaExpr(self: BytecodeCompiler, node: LambdaExpr, compile: bool = true line: argument.name.token.line, belongsTo: nil, # TODO kind: NameKind.Argument, - node: argument.name + node: argument.name, + position: self.stackIndex ) if compile: self.names.add(name) + inc(self.stackIndex) if node.arguments.high() - node.defaults.high() <= node.arguments.high(): # There's a default argument! 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, owner: self.currentModule, file: self.file, - valueType: Type(kind: Function, - returnType: result.returnType, - args: result.args, - fun: node, - forwarded: false, - isAuto: false), + valueType: result, ident: nil, node: node, isLet: false, line: node.token.line, kind: NameKind.Function, - belongsTo: self.currentFunction, + belongsTo: function, isReal: true) - if compile: - result.compiled = true - let stackIdx = self.stackIndex - self.stackIndex = name.position + if compile and node notin self.lambdas: + self.lambdas.add(node) let jmp = self.emitJump(JumpForwards, node.token.line) if BlockStmt(node.body).code.len() == 0: 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() for jump in self.currentFunction.valueType.retJumps: self.patchJump(jump) - self.endScope() # Terminates the function's context self.emitByte(OpCode.Return, self.peek().token.line) if hasVal: @@ -1570,13 +1550,13 @@ method lambdaExpr(self: BytecodeCompiler, node: LambdaExpr, compile: bool = true # Well, we've compiled everything: time to patch # the jump offset 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.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.} =