Skip to content

Commit

Permalink
little refactoring, add for statement
Browse files Browse the repository at this point in the history
  • Loading branch information
Ethosa committed Apr 8, 2024
1 parent e8ed48b commit 5d3d6d1
Show file tree
Hide file tree
Showing 6 changed files with 347 additions and 211 deletions.
1 change: 1 addition & 0 deletions src/elys.nim
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import
./elyspkg/lexer,
./elyspkg/parser,
./elyspkg/ast,
./elyspkg/result,
options


Expand Down
225 changes: 101 additions & 124 deletions src/elyspkg/ast.nim
Original file line number Diff line number Diff line change
@@ -1,91 +1,12 @@
import
./result,
macros,
strutils,
tables,
options


type
ASTKind* {.size: sizeof(int8).} = enum
akRoot,
akExpr, akNull, akInt, akFloat, akBool, akString, akArr, akVar, akBinOp, akUnaryOp,
akTernary, akBracketExpr, akSliceExpr, akNot,
akEof,
akStmt, akStmtList, akAssign, akPrint, akIncDec, akElifBranch, akElseBranch,
akIfStmt, akBreak, akContinue, akWhile, akAssignBracket, akSwap
ASTRoot* = ref object of RootObj
kind*: ASTKind

ASTExpr* = ref object of ASTRoot
NullAST* = ref object of ASTExpr
IntAST* = ref object of ASTExpr
val*: int
FloatAST* = ref object of ASTExpr
val*: float
BoolAST* = ref object of ASTExpr
val*: bool
StringAST* = ref object of ASTExpr
val*: string
ArrayAST* = ref object of ASTExpr
val*: seq[ASTRoot]
BracketExprAST* = ref object of ASTExpr
index*: ASTRoot
expr*: ASTRoot
indexes*: seq[ASTRoot]
SliceExprAST* = ref object of ASTExpr
l*, r*: ASTRoot
op*: string
VarAST* = ref object of ASTExpr
name*: string
BinOpAST* = ref object of ASTExpr
op*: string
l*, r*: ASTRoot
UnaryOpAST* = ref object of ASTExpr
op*: string
expr*: ASTRoot
TernaryOpAST* = ref object of ASTExpr
first*, second*, third*: ASTRoot
op1*, op2*: string
NotOp* = ref object of ASTExpr
expr*: ASTRoot

Stmt* = ref object of ASTRoot
EofStmt* = ref object of Stmt
StmtList* = ref object of Stmt
statements*: seq[ASTRoot]
parent*: ASTKind
AssignStmt* = ref object of Stmt
name*: string
expr*: ASTRoot
isConst*: bool
isAssign*: bool
assignOp*: string
AssignBracketStmt* = ref object of Stmt
expr*: BracketExprAST
val*: ASTRoot
op*: string
IncDecStmt* = ref object of Stmt
op*: string
expr*: ASTRoot
ElifBranchStmt* = ref object of Stmt
condition*: ASTRoot
body*: ASTRoot
ElseBranchStmt* = ref object of Stmt
body*: ASTRoot
IfStmt* = ref object of Stmt
condition*: ASTRoot
body*: ASTRoot
elifArray*: seq[ElifBranchStmt]
elseBranch*: Option[ElseBranchStmt]
WhileStmt* = ref object of Stmt
body*: ASTRoot
condition*: ASTRoot
SwapStmt* = ref object of Stmt
l*, r*: ASTRoot
toL*, toR*: ASTRoot
ContinueStmt* = ref object of Stmt
BreakStmt* = ref object of Stmt

type
SignalKind* {.size: sizeof(int8).} = enum
sNothing,
sBreak,
Expand Down Expand Up @@ -117,49 +38,6 @@ proc newEnv*(): Environment =
Environment(vars: newTable[string, EnvVar](), lvl: 0, modules: @[])


func `$`*(ast: ASTRoot): string =
case ast.kind:
of akNull: "NullAST()"
of akInt: "IntAST(" & $ast.IntAST.val & ")"
of akFloat: "FloatAST(" & $ast.FloatAST.val & ")"
of akString: "StringAST(" & $ast.StringAST.val & ")"
of akBool: "BoolAST(" & $ast.BoolAST.val & ")"
of akBinOp: "BinOpAST(" & $ast.BinOpAST.l & ", " & $ast.BinOpAST.r & ", " & ast.BinOpAST.op & ")"
of akVar: "VarAST(" & ast.VarAST.name & ")"
of akNot: "NotOp(" & $ast.NotOp.expr & ")"
of akEof: "EOFStmt()"
of akStmtList: "StmtList(" & ast.StmtList.statements.join(", ") & ")"
of akIncDec:
case ast.IncDecStmt.op:
of "++":
"Increment(" & $ast.IncDecStmt.expr & ")"
of "--":
"Decrement(" & $ast.IncDecStmt.expr & ")"
else:
""
of akElseBranch: "ElseBranchStmt(" & $ast.ElseBranchStmt.body & ")"
of akElifBranch: "ElifBranchStmt(" & $ast.ElifBranchStmt.condition & ", " & $ast.ElifBranchStmt.body & ")"
of akIfStmt:
"IfStmt(" & $ast.IfStmt.condition & ", " & $ast.IfStmt.body &
", [" & ast.IfStmt.elifArray.join(", ") & "], " &
$ast.IfStmt.elseBranch & ")"
of akWhile: "WhileStmt(" & $ast.WhileStmt.condition & ", " & $ast.WhileStmt.body & ")"
of akBreak: "BreakStmt()"
of akContinue: "ContinueStmt()"
of akArr: "ArrayAST(" & ast.ArrayAST.val.join(", ") & ")"
of akBracketExpr:
"BracketExprAST(" & $ast.BracketExprAST.expr & ", " &
$ast.BracketExprAST.index & ", " & $ast.BracketExprAST.indexes & ")"
of akSliceExpr:
"SliceExprAST(" & $ast.SliceExprAST.l & ast.SliceExprAST.op &
$ast.SliceExprAST.r & ")"
of akSwap:
"SwapStmt(" & $ast.SwapStmt.l & ", " & $ast.SwapStmt.r & " = " &
$ast.SwapStmt.toL & ", " & $ast.SwapStmt.toR & ")"
else:
"ASTRoot(kind: " & $ast.kind & ")"


macro evalFor(t, body: untyped) =
newProc(
postfix(ident"eval", "*"),
Expand Down Expand Up @@ -225,6 +103,9 @@ template elifBranchStmt*(c: ASTRoot, b: ASTRoot): ElifBranchStmt =
template elseBranchStmt*(b: ASTRoot): ElseBranchStmt =
ElseBranchStmt(body: b, kind: akElseBranch)

template printAst*(d: seq[Result]): PrintStmt =
PrintStmt(data: d, kind: akPrint)

template ifStmt*(c: ASTRoot, b: ASTRoot,
earr: seq[ElifBranchStmt], eb: Option[ElseBranchStmt]): IfStmt =
IfStmt(
Expand All @@ -238,13 +119,31 @@ template whileStmt*(c: ASTRoot, b: ASTRoot): WhileStmt =
condition: c, body: b, kind: akWhile
)

template forInStmt*(v: seq[ASTRoot], o, b: ASTRoot): ForInStmt =
ForInStmt(vars: v, obj: o, body: b, kind: akForInStmt)

template swap*(left, right, toLeft, toRight: ASTRoot): SwapStmt =
SwapStmt(l: left, r: right, toL: toLeft, toR: toRight, kind: akSwap)


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


func `[]=`*(env: Environment, key: string, value: ASTExpr) =
env.vars[key].val = value


func setDef*(env: Environment, key: string, value: ASTExpr) =
if env.vars.hasKey(key):
env.vars[key].val = value
else:
env.vars[key] = EnvVar(val: value)


func `[]`*(env: Environment, key: string): ASTExpr =
env.vars[key].val


func astName*(a: ASTRoot): string =
case a.kind:
of akInt: "int"
Expand Down Expand Up @@ -678,9 +577,24 @@ method eval*(self: WhileStmt, env: Environment): ASTRoot =
return nullAst()


method eval*(self: PrintStmt, env: Environment): ASTRoot =
var
res = ""
i = 0
while i < self.data.len:
if i == self.data.len-1:
res &= $self.data[i].ast.eval(env).astValue(env)
else:
res &= $self.data[i].ast.eval(env).astValue(env) & ", "
inc i
echo res
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
Expand All @@ -704,3 +618,66 @@ method eval*(self: SwapStmt, env: Environment): ASTRoot =
else:
raise newException(RuntimeError, "Can not swap this")
nullAst()

method eval*(self: ForInStmt, env: Environment): ASTRoot =
let
obj = self.obj.eval(env)
var
environment = newEnv(env)
# check for variables
for i in self.vars:
if i.kind != akVar:
raise newException(
RuntimeError,
"Can not iterate over " & self.obj.astValue(environment) &
" via " & i.astValue(environment)
)
case self.vars.len:
of 1:
let variable = self.vars[0].VarAST.name
case obj.kind:
of akArr:
for i in obj.ArrayAST.val:
environment.setDef(variable, i.eval(environment).ASTExpr)
discard self.body.eval(environment)
of akSliceExpr:
for i in obj.SliceExprAST.l.IntAST.val..obj.SliceExprAST.r.IntAST.val:
environment.setDef(variable, intAst(i))
discard self.body.eval(environment)
of akString:
for i in obj.StringAST.val:
environment.setDef(variable, stringAst($i))
discard self.body.eval(environment)
else:
raise newException(
RuntimeError,
"Can not unpack " & $self.vars.len & " variables from " &
self.obj.astValue(env)
)
of 2:
let
variable1 = self.vars[0].VarAST.name
variable2 = self.vars[1].VarAST.name
case obj.kind:
of akArr:
for (index, value) in obj.ArrayAST.val.pairs:
environment.setDef(variable2, value.eval(environment).ASTExpr)
environment.setDef(variable1, intAst(index))
discard self.body.eval(environment)
of akString:
for (index, value) in obj.StringAST.val.pairs:
environment.setDef(variable2, stringAst($value))
environment.setDef(variable1, intAst(index))
discard self.body.eval(environment)
else:
raise newException(
RuntimeError,
"Can not unpack " & $self.vars.len & " variables from " &
self.obj.astValue(env)
)
else:
raise newException(
RuntimeError,
"Can not unpack " & $self.vars.len & " variables from " &
self.obj.astValue(env)
)
88 changes: 1 addition & 87 deletions src/elyspkg/combinator.nim
Original file line number Diff line number Diff line change
@@ -1,41 +1,12 @@
import
./lexer,
./ast,
./result,
strutils,
options


type
ResultKind* {.size: sizeof(int8).} = enum
rkStr,
rkPair,
rkArr,
rkBool,
rkInt,
rkFloat,
rkFun,
rkAst
ResultFunc* = proc(res: Result): Option[Result]
Result* = ref object
case kind*: ResultKind
of rkStr:
val*: Option[string]
of rkPair:
valx*: Result
valy*: Result
of rkArr:
arr*: seq[Result]
of rkBool:
valb*: bool
of rkInt:
vali*: int
of rkFloat:
valf*: float
of rkFun:
valfn*: ResultFunc
of rkAst:
ast*: ASTRoot
pos*: int
ProcessFunc* = proc(val: Result): Option[Result]
LazyFunc* = proc(): Combinator
Combinator* = ref object of RootObj
Expand Down Expand Up @@ -67,10 +38,6 @@ type
Phrase* = ref object of Combinator
c*: Combinator

# AST help
PrintStmt* = ref object of Stmt
data: seq[Result]


func reserved*(val: string, kind: TokenKind): Reserved = Reserved(tkn: Token(value: val, kind: kind))
func tag*(kind: TokenKind): Tag = Tag(kind: kind)
Expand Down Expand Up @@ -99,59 +66,6 @@ method `$`*(c: Lazy): string = "Lazy(" & $c.c & ", func)"
method `$`*(c: Phrase): string = "Phrase(" & $c.c & ")"


func astRes*(ast: ASTRoot): Option[Result] =
Result(kind: rkAst, ast: ast).some

func fnRes*(function: ResultFunc): Option[Result] =
Result(
kind: rkFun,
valfn: function
).some

func getVal*(res: Result): string =
case res.kind:
of rkStr:
$res.val
of rkPair:
"(" & res.valx.getVal & ", " & res.valy.getVal & ")"
of rkArr:
var arr: seq[string] = @[]
for i in res.arr:
arr.add i.getVal
"[" & arr.join(", ") & "]"
of rkBool:
$res.valb
of rkInt:
$res.vali
of rkFloat:
$res.valf
of rkFun:
"function"
of rkAst:
$res.ast

func `$`*(res: Result): string =
"Result(" & res.getVal & ")"


# --== AST ==-- #
func printAst*(data: seq[Result]): PrintStmt =
PrintStmt(data: data, kind: akPrint)
method `$`*(ast: PrintStmt): string = "PrintStmt(" & $ast.data & ")"
method eval*(self: PrintStmt, env: Environment): ASTRoot =
var
res = ""
i = 0
while i < self.data.len:
if i == self.data.len-1:
res &= $self.data[i].ast.eval(env).astValue(env)
else:
res &= $self.data[i].ast.eval(env).astValue(env) & ", "
inc i
echo res
nullAst()


{.experimental: "callOperator".}

template `()`(obj: Combinator, tokens: seq[Token], pos: int): untyped =
Expand Down
Loading

0 comments on commit 5d3d6d1

Please sign in to comment.