Skip to content

Commit

Permalink
add swap support
Browse files Browse the repository at this point in the history
  • Loading branch information
Ethosa committed Apr 7, 2024
1 parent 02c03c7 commit 0e308d2
Show file tree
Hide file tree
Showing 7 changed files with 268 additions and 177 deletions.
2 changes: 1 addition & 1 deletion elys.nimble
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

description = "Little scripting language"
author = "HapticX"
version = "0.3.0"
version = "0.4.0"
license = "MIT"
srcDir = "src"
installExt = @["nim"]
Expand Down
25 changes: 25 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,28 @@ Thanks to its compact implementation, **Elys** can be embedded into Minecraft mo
With its simple syntax, **Elys** is an excellent choice for rapid prototyping and building extensible systems.

It provides easy interaction with the host application and straightforward handling of tasks such as data management, interface control, and process automation.


## Hello, world! 👋

Here's hello world program written in **Elys**:
```elys
print('Hello, world!')
```


## Variables

**Elys** supports two types of variables - `var` and `const`.

`var` is mutable variable. `const` is immutable variable

### Example

```elys
var x = 10
const y = 20
x = 20 # success
y = 10 # error
```
8 changes: 6 additions & 2 deletions src/elys.nim
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ when isMainModule:
terminal


proc exec*(code: string) =
func compile(code: string): ASTRoot =
let tokens = code.parseForTokens
# echo tokens
let parsed = tokens.elysParser
Expand All @@ -19,8 +19,12 @@ proc exec*(code: string) =
discard parsed.get.ast.eval(env)


func exec*(code: string): ASTRoot {.discardable, exportc.} =
compile(code)


when isMainModule:
const VERSION = "0.3.0"
const VERSION = "0.4.0"

styledEcho fgRed, " _ "
styledEcho fgRed, " ___| |_ _ ___ "
Expand Down
124 changes: 72 additions & 52 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, akBreak, akContinue, akWhile, akAssignBracket
akIfStmt, akBreak, akContinue, akWhile, akAssignBracket, akSwap
ASTRoot* = ref object of RootObj
kind*: ASTKind

Expand Down Expand Up @@ -92,6 +92,9 @@ type
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

Expand Down Expand Up @@ -162,6 +165,8 @@ method `$`*(ast: BracketExprAST): string =
"BracketExprAST(" & $ast.expr & ", " & $ast.index & ", " & $ast.indexes & ")"
method `$`*(ast: SliceExprAST): string =
"SliceExprAST(" & $ast.l & ast.op & $ast.r & ")"
method `$`*(ast: SwapStmt): string =
"SwapStmt(" & $ast.l & ", " & $ast.r & " = " & $ast.toL & ", " & $ast.toR & ")"


macro evalFor(t, body: untyped) =
Expand All @@ -177,43 +182,43 @@ macro evalFor(t, body: untyped) =
)


proc nullAst*(): NullAST = NullAST(kind: akNull)
proc eofStmt*(): EofStmt = EofStmt(kind: akEof)
func nullAst*(): NullAST = NullAST(kind: akNull)
func eofStmt*(): EofStmt = EofStmt(kind: akEof)

proc intAst*(val: int): IntAST = IntAST(val: val, kind: akInt)
proc floatAst*(val: float): FloatAST = FloatAST(val: val, kind: akFloat)
proc stringAst*(val: string): StringAST = StringAST(val: val, kind: akString)
proc boolAst*(val: bool): BoolAST = BoolAST(val: val, kind: akBool)
func intAst*(val: int): IntAST = IntAST(val: val, kind: akInt)
func floatAst*(val: float): FloatAST = FloatAST(val: val, kind: akFloat)
func stringAst*(val: string): StringAST = StringAST(val: val, kind: akString)
func boolAst*(val: bool): BoolAST = BoolAST(val: val, kind: akBool)

proc arrAst*(val: seq[ASTRoot]): ArrayAST =
func arrAst*(val: seq[ASTRoot]): ArrayAST =
ArrayAST(val: val, kind: akArr)

proc bracket*(expr, index: ASTRoot, indexes: seq[ASTRoot]): BracketExprAST =
func bracket*(expr, index: ASTRoot, indexes: seq[ASTRoot]): BracketExprAST =
BracketExprAST(index: index, expr: expr, indexes: indexes, kind: akBracketExpr)

proc slice*(l, r: ASTRoot, op: string): SliceExprAST =
func slice*(l, r: ASTRoot, op: string): SliceExprAST =
SliceExprAST(l: l, r: r, op: op, kind: akSliceExpr)

proc unaryOpAst*(expr: ASTRoot, op: string): UnaryOpAST =
func unaryOpAst*(expr: ASTRoot, op: string): UnaryOpAST =
UnaryOpAST(kind: akUnaryOp, expr: expr, op: op)

proc incDecStmt*(expr: ASTRoot, op: string): IncDecStmt =
func incDecStmt*(expr: ASTRoot, op: string): IncDecStmt =
IncDecStmt(kind: akIncDec, expr: expr, op: op)

proc varAst*(val: string): VarAST = VarAST(name: val, kind: akVar)
func varAst*(val: string): VarAST = VarAST(name: val, kind: akVar)

proc binOpAst*(l, r: ASTRoot, op: string): BinOpAST =
func binOpAst*(l, r: ASTRoot, op: string): BinOpAST =
BinOpAST(l: l, r: r, op: op, kind: akBinOp)

proc relOp*(l, r: ASTRoot, op: string): RelativeOp =
func relOp*(l, r: ASTRoot, op: string): RelativeOp =
RelativeOp(l: l, r: r, op: op, kind: akRelativeOp)
proc notAst*(expr: ASTRoot): NotOp =
func notAst*(expr: ASTRoot): NotOp =
NotOp(expr: expr, kind: akNot)

proc statementList*(stmts: seq[ASTRoot]): StmtList =
func statementList*(stmts: seq[ASTRoot]): StmtList =
StmtList(statements: stmts, kind: akStmtList)

proc assignStmtAst*(name: string, expr: ASTRoot,
func assignStmtAst*(name: string, expr: ASTRoot,
isConst: bool = false, isAssign: bool = false,
assignOp: string = "="): AssignStmt =
AssignStmt(
Expand All @@ -222,39 +227,42 @@ proc assignStmtAst*(name: string, expr: ASTRoot,
kind: akAssign
)

proc assignBracket*(expr: BracketExprAST, val: ASTRoot, op: string): AssignBracketStmt =
func assignBracket*(expr: BracketExprAST, val: ASTRoot, op: string): AssignBracketStmt =
AssignBracketStmt(expr: expr, val: val, kind: akAssignBracket, op: op[1..^1])

proc elifBranchStmt*(condition: ASTRoot, body: ASTRoot): ElifBranchStmt =
func elifBranchStmt*(condition: ASTRoot, body: ASTRoot): ElifBranchStmt =
ElifBranchStmt(condition: condition, body: body, kind: akElifBranch)

proc elseBranchStmt*(body: ASTRoot): ElseBranchStmt =
func elseBranchStmt*(body: ASTRoot): ElseBranchStmt =
ElseBranchStmt(body: body, kind: akElseBranch)

proc ifStmt*(condition: ASTRoot, body: ASTRoot,
func ifStmt*(condition: ASTRoot, body: ASTRoot,
elifArray: seq[ElifBranchStmt], elseBranch: Option[ElseBranchStmt]): IfStmt =
IfStmt(
condition: condition, body: body,
elifArray: elifArray, elseBranch: elseBranch,
kind: akIfStmt
)

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

proc continueStmt*: ContinueStmt =
func swap*(l, r, toL, toR: ASTRoot): SwapStmt =
SwapStmt(l: l, r: r, toL: toL, toR: toR, kind: akSwap)

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

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


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


proc astName*(a: ASTRoot): string =
func astName*(a: ASTRoot): string =
case a.kind:
of akInt: "int"
of akFloat: "float"
Expand All @@ -266,7 +274,7 @@ proc astName*(a: ASTRoot): string =
else: "object"


proc astValue*(a: ASTRoot, env: Environment): string =
func astValue*(a: ASTRoot, env: Environment): string =
case a.kind:
of akInt: $a.IntAST.val
of akFloat: $a.FloatAST.val
Expand All @@ -290,7 +298,7 @@ proc astValue*(a: ASTRoot, env: Environment): string =
else: "object"


proc toBoolean*(a: ASTRoot, env: Environment): ASTRoot =
func toBoolean*(a: ASTRoot, env: Environment): ASTRoot =
case a.kind:
of akBool:
return a
Expand All @@ -308,7 +316,7 @@ proc toBoolean*(a: ASTRoot, env: Environment): ASTRoot =
raise newException(RuntimeError, "Can not get boolean from " & $a.astValue(env))


proc `+`(a, b: ASTRoot): ASTRoot =
func `+`(a, b: ASTRoot): ASTRoot =
if a.kind == akInt and b.kind == akInt:
return intAst(a.IntAST.val + b.IntAST.val)
elif a.kind == akInt and b.kind == akFloat:
Expand All @@ -323,7 +331,7 @@ proc `+`(a, b: ASTRoot): ASTRoot =
raise newException(ValueError, "Cannot plus " & a.astName & " to " & b.astName)


proc `-`(a, b: ASTRoot): ASTRoot =
func `-`(a, b: ASTRoot): ASTRoot =
if a.kind == akInt and b.kind == akInt:
return intAst(a.IntAST.val - b.IntAST.val)
elif a.kind == akInt and b.kind == akFloat:
Expand All @@ -336,7 +344,7 @@ proc `-`(a, b: ASTRoot): ASTRoot =
raise newException(ValueError, "Cannot minus " & b.astName & " from " & a.astName)


proc `*`*(a, b: ASTRoot): ASTRoot =
func `*`*(a, b: ASTRoot): ASTRoot =
if a.kind == akInt and b.kind == akInt:
return intAst(a.IntAST.val * b.IntAST.val)
elif a.kind == akInt and b.kind == akFloat:
Expand All @@ -351,7 +359,7 @@ proc `*`*(a, b: ASTRoot): ASTRoot =
raise newException(ValueError, "Cannot multiply " & a.astName & " by " & b.astName)


proc `/`*(a, b: ASTRoot): ASTRoot =
func `/`*(a, b: ASTRoot): ASTRoot =
if a.kind == akInt and b.kind == akInt:
return floatAST(a.IntAST.val / b.IntAST.val)
elif a.kind == akInt and b.kind == akFloat:
Expand All @@ -364,7 +372,7 @@ proc `/`*(a, b: ASTRoot): ASTRoot =
raise newException(ValueError, "Cannot divide " & a.astName & " by " & b.astName)


proc `//`*(a, b: ASTRoot): ASTRoot =
func `//`*(a, b: ASTRoot): ASTRoot =
if a.kind == akInt and b.kind == akInt:
return intAST(a.IntAST.val div b.IntAST.val)
elif a.kind == akInt and b.kind == akFloat:
Expand All @@ -373,14 +381,14 @@ proc `//`*(a, b: ASTRoot): ASTRoot =
raise newException(ValueError, "Cannot divide " & a.astName & " by " & b.astName)


proc `%`*(a, b: ASTRoot): ASTRoot =
func `%`*(a, b: ASTRoot): ASTRoot =
if a.kind == akInt and b.kind == akInt:
return intAst(a.IntAST.val mod b.IntAST.val)
else:
raise newException(ValueError, "Cannot get mod of " & b.astName & " from " & a.astName)


proc `==`*(a, b: ASTRoot): ASTRoot =
func `==`*(a, b: ASTRoot): ASTRoot =
if a.kind != b.kind:
return boolAst(false)
case a.kind:
Expand All @@ -392,11 +400,11 @@ proc `==`*(a, b: ASTRoot): ASTRoot =
else: boolAst(a[] == b[])


proc `!=`*(a, b: ASTRoot): ASTRoot =
func `!=`*(a, b: ASTRoot): ASTRoot =
boolAst(not (a == b).BoolAST.val)


proc `>`*(a, b: ASTRoot): ASTRoot =
func `>`*(a, b: ASTRoot): ASTRoot =
if a.kind == akInt and b.kind == akInt:
return boolAst(a.IntAST.val > b.IntAST.val)
elif a.kind == akFloat and b.kind == akFloat:
Expand All @@ -410,35 +418,27 @@ proc `>`*(a, b: ASTRoot): ASTRoot =
)


proc `>=`*(a, b: ASTRoot): ASTRoot =
func `>=`*(a, b: ASTRoot): ASTRoot =
boolAst((a == b).BoolAST.val or (a > b).BoolAST.val)


proc `<`*(a, b: ASTRoot): ASTRoot =
func `<`*(a, b: ASTRoot): ASTRoot =
boolAst(not (a >= b).BoolAST.val)


proc `<=`*(a, b: ASTRoot): ASTRoot =
func `<=`*(a, b: ASTRoot): ASTRoot =
boolAst((a == b).BoolAST.val or (a < b).BoolAST.val)


proc `and`*(a, b: ASTRoot): ASTRoot =
func `and`*(a, b: ASTRoot): ASTRoot =
boolAst(a.BoolAST.val and b.BoolAST.val)


proc `or`*(a, b: ASTRoot): ASTRoot =
func `or`*(a, b: ASTRoot): ASTRoot =
boolAst(a.BoolAST.val or b.BoolAST.val)


# proc `..`*(a, b: ASTRoot): ASTRoot =
# if a.kind != b.kind:
# raise newException(ValueError, "Can not slice with different types")
# case a.kind:
# of akInt:
# return slice(Slice())


proc `[]`*(a, b: ASTRoot, env: Environment): ASTRoot =
func `[]`*(a, b: ASTRoot, env: Environment): ASTRoot =
if a.kind == akArr and b.kind == akInt:
let idx = b.IntAST.val
if idx < 0:
Expand Down Expand Up @@ -481,7 +481,7 @@ proc `[]`*(a, b: ASTRoot, env: Environment): ASTRoot =
)


proc `[]=`*(a, b: ASTRoot, env: Environment, val: ASTRoot) =
func `[]=`*(a, b: ASTRoot, env: Environment, val: ASTRoot) =
if a.kind == akArr and b.kind == akInt:
let idx = b.IntAST.val
if idx < 0:
Expand Down Expand Up @@ -701,3 +701,23 @@ method eval*(self: BreakStmt, env: Environment): ASTRoot =
method eval*(self: ContinueStmt, env: Environment): ASTRoot =
env.signal = sContinue
return self

method eval*(self: SwapStmt, env: Environment): ASTRoot =
if self.l.kind != self.r.kind or self.toL.kind != self.toR.kind:
raise newException(RuntimeError, "Can not swap different types")
case self.l.kind:
of akVar:
let
l = self.toL.eval(env)
r = self.toR.eval(env)
discard assignStmtAst(self.l.VarAST.name, l, false, false).eval(env)
discard assignStmtAst(self.r.VarAST.name, r, false, false).eval(env)
of akBracketExpr:
let
l = self.toL.eval(env)
r = self.toR.eval(env)
discard assignBracket(self.l.BracketExprAST, l, "=").eval(env)
discard assignBracket(self.r.BracketExprAST, r, "=").eval(env)
else:
raise newException(RuntimeError, "Can not swap this")
nullAst()
Loading

0 comments on commit 0e308d2

Please sign in to comment.