Minor fixes and changes to the parser
This commit is contained in:
parent
37f35bec08
commit
68a6e2e83b
|
@ -21,12 +21,9 @@ import std/times
|
|||
import config
|
||||
import errors
|
||||
import multibyte
|
||||
import frontend/parsing/ast
|
||||
import frontend/compiler/targets/bytecode/opcodes
|
||||
|
||||
|
||||
export ast
|
||||
|
||||
type
|
||||
Serializer* = ref object
|
||||
file: string
|
||||
|
|
|
@ -24,7 +24,7 @@ import ast
|
|||
import token
|
||||
import errors
|
||||
import config
|
||||
import lexer as l
|
||||
import lexer
|
||||
import util/symbols
|
||||
|
||||
|
||||
|
@ -79,14 +79,14 @@ type
|
|||
# to either a FunDecl or LambdaExpr
|
||||
# AST node and is nil when the parser
|
||||
# is at the top-level. It allows the
|
||||
# parser to detect errors like return
|
||||
# outside functions
|
||||
# parser to detect errors like using
|
||||
# return outside functions
|
||||
currentFunction: Declaration
|
||||
# Stores the current scope depth (0 = global, > 0 local)
|
||||
scopeDepth: int
|
||||
# Operator table
|
||||
operators: OperatorTable
|
||||
# The AST node
|
||||
# The AST we're producing
|
||||
tree: seq[Declaration]
|
||||
# Stores line data
|
||||
lines: seq[tuple[start, stop: int]]
|
||||
|
@ -99,6 +99,7 @@ type
|
|||
# to avoid importing a module twice and to
|
||||
# detect recursive dependency cycles
|
||||
modules: TableRef[string, bool]
|
||||
|
||||
ParseError* = ref object of PeonException
|
||||
## A parsing exception
|
||||
parser*: Parser
|
||||
|
@ -203,9 +204,8 @@ proc done(self: Parser): bool {.inline.} =
|
|||
result = self.peek().kind == EndOfFile
|
||||
|
||||
|
||||
proc step(self: Parser, n: int = 1): Token {.inline.} =
|
||||
## Steps n tokens into the input,
|
||||
## returning the last consumed one
|
||||
proc step(self: Parser): Token {.inline.} =
|
||||
## Consumes a token and returns it
|
||||
if self.done():
|
||||
result = self.peek()
|
||||
else:
|
||||
|
@ -228,8 +228,7 @@ proc error(self: Parser, message: string, token: Token = nil) {.raises: [ParseEr
|
|||
# tell at tokenization time which of the two contexts we're in, we just treat everything
|
||||
# as a symbol and in the cases where we need a specific token we just match the string
|
||||
# directly
|
||||
proc check[T: TokenType or string](self: Parser, kind: T,
|
||||
distance: int = 0): bool {.inline.} =
|
||||
proc check[T: TokenType or string](self: Parser, kind: T, distance: int = 0): bool {.inline.} =
|
||||
## Checks if the given token at the given distance
|
||||
## matches the expected kind and returns a boolean.
|
||||
## The distance parameter is passed directly to
|
||||
|
@ -302,11 +301,9 @@ proc expect[T: TokenType or string](self: Parser, kind: openarray[T], message: s
|
|||
proc expression(self: Parser): Expression
|
||||
proc expressionStatement(self: Parser): Statement
|
||||
proc statement(self: Parser): Statement
|
||||
proc varDecl(self: Parser, isLet: bool = false,
|
||||
isConst: bool = false): Declaration
|
||||
proc varDecl(self: Parser, isLet: bool = false, isConst: bool = false): Declaration
|
||||
proc parseFunExpr(self: Parser): LambdaExpr
|
||||
proc funDecl(self: Parser, isAsync: bool = false, isGenerator: bool = false,
|
||||
isLambda: bool = false, isOperator: bool = false): Declaration
|
||||
proc funDecl(self: Parser, isAsync: bool = false, isGenerator: bool = false, isLambda: bool = false, isOperator: bool = false): Declaration
|
||||
proc declaration(self: Parser): Declaration
|
||||
proc parse*(self: Parser, tokens: seq[Token], file: string, lines: seq[tuple[start, stop: int]], source: string, persist: bool = false): seq[Declaration]
|
||||
proc findOperators(self: Parser, tokens: seq[Token])
|
||||
|
@ -416,7 +413,6 @@ proc makeCall(self: Parser, callee: Expression): CallExpr =
|
|||
while true:
|
||||
if argCount >= 255:
|
||||
self.error("can not pass more than 255 arguments in function call")
|
||||
break
|
||||
argument = self.expression()
|
||||
if argument.kind == assignExpr:
|
||||
var assign = AssignExpr(argument)
|
||||
|
@ -547,7 +543,7 @@ proc parseAnd(self: Parser): Expression =
|
|||
result = self.parseCmp()
|
||||
var operator: Token
|
||||
var right: Expression
|
||||
while self.check([Identifier, Symbol]) and self.operators.getPrecedence(self.peek().lexeme) == Precedence.And:
|
||||
while self.check([Identifier, Symbol]) and self.operators.getPrecedence(self.peek().lexeme) == And:
|
||||
operator = self.step()
|
||||
right = self.parseCmp()
|
||||
result = newBinaryExpr(result, operator, right)
|
||||
|
@ -559,7 +555,7 @@ proc parseOr(self: Parser): Expression =
|
|||
result = self.parseAnd()
|
||||
var operator: Token
|
||||
var right: Expression
|
||||
while self.check([Identifier, Symbol]) and self.operators.getPrecedence(self.peek().lexeme) == Precedence.Or:
|
||||
while self.check([Identifier, Symbol]) and self.operators.getPrecedence(self.peek().lexeme) == Or:
|
||||
operator = self.step()
|
||||
right = self.parseAnd()
|
||||
result = newBinaryExpr(result, operator, right)
|
||||
|
@ -588,7 +584,7 @@ proc parseArrow(self: Parser): Expression =
|
|||
result = self.parseAssign()
|
||||
var operator: Token
|
||||
var right: Expression
|
||||
while self.check([Identifier, Symbol]) and self.operators.getPrecedence(self.peek().lexeme) == Precedence.Arrow:
|
||||
while self.check([Identifier, Symbol]) and self.operators.getPrecedence(self.peek().lexeme) == Arrow:
|
||||
operator = self.step()
|
||||
right = self.parseAssign()
|
||||
result = newBinaryExpr(result, operator, right)
|
||||
|
@ -815,7 +811,7 @@ proc importStmt(self: Parser, fromStmt: bool = false): Statement =
|
|||
elif i == searchPath.high():
|
||||
self.error(&"""could not import '{path}': module not found""")
|
||||
if not self.modules.getOrDefault(path, true):
|
||||
self.error(&"coult not import '{path}' (recursive dependency detected)")
|
||||
self.error(&"coult not import '{path}' from '{self.file}' due to a cyclic dependency")
|
||||
else:
|
||||
self.modules[path] = false
|
||||
try:
|
||||
|
@ -940,8 +936,7 @@ proc parsePragmas(self: Parser): seq[Pragma] =
|
|||
elif self.match("("):
|
||||
while not self.match(")") and not self.done():
|
||||
exp = self.primary()
|
||||
if exp.kind notin {strExpr, intExpr, octExpr, binExpr, hexExpr, floatExpr,
|
||||
trueExpr, falseExpr}:
|
||||
if not exp.isConst():
|
||||
self.error("pragma arguments can only be literals", exp.token)
|
||||
args.add(LiteralExpr(exp))
|
||||
if not self.match(","):
|
||||
|
@ -949,8 +944,7 @@ proc parsePragmas(self: Parser): seq[Pragma] =
|
|||
self.expect(LeftParen, "unterminated parenthesis in pragma arguments")
|
||||
else:
|
||||
exp = self.primary()
|
||||
if exp.kind notin {strExpr, intExpr, octExpr, binExpr, hexExpr, floatExpr,
|
||||
trueExpr, falseExpr}:
|
||||
if not exp.isConst():
|
||||
self.error("pragma arguments can only be literals", exp.token)
|
||||
args.add(LiteralExpr(exp))
|
||||
result.add(newPragma(name, args))
|
||||
|
@ -990,14 +984,11 @@ proc varDecl(self: Parser, isLet: bool = false,
|
|||
pragmas.add(pragma)
|
||||
case tok.kind:
|
||||
of TokenType.Var:
|
||||
result = newVarDecl(name, value, isPrivate = isPrivate, token = tok,
|
||||
valueType = valueType, pragmas = (@[]))
|
||||
result = newVarDecl(name, value, isPrivate=isPrivate, token=tok, valueType=valueType, pragmas=(@[]))
|
||||
of Const:
|
||||
result = newVarDecl(name, value, isPrivate = isPrivate, token = tok,
|
||||
isConst = true, valueType = valueType, pragmas = (@[]))
|
||||
result = newVarDecl(name, value, isPrivate=isPrivate, token=tok, isConst=true, valueType=valueType, pragmas=(@[]))
|
||||
of Let:
|
||||
result = newVarDecl(name, value, isPrivate = isPrivate, token = tok,
|
||||
isLet = isLet, valueType = valueType, pragmas = (@[]))
|
||||
result = newVarDecl(name, value, isPrivate=isPrivate, token=tok, isLet=isLet, valueType=valueType, pragmas=(@[]))
|
||||
else:
|
||||
discard # Unreachable
|
||||
if not hasInit and VarDecl(result).valueType.isNil():
|
||||
|
@ -1064,7 +1055,7 @@ proc parseFunExpr(self: Parser): LambdaExpr =
|
|||
proc parseGenericConstraint(self: Parser): Expression =
|
||||
## Recursively parses a generic constraint
|
||||
## and returns it as an expression
|
||||
result = self.expression() # First value is always an identifier of some sort
|
||||
result = self.expression()
|
||||
if not self.check(RightBracket):
|
||||
case self.peek().lexeme:
|
||||
of "|":
|
||||
|
@ -1139,8 +1130,11 @@ proc funDecl(self: Parser, isAsync: bool = false, isGenerator: bool = false,
|
|||
elif isLambda:
|
||||
self.currentFunction = newLambdaExpr(arguments, defaults, newBlockStmt(@[], Token()), isGenerator=isGenerator, isAsync=isAsync, token=tok,
|
||||
returnType=nil, depth=self.scopeDepth)
|
||||
if self.match(LeftParen):
|
||||
var parameter: tuple[name: IdentExpr, valueType: Expression]
|
||||
self.parseDeclArguments(arguments, parameter, defaults)
|
||||
if self.match(":"):
|
||||
# Function has explicit return type
|
||||
# Function returns a value
|
||||
if self.match([Function, Coroutine, Generator]):
|
||||
# The function's return type is another
|
||||
# function. We specialize this case because
|
||||
|
@ -1150,15 +1144,6 @@ proc funDecl(self: Parser, isAsync: bool = false, isGenerator: bool = false,
|
|||
returnType = self.parseFunExpr()
|
||||
else:
|
||||
returnType = self.expression()
|
||||
if self.match(LeftParen):
|
||||
var parameter: tuple[name: IdentExpr, valueType: Expression]
|
||||
self.parseDeclArguments(arguments, parameter, defaults)
|
||||
if self.match(":"):
|
||||
# Function's return type
|
||||
if self.match([Function, Coroutine, Generator]):
|
||||
returnType = self.parseFunExpr()
|
||||
else:
|
||||
returnType = self.expression()
|
||||
if self.currentFunction.kind == funDecl:
|
||||
if not self.match(Semicolon):
|
||||
# If we don't find a semicolon,
|
||||
|
|
Loading…
Reference in New Issue