-> method call

This commit is contained in:
prod2 2022-02-08 09:23:21 +01:00
parent 5f3f61af2d
commit ece31b11e0
5 changed files with 86 additions and 11 deletions

View File

@ -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,

View File

@ -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

View File

@ -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.")

View File

@ -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)

View File

@ -40,4 +40,44 @@ nested["lvl1"]["lvl2"]["lvl3"] = -5.4;
nested .lvl1 .lvl2 .lvl3 :: print;
//expect:-5.4
// creating tables with : and no [] idents
// 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