From 2e60ab9fb6293cc5185c7c48a819ca20504fd0ad Mon Sep 17 00:00:00 2001 From: nocturn9x Date: Thu, 14 Jan 2021 12:55:51 +0100 Subject: [PATCH] Added a beta implementation for arrow functions --- src/compiler.nim | 36 ++++++++++++++++++++++++++---------- src/lexer.nim | 2 ++ src/meta/token.nim | 2 +- src/types/function.nim | 18 ++++++++++++++++-- src/types/japlString.nim | 1 - 5 files changed, 45 insertions(+), 14 deletions(-) diff --git a/src/compiler.nim b/src/compiler.nim index 8012f17..1745a78 100644 --- a/src/compiler.nim +++ b/src/compiler.nim @@ -925,7 +925,7 @@ proc parseFunction(self: Compiler, funType: FunctionType) = ## keyword ones as well var self = initCompiler(funType, self, self.parser, self.file) self.beginScope() - self.parser.consume(LP, "Expecting '(' after function name") + self.parser.consume(LP, "Expecting '('") if self.parser.hadError: return var paramNames: seq[string] = @[] @@ -970,13 +970,22 @@ proc parseFunction(self: Compiler, funType: FunctionType) = self.emitBytes(self.makeLongConstant(fun)) -proc funDeclaration(self: Compiler) = + +proc parseLambda(self: Compiler, canAssign: bool) = + ## Parses lambda expressions of the form => (params) {code} + self.parseFunction(FunctionType.LAMBDA) + + +proc funDeclaration(self: Compiler, named: bool = true) = ## Parses function declarations and declares ## them in the current scope - var funName = self.parseVariable("expecting function name") - self.markInitialized() - self.parseFunction(FunctionType.FUNC) - self.defineVariable(funName) + if named: + var funName = self.parseVariable("expecting function name") + self.markInitialized() + self.parseFunction(FunctionType.FUNC) + self.defineVariable(funName) + else: + self.parseFunction(FunctionType.LAMBDA) proc argumentList(self: Compiler): uint8 = @@ -1153,7 +1162,8 @@ var rules: array[TokenType, ParseRule] = [ makeRule(nil, binary, Precedence.Term), # BOR makeRule(unary, nil, Precedence.None), # TILDE makeRule(nil, binary, Precedence.Is), # IS - makeRule(nil, binary, Precedence.As) # AS + makeRule(nil, binary, Precedence.As), # AS + makeRule(parseLambda, nil, Precedence.None) # LAMBDA ] @@ -1229,9 +1239,15 @@ proc initCompiler*(context: FunctionType, enclosing: Compiler = nil, parser: Par result.parser.file = file result.locals.add(Local(depth: 0, name: Token(kind: EOF, lexeme: ""))) inc(result.localCount) - result.function = result.markObject(newFunction(chunk=newChunk())) - if context != SCRIPT: # If we're compiling a function, we give it its name - result.function.name = asStr(enclosing.parser.previous().lexeme) + case context: + of FunctionType.Func: + result.function = result.markObject(newFunction(enclosing.parser.previous().lexeme, newChunk())) + of FunctionType.Lambda: + result.function = result.markObject(newLambda(newChunk())) + else: # Script + result.function = result.markObject(newFunction("", newChunk())) + result.function.name = nil + # This way the compiler can be executed on its own # without the VM diff --git a/src/lexer.nim b/src/lexer.nim index ca904b7..b5879ca 100644 --- a/src/lexer.nim +++ b/src/lexer.nim @@ -218,6 +218,8 @@ proc scanToken(self: Lexer) = self.parseComment() elif single == '=' and self.match('='): self.tokens.add(self.createToken(TokenType.DEQ)) + elif single == '=' and self.match('>'): + self.tokens.add(self.createToken(TokenType.LAMBDA)) elif single == '>' and self.match('='): self.tokens.add(self.createToken(TokenType.GE)) elif single == '>' and self.match('>'): diff --git a/src/meta/token.nim b/src/meta/token.nim index e04df4e..63a861a 100644 --- a/src/meta/token.nim +++ b/src/meta/token.nim @@ -29,7 +29,7 @@ type WHILE, DEL, BREAK, EOF, COLON, CONTINUE, CARET, SHL, SHR, NAN, INF, BAND, - BOR, TILDE, IS, AS + BOR, TILDE, IS, AS, LAMBDA Token* = ref object kind*: TokenType lexeme*: string diff --git a/src/types/function.nim b/src/types/function.nim index debbff8..d2ec2c0 100644 --- a/src/types/function.nim +++ b/src/types/function.nim @@ -12,7 +12,7 @@ type ## the top-level code, this tiny ## enum is used to tell the two ## contexts apart when compiling - Func, Script + Func, Script, Lambda Function* = object of Obj ## A function object @@ -40,13 +40,27 @@ proc newFunction*(name: string = "", chunk: Chunk, arity: int = 0): ptr Function result.isHashable = false +proc newLambda*(chunk: Chunk, arity: int = 0): ptr Function = + ## Allocates a new lambda object (anonymous function) with the given + ## bytecode chunk and arity + # TODO: Add lambdas + # TODO: Add support for optional parameters + result = allocateObj(Function, ObjectType.Function) + result.name = "".asStr() + result.arity = arity + result.chunk = chunk + result.isHashable = false + + proc typeName*(self: ptr Function): string = result = "function" proc stringify*(self: ptr Function): string = - if self.name != nil: + if self.name != nil and self.name.toStr() != "": result = "" + elif self.name.toStr() == "": + return self.name.toStr() else: result = "" diff --git a/src/types/japlString.nim b/src/types/japlString.nim index 53675bc..809bc22 100644 --- a/src/types/japlString.nim +++ b/src/types/japlString.nim @@ -19,7 +19,6 @@ import baseObject import numbers import ../memory import strutils -import strformat type