Wired up the parser
This commit is contained in:
parent
21fda63fad
commit
7f950893c5
|
@ -74,7 +74,7 @@ type
|
|||
scopeDepth: int
|
||||
|
||||
|
||||
proc initParser*(): Parser =
|
||||
proc newParser*(): Parser =
|
||||
## Initializes a new Parser object
|
||||
new(result)
|
||||
result.current = 0
|
||||
|
@ -327,7 +327,7 @@ proc primary(self: Parser): ASTNode =
|
|||
|
||||
proc makeCall(self: Parser, callee: ASTNode): ASTNode =
|
||||
## Utility function called iteratively by self.call()
|
||||
## to parse a function-like call
|
||||
## to parse a function call
|
||||
let tok = self.peek(-1)
|
||||
var argNames: seq[ASTNode] = @[]
|
||||
var arguments: tuple[positionals: seq[ASTNode], keyword: seq[tuple[name: ASTNode, value: ASTNode]]] = (positionals: @[], keyword: @[])
|
||||
|
@ -347,7 +347,7 @@ proc makeCall(self: Parser, callee: ASTNode): ASTNode =
|
|||
elif arguments.keyword.len() == 0:
|
||||
arguments.positionals.add(argument)
|
||||
else:
|
||||
self.error("positional arguments cannot follow keyword arguments in call")
|
||||
self.error("positional argument(s) cannot follow keyword argument(s) in call")
|
||||
if not self.match(Comma):
|
||||
break
|
||||
argCount += 1
|
||||
|
@ -392,7 +392,7 @@ proc pow(self: Parser): ASTNode =
|
|||
result = self.unary()
|
||||
var operator: Token
|
||||
var right: ASTNode
|
||||
while self.match(DoubleAsterisk):
|
||||
while self.match(DoubleStar):
|
||||
operator = self.peek(-1)
|
||||
right = self.unary()
|
||||
result = newBinaryExpr(result, operator, right)
|
||||
|
@ -403,7 +403,7 @@ proc mul(self: Parser): ASTNode =
|
|||
result = self.pow()
|
||||
var operator: Token
|
||||
var right: ASTNode
|
||||
while self.match([Slash, Percentage, FloorDiv, Asterisk]):
|
||||
while self.match([Slash, Percentage, FloorDiv, Star]):
|
||||
operator = self.peek(-1)
|
||||
right = self.pow()
|
||||
result = newBinaryExpr(result, operator, right)
|
||||
|
@ -421,7 +421,8 @@ proc add(self: Parser): ASTNode =
|
|||
|
||||
|
||||
proc comparison(self: Parser): ASTNode =
|
||||
## Parses comparison expressions
|
||||
## Parses other comparison expressions
|
||||
## and some other operators
|
||||
result = self.add()
|
||||
var operator: Token
|
||||
var right: ASTNode
|
||||
|
@ -443,7 +444,8 @@ proc equality(self: Parser): ASTNode =
|
|||
|
||||
|
||||
proc logicalAnd(self: Parser): ASTNode =
|
||||
## Parses logical AND expressions
|
||||
## Parses logical and expressions
|
||||
## (a and b)
|
||||
result = self.equality()
|
||||
var operator: Token
|
||||
var right: ASTNode
|
||||
|
@ -454,7 +456,8 @@ proc logicalAnd(self: Parser): ASTNode =
|
|||
|
||||
|
||||
proc logicalOr(self: Parser): ASTNode =
|
||||
## Parses logical OR expressions
|
||||
## Parses logical or expressions
|
||||
## (a or b)
|
||||
result = self.logicalAnd()
|
||||
var operator: Token
|
||||
var right: ASTNode
|
||||
|
@ -465,7 +468,7 @@ proc logicalOr(self: Parser): ASTNode =
|
|||
|
||||
|
||||
proc bitwiseAnd(self: Parser): ASTNode =
|
||||
## Parser a & b expressions
|
||||
## Parses a & b expressions
|
||||
result = self.logicalOr()
|
||||
var operator: Token
|
||||
var right: ASTNode
|
||||
|
@ -476,7 +479,7 @@ proc bitwiseAnd(self: Parser): ASTNode =
|
|||
|
||||
|
||||
proc bitwiseOr(self: Parser): ASTNode =
|
||||
## Parser a | b expressions
|
||||
## Parses a | b expressions
|
||||
result = self.bitwiseAnd()
|
||||
var operator: Token
|
||||
var right: ASTNode
|
||||
|
@ -504,30 +507,6 @@ proc assignment(self: Parser): ASTNode =
|
|||
self.error("invalid assignment target")
|
||||
|
||||
|
||||
proc delStmt(self: Parser): ASTNode =
|
||||
## Parses "del" statements,
|
||||
## which unbind a name from its
|
||||
## value in the current scope and
|
||||
## calls its destructor
|
||||
let tok = self.peek(-1)
|
||||
var expression = self.expression()
|
||||
var temp = expression
|
||||
endOfLIne("missing semicolon after del statement")
|
||||
if expression.kind == groupingExpr:
|
||||
# We unpack grouping expressions
|
||||
temp = self.unnest(temp)
|
||||
if temp.isLiteral():
|
||||
self.error("cannot delete a literal")
|
||||
elif temp.kind in {binaryExpr, unaryExpr}:
|
||||
self.error("cannot delete operator")
|
||||
elif temp.kind == callExpr:
|
||||
self.error("cannot delete function call")
|
||||
elif temp.kind == assignExpr:
|
||||
self.error("cannot delete assignment")
|
||||
else:
|
||||
result = newDelStmt(expression, tok)
|
||||
|
||||
|
||||
proc assertStmt(self: Parser): ASTNode =
|
||||
## Parses "assert" statements,
|
||||
## raise an error if the expression
|
||||
|
@ -669,25 +648,6 @@ proc importStmt(self: Parser): ASTNode =
|
|||
endOfLine("missing semicolon after import statement")
|
||||
|
||||
|
||||
proc fromStmt(self: Parser): ASTNode =
|
||||
## Parser from xx import yy statements
|
||||
let tok = self.peek(-1)
|
||||
self.expect(Identifier, "expecting module name(s) after import statement")
|
||||
result = newIdentExpr(self.peek(-1))
|
||||
var attributes: seq[ASTNode] = @[]
|
||||
var attribute: ASTNode
|
||||
self.expect(Import)
|
||||
self.expect(Identifier)
|
||||
attribute = newIdentExpr(self.peek(-1))
|
||||
attributes.add(attribute)
|
||||
while self.match(Comma):
|
||||
self.expect(Identifier)
|
||||
attribute = newIdentExpr(self.peek(-1))
|
||||
attributes.add(attribute)
|
||||
# from x import a [, b, c, ...];
|
||||
endOfLine("missing semicolon after import statement")
|
||||
result = newFromImportStmt(result, attributes, tok)
|
||||
|
||||
|
||||
proc tryStmt(self: Parser): ASTNode =
|
||||
## Parses try/except/finally/else blocks
|
||||
|
@ -769,21 +729,6 @@ proc forStmt(self: Parser): ASTNode =
|
|||
# messages
|
||||
if self.match(Semicolon):
|
||||
discard
|
||||
elif self.match(Dynamic):
|
||||
self.error("dynamic declarations are not allowed in the foor loop initializer")
|
||||
elif self.match(Public):
|
||||
self.error("public declarations are not allowed in the for loop initializer")
|
||||
elif self.match(Static):
|
||||
self.expect(Var, "expecting 'var' after 'static' in for loop initializer")
|
||||
initializer = self.varDecl(isStatic=true, isPrivate=true)
|
||||
elif self.match(Private):
|
||||
if self.match(Dynamic):
|
||||
self.error("dynamic declarations are not allowed in the foor loop initializer")
|
||||
elif self.match(Static):
|
||||
self.expect(Var, "expecting 'var' after 'static' in for loop initializer")
|
||||
initializer = self.varDecl(isStatic=true, isPrivate=true)
|
||||
elif self.match(Var):
|
||||
initializer = self.varDecl(isStatic=true, isPrivate=true)
|
||||
elif self.match(Var):
|
||||
initializer = self.varDecl(isStatic=true, isPrivate=true)
|
||||
else:
|
||||
|
@ -933,23 +878,6 @@ proc funDecl(self: Parser, isAsync: bool = false, isStatic: bool = true, isPriva
|
|||
self.currentFunction = enclosingFunction
|
||||
|
||||
|
||||
proc classDecl(self: Parser, isStatic: bool = true, isPrivate: bool = true): ASTNode =
|
||||
## Parses class declarations
|
||||
self.checkDecl(isStatic, isPrivate)
|
||||
let tok = self.peek(-1)
|
||||
var parents: seq[ASTNode] = @[]
|
||||
self.expect(Identifier)
|
||||
var name = newIdentExpr(self.peek(-1))
|
||||
if self.match(LessThan):
|
||||
while true:
|
||||
self.expect(Identifier)
|
||||
parents.add(newIdentExpr(self.peek(-1)))
|
||||
if not self.match(Comma):
|
||||
break
|
||||
self.expect(LeftBrace)
|
||||
result = newClassDecl(name, self.blockStmt(), isPrivate=isPrivate, isStatic=isStatic, parents=parents, token=tok, owner=self.file, closedOver=false)
|
||||
|
||||
|
||||
proc expression(self: Parser): ASTNode =
|
||||
## Parses expressions
|
||||
result = self.assignment()
|
||||
|
@ -969,9 +897,6 @@ proc statement(self: Parser): ASTNode =
|
|||
of If:
|
||||
discard self.step()
|
||||
result = self.ifStmt()
|
||||
of Del:
|
||||
discard self.step()
|
||||
result = self.delStmt()
|
||||
of Assert:
|
||||
discard self.step()
|
||||
result = self.assertStmt()
|
||||
|
@ -990,9 +915,6 @@ proc statement(self: Parser): ASTNode =
|
|||
of Import:
|
||||
discard self.step()
|
||||
result = self.importStmt()
|
||||
of From:
|
||||
discard self.step()
|
||||
result = self.fromStmt()
|
||||
of While:
|
||||
discard self.step()
|
||||
result = self.whileStmt()
|
||||
|
@ -1024,62 +946,14 @@ proc statement(self: Parser): ASTNode =
|
|||
proc declaration(self: Parser): ASTNode =
|
||||
## Parses declarations
|
||||
case self.peek().kind:
|
||||
of Var, Const:
|
||||
of Var, Const, Let:
|
||||
discard self.step()
|
||||
result = self.varDecl()
|
||||
of Class:
|
||||
discard self.step()
|
||||
result = self.classDecl()
|
||||
of Fun:
|
||||
of Function:
|
||||
discard self.step()
|
||||
result = self.funDecl()
|
||||
of Private, Public:
|
||||
discard self.step()
|
||||
var isStatic: bool = true
|
||||
let isPrivate = if self.peek(-1).kind == Private: true else: false
|
||||
if self.match(Dynamic):
|
||||
isStatic = false
|
||||
elif self.match(Static):
|
||||
discard # This is just to allow an "explicit" static keyword
|
||||
if self.match(Async):
|
||||
result = self.funDecl(isStatic=isStatic, isPrivate=isPrivate, isAsync=true)
|
||||
else:
|
||||
case self.peek().kind:
|
||||
of Var, Const:
|
||||
discard self.step()
|
||||
result = self.varDecl(isStatic=isStatic, isPrivate=isPrivate)
|
||||
of Class:
|
||||
discard self.step()
|
||||
result = self.classDecl(isStatic=isStatic, isPrivate=isPrivate)
|
||||
of Fun:
|
||||
discard self.step()
|
||||
result = self.funDecl(isStatic=isStatic, isPrivate=isPrivate)
|
||||
else:
|
||||
self.error("expecting declaration")
|
||||
of Static, Dynamic:
|
||||
discard self.step()
|
||||
let isStatic: bool = if self.peek(-1).kind == Static: true else: false
|
||||
if self.match(Async):
|
||||
self.expect(Fun)
|
||||
result = self.funDecl(isStatic=isStatic, isPrivate=true, isAsync=true)
|
||||
else:
|
||||
case self.peek().kind:
|
||||
of Var, Const:
|
||||
discard self.step()
|
||||
result = self.varDecl(isStatic=isStatic, isPrivate=true)
|
||||
of Class:
|
||||
discard self.step()
|
||||
result = self.classDecl(isStatic=isStatic, isPrivate=true)
|
||||
of Fun:
|
||||
discard self.step()
|
||||
result = self.funDecl(isStatic=isStatic, isPrivate=true)
|
||||
else:
|
||||
self.error("expecting declaration")
|
||||
of Async:
|
||||
discard self.step()
|
||||
self.expect(Fun)
|
||||
result = self.funDecl(isAsync=true)
|
||||
|
||||
of Type:
|
||||
discard # TODO
|
||||
else:
|
||||
result = self.statement()
|
||||
|
||||
|
|
75
src/test.nim
75
src/test.nim
|
@ -1,4 +1,61 @@
|
|||
import sequtils
|
||||
|
||||
import frontend/lexer
|
||||
import frontend/parser as p
|
||||
import jale/editor
|
||||
import jale/templates
|
||||
import jale/plugin/defaults
|
||||
import jale/plugin/editor_history
|
||||
import jale/keycodes
|
||||
import jale/multiline
|
||||
|
||||
proc fillSymbolTable(tokenizer: Lexer)
|
||||
|
||||
|
||||
proc getLineEditor: LineEditor =
|
||||
result = newLineEditor()
|
||||
result.prompt = "=> "
|
||||
result.populateDefaults() # Setup default keybindings
|
||||
let hist = result.plugHistory() # Create history object
|
||||
result.bindHistory(hist) # Set default history keybindings
|
||||
|
||||
|
||||
|
||||
when isMainModule:
|
||||
setControlCHook(proc () {.noconv.} = quit(0))
|
||||
var keep = true
|
||||
var tokens: seq[Token] = @[]
|
||||
var tokenizer = newLexer()
|
||||
var parser = newParser()
|
||||
let lineEditor = getLineEditor()
|
||||
var input: string
|
||||
lineEditor.bindEvent(jeQuit):
|
||||
keep = false
|
||||
lineEditor.bindKey("ctrl+a"):
|
||||
lineEditor.content.home()
|
||||
lineEditor.bindKey("ctrl+e"):
|
||||
lineEditor.content.`end`()
|
||||
tokenizer.fillSymbolTable()
|
||||
while keep:
|
||||
try:
|
||||
input = lineEditor.read()
|
||||
if input.len() > 0:
|
||||
tokens = filter(tokenizer.lex(input, "<stdin>"), proc (x: Token): bool = x.kind notin {Whitespace, Tab})
|
||||
for i, token in tokens:
|
||||
if i == tokens.high():
|
||||
# Who cares about EOF?
|
||||
break
|
||||
echo token
|
||||
for node in parser.parse(tokens, "<stdin>"):
|
||||
echo node
|
||||
except IOError:
|
||||
break
|
||||
except LexingError:
|
||||
echo getCurrentExceptionMsg()
|
||||
except ParseError:
|
||||
echo getCurrentExceptionMsg()
|
||||
quit(0)
|
||||
|
||||
|
||||
|
||||
proc fillSymbolTable(tokenizer: Lexer) =
|
||||
|
@ -106,21 +163,3 @@ proc fillSymbolTable(tokenizer: Lexer) =
|
|||
# intrernally). You can add/remove symbols (and keywords
|
||||
# for that matter) as you like!
|
||||
|
||||
|
||||
when isMainModule:
|
||||
setControlCHook(proc () {.noconv.} = quit(0))
|
||||
var tokenizer = newLexer()
|
||||
tokenizer.fillSymbolTable()
|
||||
while true:
|
||||
try:
|
||||
stdout.write("> ")
|
||||
for token in tokenizer.lex(stdin.readLine(), "<stdin>"):
|
||||
if token.kind notin [Whitespace, Tab]:
|
||||
# Reduces clutter in the output
|
||||
echo token
|
||||
except IOError:
|
||||
break
|
||||
except LexingError:
|
||||
echo getCurrentExceptionMsg()
|
||||
echo ""
|
||||
quit(0)
|
||||
|
|
Loading…
Reference in New Issue