127 lines
3.1 KiB
Nim
127 lines
3.1 KiB
Nim
# beacon_chain
|
|
# Copyright (c) 2020-2024 Status Research & Development GmbH
|
|
# Licensed and distributed under either of
|
|
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
|
|
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
|
|
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
|
|
|
import
|
|
std/[strutils, strformat, parseutils]
|
|
|
|
type
|
|
TokenKind* = enum
|
|
tIdent = "ident"
|
|
tNumber = "number"
|
|
tDot = "dot"
|
|
tOpenBracket = "["
|
|
tCloseBracket = "]"
|
|
tEof = "end of file"
|
|
tError = "error"
|
|
|
|
Token* = object
|
|
case kind*: TokenKind
|
|
of tIdent:
|
|
name*: string
|
|
of tNumber:
|
|
val*: uint64
|
|
of tError:
|
|
errMsg: string
|
|
else:
|
|
discard
|
|
|
|
Lexer* = object
|
|
tok*: Token
|
|
input: string
|
|
pos: int
|
|
|
|
Parser* = object
|
|
lexer: Lexer
|
|
|
|
NodeKind* = enum
|
|
Ident
|
|
Number
|
|
Dot
|
|
ArrayAccess
|
|
Error
|
|
|
|
Node* = ref object
|
|
case kind*: NodeKind
|
|
of Dot:
|
|
objVal*, field*: Node
|
|
of ArrayAccess:
|
|
arrayVal*, index*: Node
|
|
of Ident:
|
|
name*: string
|
|
of Number:
|
|
numVal*: uint64
|
|
of Error:
|
|
errMsg*: string
|
|
|
|
func advance(lexer: var Lexer) =
|
|
if lexer.pos >= lexer.input.len:
|
|
lexer.tok = Token(kind: tEof)
|
|
else:
|
|
let nextChar = lexer.input[lexer.pos]
|
|
case nextChar
|
|
of IdentStartChars:
|
|
lexer.tok = Token(kind: tIdent)
|
|
lexer.pos = parseIdent(lexer.input, lexer.tok.name, lexer.pos)
|
|
of Whitespace:
|
|
lexer.pos = skipWhitespace(lexer.input, lexer.pos)
|
|
advance lexer
|
|
of Digits:
|
|
lexer.tok = Token(kind: tNumber)
|
|
lexer.pos = parseBiggestUInt(lexer.input, lexer.tok.val, lexer.pos)
|
|
of '[':
|
|
lexer.tok = Token(kind: tOpenBracket)
|
|
inc lexer.pos
|
|
of ']':
|
|
lexer.tok = Token(kind: tCloseBracket)
|
|
inc lexer.pos
|
|
of '.':
|
|
lexer.tok = Token(kind: tDot)
|
|
inc lexer.pos
|
|
else:
|
|
lexer.tok = Token(
|
|
kind: tError,
|
|
errMsg: &"Unexpected character '{nextChar}' at position {lexer.pos}")
|
|
|
|
func init*(T: type Lexer, src: string): Lexer =
|
|
result.input = src
|
|
result.pos = 0
|
|
advance result
|
|
|
|
func init*(T: type Parser, src: string): Parser =
|
|
Parser(lexer: Lexer.init(src))
|
|
|
|
func expr(parser: var Parser): Node =
|
|
template unexpectedToken =
|
|
return Node(kind: Error, errMsg: &"Unexpected {parser.lexer.tok.kind} token")
|
|
|
|
case parser.lexer.tok.kind
|
|
of tIdent:
|
|
result = Node(kind: Ident, name: parser.lexer.tok.name)
|
|
of tNumber:
|
|
return Node(kind: Number, numVal: parser.lexer.tok.val)
|
|
else:
|
|
unexpectedToken
|
|
|
|
advance parser.lexer
|
|
case parser.lexer.tok.kind
|
|
of tOpenBracket:
|
|
advance parser.lexer
|
|
result = Node(kind: ArrayAccess, arrayVal: result, index: parser.expr)
|
|
if parser.lexer.tok.kind != tCloseBracket:
|
|
unexpectedToken
|
|
else:
|
|
advance parser.lexer
|
|
of tDot:
|
|
advance parser.lexer
|
|
return Node(kind: Dot, objVal: result, field: parser.expr)
|
|
else:
|
|
discard
|
|
|
|
func parse*(input: string): Node =
|
|
var p = Parser.init(input)
|
|
p.expr
|