WORKING VERSION
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Sat, 15 Dec 2018 21:39:20 +0000 (15:39 -0600)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Sat, 15 Dec 2018 21:39:20 +0000 (15:39 -0600)
18 files changed:
christmas_proj
christmas_proj.nimble
data/progs/fibcol.lgt [new file with mode: 0644]
data/progs/first.lgt [new file with mode: 0644]
data/progs/test.lgt
src/board/board.nim
src/christmas_proj.nim
src/gfx/window.nim
src/lang/ast.nim [deleted file]
src/lang/executer.nim [new file with mode: 0644]
src/lang/lexer.nim
src/lang/parser.nim
src/lang/program.nim [new file with mode: 0644]
src/lang/tokens.nim [deleted file]
src/lang/types.nim [deleted file]
src/lang/types/ast.nim [new file with mode: 0644]
src/lang/types/tokens.nim [new file with mode: 0644]
src/lang/types/types.nim [new file with mode: 0644]

index 8bf1cf3c1e8c1e0a4d17aa0c6421f1fab9de6df9..94824293d7132f8befb22591f48e87cbb66a8d47 100755 (executable)
Binary files a/christmas_proj and b/christmas_proj differ
index 88bb56aec01272fde5158f388494689ca9549cd3..182ef92fa663232d62b8e299f379f155f537178a 100644 (file)
@@ -15,5 +15,5 @@ requires "opengl >= 1.2.0"
 requires "glfw"
 
 task run, "Run project":
-  exec("nimble build")
+  exec("nimble build -d:release")
   exec("./christmas_proj")
\ No newline at end of file
diff --git a/data/progs/fibcol.lgt b/data/progs/fibcol.lgt
new file mode 100644 (file)
index 0000000..11e416d
--- /dev/null
@@ -0,0 +1,21 @@
+$mem_2 = 0
+$mem_3 = 10000
+
+while 1 {
+       $pos_x = 0
+       $pos_y = 0
+       while $pos_y < 256 {
+               $mem_1 = 20 * $pos_x + $mem_2 / 4
+               $mem_1 = $mem_1 + $pos_y * $pos_x * 5
+               !set_col($mem_1)
+               !step_linear(1)
+       }
+       $mem_2 = $mem_2 + 1
+       !render()
+
+       $mem_3 = $mem_3 - 1
+       if $mem_3 <= 0 {
+               !halt()
+       }
+}
+
diff --git a/data/progs/first.lgt b/data/progs/first.lgt
new file mode 100644 (file)
index 0000000..61b8e9e
--- /dev/null
@@ -0,0 +1,43 @@
+$pos_x = 0
+$pos_y = 10
+$mem_8 = 1
+
+#move_diag {
+       $pos_x = $pos_x + $mem_8
+       $pos_y = $pos_y + $mem_8
+}
+
+#swap_xy {
+       $mem_1 = $pos_x
+       $pos_x = $pos_y
+       $pos_y = $mem_1
+}
+
+$mem_3 = 100
+while $pos_x <= 255 {
+       $mem_3 = $mem_3 + 4
+       if $mem_3 >= 256 {
+               $mem_3 = $mem_3 - 156
+       }
+
+       !set_col($pos_x, $pos_y, $mem_3)
+       !move_diag()
+       !swap_xy()
+       !render()
+}
+
+$pos_x = 240
+$pos_y = 255
+$mem_8 = 0 - 1
+
+while $pos_x >= 0 {
+       !set_col($pos_x, $pos_y, 255)
+       !move_diag()
+       !render()
+}
+
+!say($pos_x)
+$mem_2 = if $pos_x < 0 {
+       1000
+}
+!say($mem_2)
index 93a542718387a28fc98716296435f8103323b2a9..a7197157208fcd857104c3b6065680fe51d1ae52 100644 (file)
@@ -1,15 +1,20 @@
-$MEM_1 = 0
-$MEM_2 = 1
+$mem_1 = 0
+$mem_2 = 1
 
-WHILE $MEM_2 < 100000 DO
-       $MEM_3 = $MEM_1 + $MEM_2
-       $MEM_1 = $MEM_2
-       $MEM_2 = $MEM_3
-       !PRINT($MEM_3, 3 + $MEM_7)
-END
+//Dummy function that doesn't do much
+#test {
+       !say($mem_1 + $mem_2)
+}
 
-IF !IN_BOUNDS($POS_X + 1, $POS_Y) THEN
-       !SAY($MEM_8)
-END
+while $mem_2 < 100000 {
+       $mem_3 = $mem_1 + $mem_2
+       $mem_1 = $mem_2
+       $mem_2 = $mem_3
+       !say($mem_3, $mem_2, $mem_2 == $mem_3)
+}
 
-!REDRAW()
\ No newline at end of file
+if !in_bounds($pos_x + 1, $pos_y) {
+       !test()
+}
+
+!redraw()
\ No newline at end of file
index 35101fda174e8c2cbb9e42395fba8d34d181d266..aecfcdfc0b0721fdffec9eb28adf13b93c82aa9c 100644 (file)
@@ -2,7 +2,7 @@ import opengl
 import ../gfx/glutils
 
 type
-  LightBoard = ref object
+  LightBoard* = ref object
     width: int
     height: int
     data: ref array[1024 * 1024, GLuint]
index 49b211ee162dc5f290b14e2686835ccb2fdc59f3..229b07b126e994cc685c453b4e6cfa759b3d8415 100644 (file)
@@ -1,15 +1,13 @@
 import os
-import sequtils
+import tables
 import opengl
-import random
 import glfw3 as glfw
 import gfx/window as gfx_window
 import gfx/glutils as glutils
 
-import lang/ast
-import lang/lexer as lexer
-import lang/parser as parser
-import lang/tokens
+import lang/types/types
+import lang/program
+import lang/executer
 
 import board/board
 
@@ -17,75 +15,56 @@ proc key_down(window: glfw.Window, key, scancode, action, modifier: cint) {.cdec
   if key == glfw.KEY_ESCAPE and action == glfw.PRESS:
     glfw.SetWindowShouldClose(window, glfw.TRUE)
 
-proc main2() =
-  let window = gfxWindow.NewWindow(800, 600, "ASDF")
-  window.SetKeyCallback(key_down)
-
-  let vertex_shader = glutils.CreateShader(glutils.stVertex, "./data/shaders/basic.vert")
-  let fragment_shader = glutils.CreateShader(glutils.stFragment, "./data/shaders/basic.frag")
-  let program = glutils.LinkProgram(vertex_shader, fragment_shader)
-  glUseProgram(program)
-
-  var vao: GLuint
-  var temp_vao: GLuint
-  glGenVertexArrays(1.GLsizei, vao.addr)
-  glGenVertexArrays(1.GLsizei, temp_vao.addr)
-
-  var vbo: GLuint
-  var cbo: GLuint
-  var ibo: GLuint
-  glGenBuffers(1.GLsizei, vbo.addr)
-  glGenBuffers(1.GLsizei, cbo.addr)
-  glGenBuffers(1.GLsizei, ibo.addr)
-
-  glBindVertexArray(vao)
-  glEnableVertexAttribArray(0)
-  glEnableVertexAttribArray(1)
-
-  var vertex_data: array[6, GLfloat] = [
-    0'f32, 0'f32,
-    0'f32, 1'f32,
-    1'f32, 0'f32,
-  ]
-  glBindBuffer(GL_ARRAY_BUFFER, vbo)
-  glBufferData(GL_ARRAY_BUFFER, vertex_data.sizeof, vertex_data.addr, GL_STATIC_DRAW)
-  glVertexAttribPointer(0, 2, cGL_FLOAT, GL_FALSE, 8.GLsizei, nil)
-
-  var color_data: array[8, GLfloat] = [
-    1'f32, 0'f32, 1'f32, 1'f32,
-    0'f32, 1'f32, 0'f32, 1'f32,
-  ]
-  glBindBuffer(GL_ARRAY_BUFFER, cbo)
-  glBufferData(GL_ARRAY_BUFFER, color_data.sizeof, color_data.addr, GL_STATIC_DRAW)
-  glVertexAttribDivisor(1, 1)
-  glVertexAttribPointer(1, 4, cGL_FLOAT, GL_FALSE, 16.GLsizei, nil)
-
-  var index_data: array[3, GLuint] = [
-    0.GLuint, 1.Gluint, 2.Gluint,
-  ] 
-  glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo)
-  glBufferData(GL_ELEMENT_ARRAY_BUFFER, index_data.sizeof, index_data.addr, GL_STATIC_DRAW)
-
-  glBindVertexArray(0)
-
-
 proc main() =
   let window = gfxWindow.NewWindow(1200, 700, "ASDF")
   window.SetKeyCallback(key_down)
 
-  let source_code = readFile("data/progs/test.lgt")
-  let tokens = toSeq(lexer.GenerateTokens(source_code))
-  for exp in parser.ParseTokens(tokens):
-    echo exp
+  let program = LoadProgram("./data/progs/fibcol.lgt")
 
-  let board = CreateBoard(256, 256)
+  const board_width: int = 128
+  const board_height: int = 128
+  let board = CreateBoard(board_width, board_height)
   board.InitRendering()
 
+  var funcs = newTable({
+    "say": (proc(ec: ExecutionContext, args: openarray[int32]): int32 {.closure.} =
+      echo $args
+    ),
+    "set_col": (proc(ec: ExecutionContext, args: openarray[int32]): int32 {.closure.} =
+      board.SetCol(ec.worker.pos_x.int, ec.worker.pos_y.int, args[0].GLuint)
+    ),
+    "step_linear": (proc(ec: ExecutionContext, args: openarray[int32]): int32 {.closure.} =
+      ec.worker.pos_x += args[0]
+      while ec.worker.pos_x >= board_width:
+        ec.worker.pos_x -= board_width.LightInt
+        ec.worker.pos_y += 1
+      while ec.worker.pos_x < 0:
+        ec.worker.pos_x += board_width.LightInt
+        ec.worker.pos_y -= 1
+    ),
+    "halt": (proc(ec: ExecutionContext, args: openarray[int32]): int32 {.closure.} =
+      ec.StopExecution()
+    ),
+    "render": (proc(ec: ExecutionContext, args: openarray[int32]): int32 {.closure.} =
+      glClearColor(0, 0, 0, 1)
+      glClear(GL_COLOR_BUFFER_BIT)
+      
+      board.RebufferColors()
+      board.Render()
+
+      os.sleep(1)
+      window.Refresh()
+      if window.ShouldClose():
+        ec.StopExecution()
+    )
+  })
+
+  let ec = MakeExecutionContext(funcs)
+  discard ExecuteProgram(ec, program)
+
   while not window.ShouldClose():
     glClearColor(0, 0, 0, 1)
     glClear(GL_COLOR_BUFFER_BIT)
-
-    board.SetCol(random.rand(256), random.rand(256), random.rand(0xffffff).GLuint)
     
     board.RebufferColors()
     board.Render()
index 6a8064002698a2aeea93f0b49365b57e4993d1b8..1b7cefa1563849543af1da3efb9290c76c3878bb 100644 (file)
@@ -2,7 +2,7 @@ import glfw3 as glfw
 import opengl
 
 type
-  Window* = object
+  Window* = ref object
     window: glfw.Window
     width, height: cint
     title: cstring
diff --git a/src/lang/ast.nim b/src/lang/ast.nim
deleted file mode 100644 (file)
index e0fee97..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-import ./types
-import ./tokens
-
-type
-  LightExprType* = enum
-    leNull     = 0,
-    leVar      = 1,
-    leNumLit   = 2,
-    leOp       = 3,
-    leAssign   = 4,
-    leLabel    = 5,
-    leGoto     = 6,
-    leIf       = 7,
-    leWhile    = 8,
-    leBreak    = 9,
-    leFuncCall = 10,
-
-  LightExpr* = ref object
-    case kind*: LightExprType
-    of leVar:
-      var_name*: LightVariable
-    of leNumLit:
-      value*: LightInt
-    of leOp:
-      left*: LightExpr
-      right*: LightExpr
-      operation*: LightOperation
-    of leAssign:
-      variable*: LightVariable
-      expression*: LightExpr
-    of leLabel, leGoto:
-      label*: string
-    of leIf, leWhile:
-      condition*: LightExpr
-      body*: seq[LightExpr]
-    of leFuncCall:
-      func_name*: string
-      params*: seq[LightExpr]
-    else: 
-      discard
-
-proc `$`*(exp: LightExpr): string =
-  case exp.kind:
-  of leVar: "Var[" & $exp.var_name & "]"
-  of leNumLit: "Num[" & $exp.value & "]"
-  of leOp: "Operation[" & $exp.operation & ", " & $exp.left & ", " & $exp.right & "]"
-  of leAssign: "Assignment[" & $exp.variable & ", " & $exp.expression & "]"
-  of leLabel: "Label[" & $exp.label & "]"
-  of leGoto: "Goto[" & $exp.label & "]"
-  of leIf: "If[" & $exp.condition & " -> " & $exp.body & "]"
-  of leWhile: "While[" & $exp.condition & " -> " & $exp.body & "]"
-  of leBreak: "Break"
-  of leFuncCall: "FuncCall[" & exp.func_name & ", " & $exp.params & "]"
-  else: ""
\ No newline at end of file
diff --git a/src/lang/executer.nim b/src/lang/executer.nim
new file mode 100644 (file)
index 0000000..4988ee2
--- /dev/null
@@ -0,0 +1,165 @@
+import os
+import tables
+import ./types/types
+import ./types/ast
+import ./program
+import ../board/board
+import ../gfx/window
+
+type
+  LightWorker = ref object
+    var_1*, var_2*, var_3*, var_4*: LightInt
+    var_5*, var_6*, var_7*, var_8*: LightInt
+    pos_x*, pos_y*: LightInt
+
+  ExecFuncs = TableRef[string, proc(ec: ExecutionContext, args: openarray[LightInt]): LightInt]
+
+  ExecutionContext* = ref object
+    worker*: LightWorker
+    builtin_functions: ExecFuncs
+    defined_functions: TableRef[string, seq[LightExpr]]
+    running: bool
+
+proc MakeEmptyWorker(): LightWorker =
+  LightWorker()
+
+proc MakeExecutionContext*(funcs: ExecFuncs): ExecutionContext =
+  let worker = MakeEmptyWorker()
+  let defined_functions = newTable[string, seq[LightExpr]]()
+  ExecutionContext(
+    worker: worker,
+    builtin_functions: funcs,
+    defined_functions: defined_functions,
+    running: false
+  )
+
+proc ExecuteLines(ec: ExecutionContext, lines: seq[LightExpr]): LightInt
+
+func GetVar(worker: LightWorker, variable: LightVariable): LightInt =
+  case variable:
+  of var1: worker.var_1
+  of var2: worker.var_2
+  of var3: worker.var_3
+  of var4: worker.var_4
+  of var5: worker.var_5
+  of var6: worker.var_6
+  of var7: worker.var_7
+  of var8: worker.var_8
+  of varX: worker.pos_x
+  of varY: worker.pos_y
+
+func SetVar(worker: LightWorker, variable: LightVariable, value: LightInt): LightInt =
+  case variable:
+  of var1: worker.var_1 = value
+  of var2: worker.var_2 = value
+  of var3: worker.var_3 = value
+  of var4: worker.var_4 = value
+  of var5: worker.var_5 = value
+  of var6: worker.var_6 = value
+  of var7: worker.var_7 = value
+  of var8: worker.var_8 = value
+  of varX: worker.pos_X = value
+  of varY: worker.pos_Y = value
+
+  value
+
+proc EvalExpr(ec: ExecutionContext, exp: LightExpr): LightInt =
+  case exp.kind:
+  of leNull:
+    0
+
+  of leVar:
+    GetVar(ec.worker, exp.var_name)
+
+  of leNumLit:
+    exp.value
+
+  of leOp:
+    let
+      left = EvalExpr(ec, exp.left)
+      right = EvalExpr(ec, exp.right)
+
+    case exp.operation:
+    of loAdd: left + right
+    of loSub: left - right
+    of loMul: left * right
+    of loDiv: left div right
+    of loMod: left mod right
+    of loGt:
+      if left > right: 1
+      else: 0
+    of loGte:
+      if left >= right: 1
+      else: 0
+    of loLt:
+      if left < right: 1
+      else: 0
+    of loLte:
+      if left <= right: 1
+      else: 0
+    of loEq:
+      if left == right: 1
+      else: 0
+    of loNeq:
+      if left != right: 1
+      else: 0
+
+  of leAssign:
+    let value = EvalExpr(ec, exp.expression)
+    SetVar(ec.worker, exp.variable, value)
+
+  of leIf:
+    let cond = EvalExpr(ec, exp.condition)
+    if cond != 0:
+      ExecuteLines(ec, exp.body)
+    else:
+      0
+
+  of leWhile:
+    while ec.running:
+      let cond = EvalExpr(ec, exp.condition)
+      if cond == 0:
+        break
+
+      discard ExecuteLines(ec, exp.body)
+    0
+
+  of leFuncCall:
+    if ec.builtin_functions.hasKey(exp.func_name):
+      var args = newSeq[LightInt]()
+      for param in exp.params:
+        args.add(EvalExpr(ec, param))
+      ec.builtin_functions[exp.func_name](ec, args)
+
+    elif ec.defined_functions.hasKey(exp.func_name):
+      ExecuteLines(ec, ec.defined_functions[exp.func_name])
+
+    else:
+      raise newException(ValueError, "Cannot call undefined function")
+
+  of leFuncDef:
+    if ec.defined_functions.hasKey(exp.def_func_name):
+      raise newException(ValueError, "Cannot redefine function")
+
+    else:
+      ec.defined_functions[exp.def_func_name] = exp.func_body
+      1
+  else:
+    0
+
+proc ExecuteLines(ec: ExecutionContext, lines: seq[LightExpr]): LightInt =
+  if not ec.running:
+    return 0
+
+  var last: LightInt
+  for line in lines:
+    last = EvalExpr(ec, line)
+    if not ec.running: break
+  last
+
+proc ExecuteProgram*(ec: ExecutionContext, prog: LightProgram): LightInt =
+  ec.running = true
+  ExecuteLines(ec, prog.code)
+
+proc StopExecution*(ec: ExecutionContext) =
+  ec.running = false
index a5acc329894562201bc5855583e2ed7b2d011f78..6e754c86ee27f9a17f2d878bd623347d3a22587a 100644 (file)
@@ -2,99 +2,107 @@ import strutils
 import parseutils
 import sequtils
 
-import ./types
-import ./tokens
+import ./types/types
+import ./types/tokens
 
 iterator Generate_tokens*(source: string): LightToken =
-  for token, is_sep in strutils.tokenize(source, {' ', '\n', ';', '\t', '=', ',', '(', ')'}):
-    if is_sep:
-      if token.contains({'='}):
-        yield LightToken(kind: ltEq)
-      if token.contains({','}):
-        yield LightToken(kind: ltParamDelim)
-      if token.contains({'('}):
-        yield LightToken(kind: ltParamStart)
-      if token.contains({')'}):
-        yield LightToken(kind: ltParamEnd)
-      if token.contains({'\n', ';'}):
-        yield LightToken(kind: ltExprDelim)
+  for line in strutils.split(source, "\n"):
+    if line.strip.startsWith("//"):
       continue
 
-    if token.startsWith('$'):
-      let varString = token[1 .. ^1].toLowerAscii
-      var varName: LightVariable
+    for token, is_sep in strutils.tokenize(line, {' ', ';', '\t', ',', '(', ')'}):
+      if is_sep:
+        if token.contains({','}):
+          yield LightToken(kind: ltParamDelim)
+        if token.contains({'('}):
+          yield LightToken(kind: ltParamStart)
+        if token.contains({')'}):
+          yield LightToken(kind: ltParamEnd)
+        if token.contains({';'}):
+          yield LightToken(kind: ltExprDelim)
+        continue
 
-      if varString == "":
-        raise newException(IOError, "Expected variable name")
-      else:
-        if varString == "mem_1": varName = var1
-        elif varString == "mem_2": varName = var2
-        elif varString == "mem_3": varName = var3
-        elif varString == "mem_4": varName = var4
-        elif varString == "mem_5": varName = var5
-        elif varString == "mem_6": varName = var6
-        elif varString == "mem_7": varName = var7
-        elif varString == "mem_8": varName = var8
-        elif varString == "pos_x": varName = var9
-        elif varString == "pos_y": varName = var10
+      if token.startsWith('$'):
+        let varString = token[1 .. ^1].toLowerAscii
+        var varName: LightVariable
+
+        if varString == "":
+          raise newException(IOError, "Expected variable name")
         else:
-          raise newException(IOError, "Invalid variable name.")
+          if varString == "mem_1": varName = var1
+          elif varString == "mem_2": varName = var2
+          elif varString == "mem_3": varName = var3
+          elif varString == "mem_4": varName = var4
+          elif varString == "mem_5": varName = var5
+          elif varString == "mem_6": varName = var6
+          elif varString == "mem_7": varName = var7
+          elif varString == "mem_8": varName = var8
+          elif varString == "pos_x": varName = varX
+          elif varString == "pos_y": varName = varY
+          else:
+            raise newException(IOError, "Invalid variable name.")
 
-      yield LightToken(kind: ltVar, var_name: varName)
+        yield LightToken(kind: ltVar, var_name: varName)
 
-    elif token.startsWith('!'):
-      let funcName = token[1..^1].toLowerAscii
-      yield LightToken(kind: ltFunc, func_name: funcName)
+      elif token.startsWith('!'):
+        let funcName = token[1..^1].toLowerAscii
+        yield LightToken(kind: ltFunc, func_name: funcName)
 
-    elif token == "=":
-      yield LightToken(kind: ltEq)
+      elif token.startsWith('#'):
+        let funcName = token[1..^1].toLowerAscii
+        yield LightToken(kind: ltFuncDef, func_name: funcName)
 
-    elif token.isDigit:
-      var value: int
-      discard parseutils.parseInt(token, value)
+      elif token == "=":
+        yield LightToken(kind: ltEq)
 
-      yield LightToken(kind: ltNum, value: value.LightInt)
+      elif token.isDigit:
+        var value: int
+        discard parseutils.parseInt(token, value)
 
-    elif token.toLowerAscii == "if":
-      yield LightToken(kind: ltIf)
-    elif token.toLowerAscii == "while":
-      yield LightToken(kind: ltWhile)
-    elif token.toLowerAscii == "break":
-      yield LightToken(kind: ltBreak)
-    elif token.toLowerAscii == "then" or token.toLowerAscii == "do" or token == "{":
-      yield LightToken(kind: ltBlockStart)
-    elif token.toLowerAscii == "end" or token == "}":
-      yield LightToken(kind: ltBlockEnd)
+        yield LightToken(kind: ltNum, value: value.LightInt)
 
-    elif token.toLowerAscii == "goto":
-      yield LightToken(kind: ltGoto)
-    elif token.startsWith(':'):
-      let labelName = token[1 .. ^1]
-      yield LightToken(kind: ltLabel, label_name: labelName)
+      elif token.toLowerAscii == "if":
+        yield LightToken(kind: ltIf)
+      elif token.toLowerAscii == "while":
+        yield LightToken(kind: ltWhile)
+      elif token.toLowerAscii == "break":
+        yield LightToken(kind: ltBreak)
+      elif token.toLowerAscii == "then" or token.toLowerAscii == "do" or token == "{":
+        yield LightToken(kind: ltBlockStart)
+      elif token.toLowerAscii == "end" or token == "}":
+        yield LightToken(kind: ltBlockEnd)
+
+      elif token.toLowerAscii == "goto":
+        yield LightToken(kind: ltGoto)
+      elif token.startsWith(':'):
+        let labelName = token[1 .. ^1]
+        yield LightToken(kind: ltLabel, label_name: labelName)
 
-    else:
-      case token:
-      of "+":
-        yield LightToken(kind: ltOp, operation: loAdd)
-      of "-":
-        yield LightToken(kind: ltOp, operation: loSub)
-      of "*":
-        yield LightToken(kind: ltOp, operation: loMul)
-      of "/":
-        yield LightToken(kind: ltOp, operation: loDiv)
-      of "%":
-        yield LightToken(kind: ltOp, operation: loMod)
-      of "<":
-        yield LightToken(kind: ltOp, operation: loLt)
-      of "<=":
-        yield LightToken(kind: ltOp, operation: loLte)
-      of ">":
-        yield LightToken(kind: ltOp, operation: loGt)
-      of ">=":
-        yield LightToken(kind: ltOp, operation: loGte)
-      of "==":
-        yield LightToken(kind: ltOp, operation: loEq)
-      of "~=":
-        yield LightToken(kind: ltOp, operation: loNeq)
       else:
-        raise newException(IOError, "Invalid token")
+        case token:
+        of "+":
+          yield LightToken(kind: ltOp, operation: loAdd)
+        of "-":
+          yield LightToken(kind: ltOp, operation: loSub)
+        of "*":
+          yield LightToken(kind: ltOp, operation: loMul)
+        of "/":
+          yield LightToken(kind: ltOp, operation: loDiv)
+        of "%":
+          yield LightToken(kind: ltOp, operation: loMod)
+        of "<":
+          yield LightToken(kind: ltOp, operation: loLt)
+        of "<=":
+          yield LightToken(kind: ltOp, operation: loLte)
+        of ">":
+          yield LightToken(kind: ltOp, operation: loGt)
+        of ">=":
+          yield LightToken(kind: ltOp, operation: loGte)
+        of "==":
+          yield LightToken(kind: ltOp, operation: loEq)
+        of "~=":
+          yield LightToken(kind: ltOp, operation: loNeq)
+        else:
+          raise newException(IOError, "Invalid token")
+
+    yield LightToken(kind: ltExprDelim)
index b0400776ad07edf6a6a693c88ef28d7963d84082..1019884438d3eed7406aad0a264552cfb72c1921 100644 (file)
@@ -1,7 +1,7 @@
 
-import ./types
-import ./tokens
-import ./ast
+import ./types/types
+import ./types/tokens
+import ./types/ast
 
 import ../utils/iter
 
@@ -128,6 +128,24 @@ func NextExpr(parser: LightParser, prev: LightExpr, stop_at: set[LightTokenType]
       params: params
     )
   
+  elif curr.kind == ltFuncDef:
+    if parser.tokens.Current.kind != ltBlockStart:
+      raise newException(ValueError, "Expected block start after function definition")
+    
+    parser.tokens.Step()
+    let body = Parse_block(parser.tokens, ltExprDelim, ltBlockEnd)
+    
+    return LightExpr(
+      kind: leFuncDef,
+      def_func_name: curr.func_name,
+      func_body: body
+    )
+
+  else:
+    return LightExpr(
+      kind: leNull
+    )
+  
 iterator Parse_tokens*(tokens: seq[LightToken]): LightExpr =
   var parser = CreateParser(tokens)
   while not parser.tokens.ReachedEnd:
diff --git a/src/lang/program.nim b/src/lang/program.nim
new file mode 100644 (file)
index 0000000..1dbfce0
--- /dev/null
@@ -0,0 +1,16 @@
+import sequtils
+import tables
+import ./types/ast
+import ./lexer
+import ./parser
+
+type
+  LightProgram* = ref object
+    code*: seq[LightExpr]
+
+proc LoadProgram*(file_name: string): LightProgram =
+  let source_code = readFile(file_name)
+  let tokens = toSeq(lexer.GenerateTokens(source_code))
+  let code = toSeq(parser.ParseTokens(tokens))
+
+  LightProgram(code: code)
diff --git a/src/lang/tokens.nim b/src/lang/tokens.nim
deleted file mode 100644 (file)
index 9a9cdcb..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-import ./types
-
-type
-  LightTokenType* = enum
-    ltNull,
-    ltVar, ltNum,
-    ltExprDelim,
-    ltLabel, ltGoto,
-    ltIf, ltWhile,
-    ltBlockStart, ltBlockEnd,
-    ltBreak,
-    ltFunc,
-    ltParamStart, ltParamEnd,
-    ltParamDelim,
-    ltOp, ltEq
-
-  LightToken* = ref object
-    case kind*: LightTokenType
-    of ltVar:
-      var_name*: LightVariable
-    of ltNum:
-      value*: LightInt
-    of ltLabel:
-      label_name*: string
-    of ltFunc:
-      func_name*: string
-    of ltOp:
-      operation*: LightOperation
-    else:
-      discard
-
-func `$`*(variable: LightVariable): string =
-  case variable:
-  of var1: "MEM_1"
-  of var2: "MEM_2"
-  of var3: "MEM_3"
-  of var4: "MEM_4"
-  of var5: "MEM_5"
-  of var6: "MEM_6"
-  of var7: "MEM_7"
-  of var8: "MEM_8"
-  of var9: "POS_X"
-  of var10: "POS_Y"
-
-proc `$`*(token: LightToken): string =
-  return
-    case token.kind:
-    of ltNull: "NullToken"
-    of ltVar: "VarToken[" & $token.var_name & "]"
-    of ltEq: "EqualsToken"
-    of ltNum: "NumberToken[" & $token.value & "]"
-    of ltExprDelim: "ExprDelimToken"
-    of ltLabel: "LabelToken[" & token.label_name & "]"
-    of ltGoto: "GotoToken"
-    of ltIf: "IfToken"
-    of ltWhile: "WhileToken"
-    of ltBreak: "BreakToken"
-    of ltBlockStart: "BlockStartToken"
-    of ltBlockEnd: "BlockEndToken"
-    of ltFunc: "FunctionToken[" & token.func_name & "]"
-    of ltParamStart: "ParamStartToken"
-    of ltParamEnd: "ParamEndToken"
-    of ltParamDelim: "ParamDelimToken"
-    of ltOp: "OpeartionToken[" & $token.operation & "]"
-    else: "UndefinedToken"
\ No newline at end of file
diff --git a/src/lang/types.nim b/src/lang/types.nim
deleted file mode 100644 (file)
index 847ff5d..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-type
-  LightVariable* = enum
-    var1 = 0, var2 = 1, var3 = 2, var4 = 3,
-    var5 = 4, var6 = 5, var7 = 6, var8 = 7,
-    var9 = 8, var10 = 9
-    
-  LightOperation* = enum
-    loAdd, loSub, loMul, loDiv, loMod,
-    loGt, loGte, loLt, loLte, loEq, loNeq
-
-  LightInt* = int32
diff --git a/src/lang/types/ast.nim b/src/lang/types/ast.nim
new file mode 100644 (file)
index 0000000..1cd98b6
--- /dev/null
@@ -0,0 +1,59 @@
+import ./types
+import ./tokens
+
+type
+  LightExprType* = enum
+    leNull     = 0,
+    leVar      = 1,
+    leNumLit   = 2,
+    leOp       = 3,
+    leAssign   = 4,
+    leLabel    = 5,
+    leGoto     = 6,
+    leIf       = 7,
+    leWhile    = 8,
+    leBreak    = 9,
+    leFuncCall = 10,
+    leFuncDef  = 11,
+
+  LightExpr* = ref object
+    case kind*: LightExprType
+    of leVar:
+      var_name*: LightVariable
+    of leNumLit:
+      value*: LightInt
+    of leOp:
+      left*: LightExpr
+      right*: LightExpr
+      operation*: LightOperation
+    of leAssign:
+      variable*: LightVariable
+      expression*: LightExpr
+    of leLabel, leGoto:
+      label*: string
+    of leIf, leWhile:
+      condition*: LightExpr
+      body*: seq[LightExpr]
+    of leFuncCall:
+      func_name*: string
+      params*: seq[LightExpr]
+    of leFuncDef:
+      def_func_name*: string
+      func_body*: seq[LightExpr]
+    else: 
+      discard
+
+proc `$`*(exp: LightExpr): string =
+  case exp.kind:
+  of leVar: "Var[" & $exp.var_name & "]"
+  of leNumLit: "Num[" & $exp.value & "]"
+  of leOp: "Operation[" & $exp.operation & ", " & $exp.left & ", " & $exp.right & "]"
+  of leAssign: "Assignment[" & $exp.variable & ", " & $exp.expression & "]"
+  of leLabel: "Label[" & $exp.label & "]"
+  of leGoto: "Goto[" & $exp.label & "]"
+  of leIf: "If[" & $exp.condition & " -> " & $exp.body & "]"
+  of leWhile: "While[" & $exp.condition & " -> " & $exp.body & "]"
+  of leBreak: "Break"
+  of leFuncCall: "FuncCall[" & exp.func_name & ", " & $exp.params & "]"
+  of leFuncDef: "FuncDef[" & exp.def_func_name & ", " & $exp.func_body & "]"
+  else: ""
\ No newline at end of file
diff --git a/src/lang/types/tokens.nim b/src/lang/types/tokens.nim
new file mode 100644 (file)
index 0000000..b9ceaec
--- /dev/null
@@ -0,0 +1,67 @@
+import ./types
+
+type
+  LightTokenType* = enum
+    ltNull,
+    ltVar, ltNum,
+    ltExprDelim,
+    ltLabel, ltGoto,
+    ltIf, ltWhile,
+    ltBlockStart, ltBlockEnd,
+    ltBreak,
+    ltFunc,
+    ltParamStart, ltParamEnd,
+    ltParamDelim,
+    ltFuncDef,
+    ltOp, ltEq
+
+  LightToken* = ref object
+    case kind*: LightTokenType
+    of ltVar:
+      var_name*: LightVariable
+    of ltNum:
+      value*: LightInt
+    of ltLabel:
+      label_name*: string
+    of ltFunc, ltFuncDef:
+      func_name*: string
+    of ltOp:
+      operation*: LightOperation
+    else:
+      discard
+
+func `$`*(variable: LightVariable): string =
+  case variable:
+  of var1: "MEM_1"
+  of var2: "MEM_2"
+  of var3: "MEM_3"
+  of var4: "MEM_4"
+  of var5: "MEM_5"
+  of var6: "MEM_6"
+  of var7: "MEM_7"
+  of var8: "MEM_8"
+  of varX: "POS_X"
+  of varY: "POS_Y"
+
+proc `$`*(token: LightToken): string =
+  return
+    case token.kind:
+    of ltNull: "NullToken"
+    of ltVar: "VarToken[" & $token.var_name & "]"
+    of ltEq: "EqualsToken"
+    of ltNum: "NumberToken[" & $token.value & "]"
+    of ltExprDelim: "ExprDelimToken"
+    of ltLabel: "LabelToken[" & token.label_name & "]"
+    of ltGoto: "GotoToken"
+    of ltIf: "IfToken"
+    of ltWhile: "WhileToken"
+    of ltBreak: "BreakToken"
+    of ltBlockStart: "BlockStartToken"
+    of ltBlockEnd: "BlockEndToken"
+    of ltFunc: "FunctionToken[" & token.func_name & "]"
+    of ltParamStart: "ParamStartToken"
+    of ltParamEnd: "ParamEndToken"
+    of ltParamDelim: "ParamDelimToken"
+    of ltFuncDef: "FuncDefToken[" & token.func_name & "]"
+    of ltOp: "OpeartionToken[" & $token.operation & "]"
+    else: "UndefinedToken"
\ No newline at end of file
diff --git a/src/lang/types/types.nim b/src/lang/types/types.nim
new file mode 100644 (file)
index 0000000..d17d6d8
--- /dev/null
@@ -0,0 +1,11 @@
+type
+  LightVariable* = enum
+    var1 = 0, var2 = 1, var3 = 2, var4 = 3,
+    var5 = 4, var6 = 5, var7 = 6, var8 = 7,
+    varX = 8, varY = 9
+    
+  LightOperation* = enum
+    loAdd, loSub, loMul, loDiv, loMod,
+    loGt, loGte, loLt, loLte, loEq, loNeq
+
+  LightInt* = int32