I'm writing a simple math equation lexer and I've come to a point where I need to join two terminal tokens to make a non-terminal token.
Here's an excerpt:
type
Token* = ref object of RootObj
position*: int
DigitToken = ref object of Token
value: uint
NumberToken = ref object of Token
value: int
method joinTokens*(a, b: Token): Token {.base.} =
quit "joinTokens base called " & repr(a) & "\n" & repr(b)
method joinTokens*(a, b: DigitToken): NumberToken =
result = NumberToken()
result.position = max(a.position, b.position)
result.value = int(a.value*10 + b.value)
method joinTokens*(a: NumberToken, b: DigitToken): NumberToken =
result = NumberToken()
result.position = max(a.position, b.position)
result.value = a.value*10 + int(b.value)
var digits: seq[Token]
digits.add DigitToken(value:1, position:0)
digits.add DigitToken(value:2, position:1)
var numberA = joinTokens(digits[0], digits[1])
I've compiled it with --multimethods:on. I wanted method joinTokens*(a, b: DigitToken): NumberToken to be called, but instead method joinTokens*(a, b: Token): Token {.base.} gets called.
What can I do? I've tried type case of and I'd rather prefer to use this parent-children hierachy I have now.
Seems like there is a bug, if you comment out the first method you get
type
Token* = ref object of RootObj
position*: int
DigitToken* = ref object of Token
value*: uint
NumberToken* = ref object of Token
value*: int
# method joinTokens*(a, b: Token): Token {.base.} =
# quit "joinTokens base called " & repr(a) & "\n" & repr(b)
method joinTokens*(a: DigitToken, b: DigitToken): NumberToken =
result = NumberToken()
result.position = max(a.position, b.position)
result.value = int(a.value*10 + b.value)
method joinTokens*(a: NumberToken, b: DigitToken): NumberToken =
result = NumberToken()
result.position = max(a.position, b.position)
result.value = a.value*10 + int(b.value)
var digits: seq[Token]
digits.add DigitToken(value:1, position:0)
digits.add DigitToken(value:2, position:1)
var numberA = joinTokens(digits[0], digits[1])
Error: type mismatch: got <Token, Token>
but expected one of:
method joinTokens(a: DigitToken; b: DigitToken): NumberToken
first type mismatch at position: 1
required type for a: DigitToken
but expression 'digits[0]' is of type: Token
method joinTokens(a: NumberToken; b: DigitToken): NumberToken
first type mismatch at position: 1
required type for a: NumberToken
but expression 'digits[0]' is of type: Token
expression: joinTokens(digits[0], digits[1])
You can raise it in the issue tracker: https://github.com/nim-lang/Nim/issues
Apart from that I really don't like to pull the "actually what you are asking is not what you want" card, but this is not how you should write a lexer.
I suggest you use the npegs module which will let you define a grammar in a declarative way: https://github.com/zevv/npeg
Apart from that I really don't like to pull the "actually what you are asking is not what you want" card, but this is not how you should write a lexer.
I'd like to, but it's for a class assignment, so I have to do it by hand. Also, I want to learn how it can be done on lower level of abstraction. No problem pulling this card. It's always nice to show the other way.