Skip to content

Commit

Permalink
add while statement
Browse files Browse the repository at this point in the history
  • Loading branch information
Ethosa committed Apr 7, 2024
1 parent 9acabd8 commit b0cdd13
Show file tree
Hide file tree
Showing 4 changed files with 138 additions and 7 deletions.
78 changes: 72 additions & 6 deletions src/elyspkg/ast.nim
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ type
akBinOpExpr, akRelativeOp, akAnd, akOr, akIn, akNot,
akEof,
akStmt, akStmtList, akAssign, akPrint, akIncDec, akElifBranch, akElseBranch,
akIfStmt
akIfStmt, akBreak, akContinue, akWhile
ASTRoot* = ref object of RootObj
kind*: ASTKind

Expand Down Expand Up @@ -58,6 +58,7 @@ type
EofStmt* = ref object of Stmt
StmtList* = ref object of Stmt
statements*: seq[ASTRoot]
parent*: ASTKind
AssignStmt* = ref object of Stmt
name*: string
expr*: ASTRoot
Expand All @@ -77,14 +78,24 @@ type
body*: ASTRoot
elifArray*: seq[ElifBranchStmt]
elseBranch*: Option[ElseBranchStmt]
WhileStmt* = ref object of Stmt
body*: ASTRoot
condition*: ASTRoot
ContinueStmt* = ref object of Stmt
BreakStmt* = ref object of Stmt

SignalKind* {.size: sizeof(int8).} = enum
sNothing,
sBreak,
sContinue
EnvVar* = ref object
val*: ASTExpr
isConst*: bool
Environment* = ref object
vars*: TableRef[string, EnvVar]
lvl*: int
modules*: seq[string]
signal*: SignalKind
RuntimeError* = object of ValueError


Expand All @@ -111,11 +122,22 @@ method `$`*(ast: OrOp): string = "OrOp(" & $ast.l & ", " & $ast.r & ")"
method `$`*(ast: InOp): string = "InOp(" & $ast.l & ", " & $ast.r & ")"
method `$`*(ast: RelativeOp): string = "RelativeOp(" & $ast.l & ", " & $ast.r & ", " & ast.op & ")"
method `$`*(ast: EofStmt): string = "EOFStmt()"
method `$`*(ast: StmtList): string =
var res = ""
for i in ast.statements:
res.add $i
"StmtList(" & res & ")"
method `$`*(ast: StmtList): string = "StmtList(" & ast.statements.join(", ") & ")"
method `$`*(ast: IncDecStmt): string =
case ast.op:
of "++":
return "Increment(" & $ast.expr & ")"
of "--":
return "Decrement(" & $ast.expr & ")"
method `$`*(ast: ElseBranchStmt): string = "ElseBranchStmt(" & $ast.body & ")"
method `$`*(ast: ElifBranchStmt): string = "ElifBranchStmt(" & $ast.condition & ", " & $ast.body & ")"
method `$`*(ast: IfStmt): string =
"IfStmt(" & $ast.condition & ", " & $ast.body &
", [" & ast.elifArray.join(", ") & "], " &
$ast.elseBranch & ")"
method `$`*(ast: WhileStmt): string = "WhileStmt(" & $ast.condition & ", " & $ast.body & ")"
method `$`*(ast: BreakStmt): string = "BreakStmt()"
method `$`*(ast: ContinueStmt): string = "ContinueStmt()"


macro evalFor(t, body: untyped) =
Expand Down Expand Up @@ -181,6 +203,17 @@ proc ifStmt*(condition: ASTRoot, body: ASTRoot,
kind: akIfStmt
)

proc whileStmt*(condition: ASTRoot, body: ASTRoot): WhileStmt =
WhileStmt(
condition: condition, body: body, kind: akWhile
)

proc continueStmt*: ContinueStmt =
ContinueStmt(kind: akContinue)

proc breakStmt*: BreakStmt =
BreakStmt(kind: akBreak)


method eval*(self: ASTRoot, env: Environment): ASTRoot {.base.} = nullAst()

Expand Down Expand Up @@ -407,6 +440,10 @@ method eval*(self: StmtList, env: Environment): ASTRoot =
var environment = newEnv(env)
for s in self.statements:
result = s.eval(environment)
env.signal = environment.signal
if env.signal in {sContinue, sBreak}:
break
return result

method eval(self: BinOpAST, env: Environment): ASTRoot =
let
Expand Down Expand Up @@ -473,11 +510,40 @@ method eval*(self: AssignStmt, env: Environment): ASTRoot =
method eval*(self: IfStmt, env: Environment): ASTRoot =
var cond = self.condition.eval(env)
if cond.toBoolean(env).BoolAST.val:
self.body.StmtList.parent = akIfStmt
return self.body.eval(env)
if self.elifArray.len > 0:
for i in self.elifArray:
cond = i.condition.eval(env)
if cond.toBoolean(env).BoolAST.val:
i.body.StmtList.parent = akIfStmt
return i.body.eval(env)
if self.elseBranch.isSome:
self.elseBranch.get.body.StmtList.parent = akIfStmt
return self.elseBranch.get.body.eval(env)
return nullAst()


method eval*(self: WhileStmt, env: Environment): ASTRoot =
var res: ASTRoot
self.body.StmtList.parent = akWhile
while self.condition.eval(env).BoolAST.val:
res = self.body.eval(env)
case env.signal:
of sContinue:
env.signal = sNothing
continue
of sBreak:
env.signal = sNothing
break
else:
discard
return nullAst()


method eval*(self: BreakStmt, env: Environment): ASTRoot =
env.signal = sBreak
return self
method eval*(self: ContinueStmt, env: Environment): ASTRoot =
env.signal = sContinue
return self
2 changes: 1 addition & 1 deletion src/elyspkg/lexer.nim
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ func parseForTokens*(source: string): seq[Token] =
elif src.findRe(re2"^(\b(true|false|on|off)\b)", m):
result.add tkn(src, m, i, tkBool)
# Keywords
elif src.findRe(re2"^(\b(if|elif|else|while|for|case|of|var|const)\b)", m):
elif src.findRe(re2"^(\b(if|elif|else|while|for|case|of|var|const|continue|break)\b)", m):
result.add tkn(src, m, i, tkKeyword)
elif src.findRe(re2"^(\b(print|null)\b)", m):
result.add tkn(src, m, i, tkKeyword)
Expand Down
32 changes: 32 additions & 0 deletions src/elyspkg/parser.nim
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ proc incDecStatement(): Combinator
proc unaryOperatorStmt(): Combinator
proc stmtList(): Combinator
proc ifStatement(): Combinator
proc stmtListEmbed(): Combinator


proc exprGroup(): Combinator =
Expand All @@ -97,6 +98,7 @@ proc exprTerm(): Combinator =
(
exprGroup() |
lazy(ifStatement) |
lazy(stmtListEmbed) |
incDecStatement() |
unaryOperatorStmt() |
bExprNot() |
Expand Down Expand Up @@ -239,14 +241,44 @@ proc incDecStatement(): Combinator =
) ^ processIncDec


proc stmtListEmbed(): Combinator =
(operator("{") + opt(lazy(stmtList)) + operator("}")) ^ processGroup


proc processWhileStatement(res: Result): Option[Result] =
astRes(whileStmt(res.valx.valy.ast, res.valy.ast))
proc whileStatement(): Combinator =
(
keyword("while") + alt(
(operator("(") + expr() + operator(")")) ^ processGroup,
expr(),
) + (operator("{") + opt(lazy(stmtList)) + operator("}")) ^ processGroup
) ^ processWhileStatement


proc processBreakStatement(res: Result): Option[Result] =
astRes(breakStmt())
proc breakStatement(): Combinator =
keyword("break") ^ processBreakStatement


proc processContinueStatement(res: Result): Option[Result] =
astRes(continueStmt())
proc continueStatement(): Combinator =
keyword("continue") ^ processContinueStatement


proc stmt(): Combinator =
(
ifStatement() |
whileStatement() |
printStmt() |
assignStmt() |
assignConstStmt() |
reAssignStmt() |
incDecStatement() |
breakStatement() |
continueStatement() |
expr() |
(tag(TokenKind.tkEof) ^ processEof)
)
Expand Down
33 changes: 33 additions & 0 deletions tests/test.nim
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,28 @@ import


suite "Elys":

test "Variables":
exec("""
# Here we just declare variables
var x = 10
var y = 20
""")

test "Basic math":
exec("""
print -5 + 10
print 2 + 2 * 2 / -10 * .1
""")

test "increment / decrement":
exec("""
var x = 10
print x
print x++
print ++x
""")

test "Basic bool operations":
exec("""
var x = true
Expand All @@ -31,6 +35,7 @@ suite "Elys":
print x and y, x or y
print 2 + 2 * 2 == 6, (2 + 2) * 2 == 8
""")

test "if-elif-else bool operations":
exec("""
if 0 {
Expand Down Expand Up @@ -58,3 +63,31 @@ suite "Elys":
var x = if ("") {0} elif (true) {"hello"} else {.0}
print x
""")

test "embedded statements":
exec("""
var x = {
10
}
print x
""")

test "while statement":
exec("""
var y = 0
print {
var x = 0
while x < 10 {
x++
if x % 2 == 0 {
y++
continue
}
if x == 7 {
break
}
}
x
}
print y
""")

0 comments on commit b0cdd13

Please sign in to comment.