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) = proc consume(parser: Parser, tokenType: TokenType | set[TokenType], msg: string) =
if not parser.match(tokenType): if not parser.match(tokenType):
parser.errorAtCurrent(msg) parser.errorAtCurrent(msg)
parser.advance() # stop infinite loops
proc peek(parser: Parser): Token = proc peek(parser: Parser): Token =
parser.current parser.current
@ -114,7 +115,7 @@ proc synchronize(parser: Parser) =
while parser.current.tokenType != tkEof: while parser.current.tokenType != tkEof:
if parser.previous.get().tokenType in {tkSemicolon, tkRightBrace}: if parser.previous.get().tokenType in {tkSemicolon, tkRightBrace}:
return return
if parser.current.tokenType in {tkFunct, tkVar, tkFor, tkIf, tkWhile}: if parser.current.tokenType in {tkProc, tkVar, tkFor, tkIf, tkWhile}:
return return
parser.advance() parser.advance()
@ -157,6 +158,24 @@ proc parseTable(parser: Parser): Node =
parser.consume(tkRightBrace, "'}' expected after table declaration.") 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 = proc primary(parser: Parser): Node =
if parser.match(tkFalse): if parser.match(tkFalse):
return Node(kind: nkConst, constant: ndFalse) return Node(kind: nkConst, constant: ndFalse)
@ -182,6 +201,9 @@ proc primary(parser: Parser): Node =
result = parser.hold result = parser.hold
parser.hold = nil parser.hold = nil
return result return result
if parser.match(tkProc):
parser.consume(tkLeftParen, "'(' expected after 'proc'.")
return parser.parseProcDeclaration()
parser.errorAtCurrent("Primary expected, but something else found.") parser.errorAtCurrent("Primary expected, but something else found.")
@ -377,7 +399,6 @@ proc parseAssign(parser: Parser): Node =
# nkGetIndex # nkGetIndex
result = Node(kind: nkSetIndex, sCollection: result.gCollection, sIndex: result.gIndex, sValue: right) result = Node(kind: nkSetIndex, sCollection: result.gCollection, sIndex: result.gIndex, sValue: right)
proc parseAmpersand(parser: Parser): Node = proc parseAmpersand(parser: Parser): Node =
result = parser.parseAssign() result = parser.parseAssign()
if parser.match(tkAmpersand): 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 =
proc statement(parser: Parser): Node =
let expression = parser.expression() let expression = parser.expression()
if expression != nil: if expression != nil:
result = Node(kind: nkExprStmt, expression: expression) result = Node(kind: nkExprStmt, expression: expression)
else: else:
parser.errorAtCurrent("Expression expected.") 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: if parser.panicMode:
parser.synchronize() parser.synchronize()

View File

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