From ece31b11e02075a31ab4a4b3bcd8d96b9e610932 Mon Sep 17 00:00:00 2001 From: prod2 <95874442+prod2@users.noreply.github.com> Date: Tue, 8 Feb 2022 09:23:21 +0100 Subject: [PATCH] -> method call --- src/ndspkg/chunk.nim | 4 +-- src/ndspkg/compiler/functions.nim | 28 +++++++++++++++++++++ src/ndspkg/scanner.nim | 21 ++++++++++------ src/ndspkg/vm.nim | 2 ++ tests/sugar.nds | 42 ++++++++++++++++++++++++++++++- 5 files changed, 86 insertions(+), 11 deletions(-) diff --git a/src/ndspkg/chunk.nim b/src/ndspkg/chunk.nim index 9693986..b73e59d 100644 --- a/src/ndspkg/chunk.nim +++ b/src/ndspkg/chunk.nim @@ -9,7 +9,7 @@ type opClosure, # closures opPop, opPopSA, opPopA # pop opNegate, opNot # unary - opSwap, # stack manipulation + opSwap, opDup, # stack manipulation opAdd, opSubtract, opMultiply, opDivide, # math opEqual, opGreater, opLess, # comparison opTrue, opFalse, opNil, # literal @@ -92,7 +92,7 @@ proc writeConstant*(ch: var Chunk, constant: NdValue, line: int): int = const simpleInstructions = { opReturn, opPop, - opSwap, + opSwap, opDup, opNegate, opNot, opAdd, opSubtract, opMultiply, opDivide, opEqual, opGreater, opLess, diff --git a/src/ndspkg/compiler/functions.nim b/src/ndspkg/compiler/functions.nim index c66ec7a..c60091c 100644 --- a/src/ndspkg/compiler/functions.nim +++ b/src/ndspkg/compiler/functions.nim @@ -1,9 +1,11 @@ {.used.} import strformat +import bitops import ../scanner import ../chunk +import ../types/value import ../config import types @@ -67,6 +69,32 @@ proc parsePipeCall(comp: Compiler) = tkDoublecolon.genRule(nop, parsePipeCall, pcAmpersand) +proc parseArrowCall(comp: Compiler) = + # -> syntactic sugar for table "methods" + + # when called, the stack contains the table + # the table should be duplicated first + comp.writeChunk(1, opDup) + # then the index should be read + comp.consume(tkIdentifier, "Identifier (index) expected after '->'.") + let index = comp.previous.text.fromNimString() + comp.writeConstant(index) + comp.writeChunk(-1, opGetIndex) + # the stack's state now is table, method + # invert to get the right alignment for further function call + comp.writeChunk(0, opSwap) + # now the same code as :: applies + var argcount = 1 + # args optional + if comp.match(tkLeftParen): + argcount = 1 + comp.parseArgs() + + comp.writeChunk(-argcount, opCall) + comp.writeChunk(0, argcount.uint8) + + +tkArrow.genRule(nop, parseArrowCall, pcIndex) + proc parseFunct(comp: Compiler) = # jump over diff --git a/src/ndspkg/scanner.nim b/src/ndspkg/scanner.nim index d1b2cc6..537ffd2 100644 --- a/src/ndspkg/scanner.nim +++ b/src/ndspkg/scanner.nim @@ -11,7 +11,8 @@ type TokenType* = enum tkNone, # the default tokentype, if encountered anywhere, erroring out is the best course of action - tkLeftParen, tkRightParen, tkLeftBrace, tkRightBrace, tkComma, tkDot, tkColon, tkDoublecolon, + tkLeftParen, tkRightParen, tkLeftBrace, tkRightBrace, tkComma, tkDot, + tkColon, tkDoublecolon, tkArrow, tkMinus, tkPlus, tkSemicolon, tkSlash, tkStar, tkBang, tkBangEqual, tkGreater, tkGreaterEqual, tkLess, tkLessEqual, tkEqual, tkEqualEqual, tkStartList, tkStartTable, tkLeftBracket, tkRightBracket, @@ -127,7 +128,7 @@ const keywords = { }.toTable proc canStartIdent(chr: char): bool = - chr in Letters or chr in {'_', ':'} + chr in Letters or chr in {'_'} proc canContIdent(chr: char): bool = canStartIdent(chr) or chr in Digits @@ -175,7 +176,11 @@ proc scanToken*(scanner: Scanner): Token = of ';': return scanner.makeToken(tkSemicolon) of ',': return scanner.makeToken(tkComma) of '.': return scanner.makeToken(tkDot) - of '-': return scanner.makeToken(tkMinus) + of '-': + if scanner.match('>'): + return scanner.makeToken(tkArrow) + else: + return scanner.makeToken(tkMinus) of '+': return scanner.makeToken(tkPlus) of '/': return scanner.makeToken(tkSlash) of '*': return scanner.makeToken(tkStar) @@ -197,13 +202,13 @@ proc scanToken*(scanner: Scanner): Token = if scanner.match('['): return scanner.makeToken(tkStartList) elif scanner.match('{'): return scanner.makeToken(tkStartTable) else: return scanner.scanLabel() + of ':': + if scanner.match(':'): return scanner.makeToken(tkDoublecolon) + elif scanner.peek().canContIdent(): return scanner.scanIdentifier() + else: return scanner.makeToken(tkColon) else: - if c == ':' and scanner.match(':'): - return scanner.makeToken(tkDoublecolon) if c.canStartIdent(): - # : can start ident, but if on its own it's probably syntactic sugar for tables - if c == ':' and not scanner.peek().canContIdent(): - return scanner.makeToken(tkColon) + # ':' can start ident, but is not handled here return scanner.scanIdentifier() else: return scanner.errorToken("Unexpected character.") diff --git a/src/ndspkg/vm.nim b/src/ndspkg/vm.nim index bb0a1de..2ec3b52 100644 --- a/src/ndspkg/vm.nim +++ b/src/ndspkg/vm.nim @@ -188,6 +188,8 @@ proc run*(chunk: Chunk): InterpretResult = stack.popn(amt) of opSwap: stack.swap() + of opDup: + stack.push(stack.peek()) of opConstant: let val: NdValue = ip.readConstant(chunk) stack.add(val) diff --git a/tests/sugar.nds b/tests/sugar.nds index 1c79729..7b3603d 100644 --- a/tests/sugar.nds +++ b/tests/sugar.nds @@ -40,4 +40,44 @@ nested["lvl1"]["lvl2"]["lvl3"] = -5.4; nested .lvl1 .lvl2 .lvl3 :: print; //expect:-5.4 -// creating tables with : and no [] idents \ No newline at end of file +// creating tables with : and no [] idents + +var mix = @{ + ident = 5, + ident2: 6, + [3] = 7, + ["ident4"]: 8, +}; + +print(mix.ident, mix["ident2"], mix[3], mix.ident4); +//expect:5.0 6.0 7.0 8.0 + +// -> method call syntax + +var class = @{ + method = funct(self) print ("i was called") +}; + +// no args needed then no parentheses needed +class->method; +//expect:i was called + +var multiplier = @{ + multiple = 5, + do = funct(self, arg) :result = self.multiple * arg, +}; + +multiplier->do(7) :: print; +//expect:35.0 + +// -> method call syntax with :: - check for precedence + +var returner = @{ + method = funct(self) :result = funct(n) :result = n * 2 +}; + +1.7 :: returner->method :: print; +//expect:3.4 + +print("finish"); +//expect:finish \ No newline at end of file