parsing procs

This commit is contained in:
prod2 2022-12-02 21:08:52 +01:00
parent e83cd424f9
commit a0e5431b0f
2 changed files with 48 additions and 9 deletions

View File

@ -102,6 +102,7 @@ proc match(parser: Parser, tokenTypes: set[TokenType]): bool =
proc consume(parser: Parser, tokenType: TokenType | set[TokenType], msg: string) =
if not parser.match(tokenType):
parser.errorAtCurrent(msg)
parser.advance() # stop infinite loops
proc peek(parser: Parser): Token =
parser.current
@ -114,7 +115,7 @@ proc synchronize(parser: Parser) =
while parser.current.tokenType != tkEof:
if parser.previous.get().tokenType in {tkSemicolon, tkRightBrace}:
return
if parser.current.tokenType in {tkFunct, tkVar, tkFor, tkIf, tkWhile}:
if parser.current.tokenType in {tkProc, tkVar, tkFor, tkIf, tkWhile}:
return
parser.advance()
@ -157,6 +158,24 @@ proc parseTable(parser: Parser): Node =
parser.consume(tkRightBrace, "'}' expected after table declaration.")
proc parseProcDeclaration(parser: Parser): Node =
# returns a nkProc, assumes that the left paren
# has been consumed, so is followed by optionally
# a param list, a ) and then an expression
var params: seq[string] = @[]
while not parser.isAtEnd() and not parser.peekMatch(tkRightParen):
parser.consume(tkIdentifier, "Parameter name expected.")
params.add(parser.previous.get().text)
if not parser.isAtEnd() and not parser.peekMatch(tkRightParen):
parser.consume(tkComma, "',' expected between parameters.")
parser.consume(tkRightParen, "')' expected after parameter list.")
let body = parser.expression()
result = Node(kind: nkProc, parameters: params, procBody: body)
proc primary(parser: Parser): Node =
if parser.match(tkFalse):
return Node(kind: nkConst, constant: ndFalse)
@ -182,6 +201,9 @@ proc primary(parser: Parser): Node =
result = parser.hold
parser.hold = nil
return result
if parser.match(tkProc):
parser.consume(tkLeftParen, "'(' expected after 'proc'.")
return parser.parseProcDeclaration()
parser.errorAtCurrent("Primary expected, but something else found.")
@ -377,7 +399,6 @@ proc parseAssign(parser: Parser): Node =
# nkGetIndex
result = Node(kind: nkSetIndex, sCollection: result.gCollection, sIndex: result.gIndex, sValue: right)
proc parseAmpersand(parser: Parser): Node =
result = parser.parseAssign()
if parser.match(tkAmpersand):
@ -392,15 +413,34 @@ proc expression(parser: Parser): Node =
proc statement(parser: Parser): Node
proc statement(parser: Parser): Node =
proc exprStatement(parser: Parser): Node =
let expression = parser.expression()
if expression != nil:
result = Node(kind: nkExprStmt, expression: expression)
else:
parser.errorAtCurrent("Expression expected.")
parser.consume(tkSemicolon, "; expected after expression statement.")
parser.consume(tkSemicolon, "';' expected after expression statement.")
proc statement(parser: Parser): Node =
if parser.match(tkProc):
# it is possibly a proc declaration, but
# it could also be a proc expression
if parser.peekMatch(tkLeftParen):
# proc expression - backtrack and let it go to expression statement
parser.backtrack()
result = parser.exprStatement()
else:
# proc definition - var declaration sort of code
parser.consume(tkIdentifier, "Procedure name expected after 'proc'.")
let varname = parser.previous.get().text
parser.consume(tkLeftParen, "'(' expected after procedure name.")
let funct = parser.parseProcDeclaration()
result = Node(kind: nkVarDecl, name: varname, value: funct)
parser.consume(tkSemicolon, "';' expected after procedure declaration.")
else:
result = parser.exprStatement()
if parser.panicMode:
parser.synchronize()

View File

@ -19,7 +19,7 @@ type
tkStartList, tkStartTable, tkLeftBracket, tkRightBracket,
tkHashtag, tkAmpersand,
tkIdentifier, tkString,
tkNumber, tkAnd, tkDef, tkElse, tkFalse, tkFor, tkFunct, tkGoto, tkIf, tkNil,
tkNumber, tkAnd, tkElse, tkFalse, tkFor, tkProc, tkGoto, tkIf, tkNil,
tkOr, tkLabel, tkBreak, tkTrue, tkVar, tkWhile,
tkError, tkEof
@ -142,11 +142,10 @@ proc scanNumber(scanner: Scanner): Token =
const keywords = {
"and": tkAnd,
"break": tkBreak,
"def": tkDef,
"else": tkElse,
"false": tkFalse,
"for": tkFor,
"proc": tkFunct,
"proc": tkProc,
"goto": tkGoto,
"if": tkIf,
"nil": tkNil,