From: Brendan Hansen Date: Sun, 16 Dec 2018 03:30:14 +0000 (-0600) Subject: polished version X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=cb4f4292a88ad2e9cdee24d4264f267481d612b5;p=light.git polished version --- diff --git a/christmas_proj b/christmas_proj index 9482429..98bedaa 100755 Binary files a/christmas_proj and b/christmas_proj differ diff --git a/christmas_proj.nimble b/christmas_proj.nimble index 182ef92..c147fcd 100644 --- a/christmas_proj.nimble +++ b/christmas_proj.nimble @@ -11,6 +11,7 @@ bin = @["christmas_proj"] # Dependencies requires "nim >= 0.19.0" +requires "docopt >= 0.6.8" requires "opengl >= 1.2.0" requires "glfw" diff --git a/data/progs/avg.lgt b/data/progs/avg.lgt new file mode 100644 index 0000000..e6ee493 --- /dev/null +++ b/data/progs/avg.lgt @@ -0,0 +1,81 @@ + +#FLOOD_WITH_RANDOM { + $m6 = -1 + 256 * 256 * 256 + $m7 = !GET_WIDTH() + $m8 = !GET_HEIGHT() + + $y = 0 + while $y < $m8 { + $x = 0 + while $x < $m7 { + !SET_COL(!RANDOM($m6)) + $x = $x + 1 + } + $y = $y + 1 + } +} + +//change 1, 2, 3 4, 7, 8 +#TAKE_AVERAGE { + //Red, Green and Blue Sum + $m1 = 0 + $m2 = 0 + $m3 = 0 + //Count + $m4 = 0 + + $m7 = $x + 1 + $m8 = $y + 1 + + $y = $y - 1 + while $y <= $m8 { + $x = $m7 - 2 + while $x <= $m7 { + if !IN_BOUNDS($x, $y) { + $m1 = $m1 + !GET_R() + $m2 = $m2 + !GET_G() + $m3 = $m3 + !GET_B() + + $m4 = $m4 + 1 + } + + $x = $x + 1 + } + $y = $y + 1 + } + $x = $x - 2 + $y = $y - 2 + + if $m4 > 0 { + $m1 = $m1 / $m4 + $m2 = $m2 / $m4 + $m3 = $m3 / $m4 + $m1 = $m1 * 256 * 256 + $m2 = $m2 * 256 + !SET_COL($m1 + $m2 + $m3) + } +} + +!FLOOD_WITH_RANDOM() + +!SAY(!GET_WIDTH()) +!SAY(!GET_HEIGHT()) + +$m5 = 30 +while 1 { + !RENDER() + $m5 = $m5 - 1 + if $m5 <= 0 { + $m5 = 30 + + $y = 0 + while $y < !GET_HEIGHT() { + $x = 0 + while $x < !GET_WIDTH() { + !TAKE_AVERAGE() + $x = $x + 1 + } + $y = $y + 1 + } + } +} diff --git a/data/progs/fibcol.lgt b/data/progs/fibcol.lgt deleted file mode 100644 index 11e416d..0000000 --- a/data/progs/fibcol.lgt +++ /dev/null @@ -1,21 +0,0 @@ -$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 index 61b8e9e..748ee79 100644 --- a/data/progs/first.lgt +++ b/data/progs/first.lgt @@ -1,43 +1,43 @@ -$pos_x = 0 -$pos_y = 10 -$mem_8 = 1 +$x = 0 +$y = 10 +$m8 = 1 #move_diag { - $pos_x = $pos_x + $mem_8 - $pos_y = $pos_y + $mem_8 + $x = $x + $m8 + $y = $y + $m8 } #swap_xy { - $mem_1 = $pos_x - $pos_x = $pos_y - $pos_y = $mem_1 + $m1 = $x + $x = $y + $y = $m1 } -$mem_3 = 100 -while $pos_x <= 255 { - $mem_3 = $mem_3 + 4 - if $mem_3 >= 256 { - $mem_3 = $mem_3 - 156 +$m3 = 100 +while $x <= !GET_WIDTH() { + $m3 = $m3 + 4 + if $m3 >= 256 { + $m3 = $m3 - 156 } - !set_col($pos_x, $pos_y, $mem_3) + !set_col($m3) !move_diag() !swap_xy() !render() } -$pos_x = 240 -$pos_y = 255 -$mem_8 = 0 - 1 +$x = !GET_WIDTH() - 15 +$y = !GET_HEIGHT() - 1 +$m8 = 0 - 1 -while $pos_x >= 0 { - !set_col($pos_x, $pos_y, 255) +while $x >= 0 { + !set_col(255) !move_diag() !render() } -!say($pos_x) -$mem_2 = if $pos_x < 0 { +!say($x) +$m2 = if $x < 0 { 1000 } -!say($mem_2) +!say($m2) diff --git a/data/progs/gol.lgt b/data/progs/gol.lgt new file mode 100644 index 0000000..39e70ba --- /dev/null +++ b/data/progs/gol.lgt @@ -0,0 +1,108 @@ +//Assumes 128 by 128 board +#BOARD_WIDTH { 128 } +#BOARD_HEIGHT { 128 } + +#CELL_ALIVE { 255 } +#CELL_DEAD { 0 } + +// Set up initial board +$y = 0 +while $y < !BOARD_HEIGHT() { + $x = 0 + while $x < !BOARD_WIDTH() { + if !random(100) >= 50 { + !set_r(!CELL_ALIVE()) + } else { + !set_r(!CELL_DEAD()) + } + $x = $x + 1 + } + $y = $y + 1 +} + +#UPDATE_CURRENT { + //Neighbor count + $m1 = 0 + + $x = $x - 1 + $y = $y - 1 + + $m1 = $m1 + !get_a() == !CELL_ALIVE() + $x = $x + 1 + $m1 = $m1 + !get_a() == !CELL_ALIVE() + $x = $x + 1 + $m1 = $m1 + !get_a() == !CELL_ALIVE() + $x = $x - 2 + $y = $y + 1 + $m1 = $m1 + !get_a() == !CELL_ALIVE() + $x = $x + 2 + $m1 = $m1 + !get_a() == !CELL_ALIVE() + $x = $x - 2 + $y = $y + 1 + $m1 = $m1 + !get_a() == !CELL_ALIVE() + $x = $x + 1 + $m1 = $m1 + !get_a() == !CELL_ALIVE() + $x = $x + 1 + $m1 = $m1 + !get_a() == !CELL_ALIVE() + + $x = $x - 1 + $y = $y - 1 + + $m2 = !get_a() == !CELL_ALIVE() + if $m2 { + $m3 = $m1 < 2 + $m3 = $m3 + $m1 > 3 + if $m3 { + !set_r(!CELL_DEAD()) + } + } else { + if $m1 == 3 { + !set_r(!CELL_ALIVE()) + } + } +} + +#COPY_BOARD { + $y = 0 + while $y < !BOARD_HEIGHT() { + $x = 0 + while $x < !BOARD_WIDTH() { + !set_a(!get_r()) + + $x = $x + 1 + } + $y = $y + 1 + } +} + +//Big render / update loop +$m7 = 30 +while 1 { + //Draw the board + !render() + + $m7 = $m7 - 1 + if $m7 <= 0 { + $m7 = 30 + + $y = 0 + while $y < !BOARD_HEIGHT() { + $x = 0 + while $x < !BOARD_WIDTH() { + !COPY_BOARD() + $x = $x + 1 + } + $y = $y + 1 + } + + $y = 0 + while $y < !BOARD_HEIGHT() { + $x = 0 + while $x < !BOARD_WIDTH() { + !UPDATE_CURRENT() + $x = $x + 1 + } + $y = $y + 1 + } + } +} \ No newline at end of file diff --git a/data/progs/test.lgt b/data/progs/test.lgt deleted file mode 100644 index a719715..0000000 --- a/data/progs/test.lgt +++ /dev/null @@ -1,20 +0,0 @@ -$mem_1 = 0 -$mem_2 = 1 - -//Dummy function that doesn't do much -#test { - !say($mem_1 + $mem_2) -} - -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) -} - -if !in_bounds($pos_x + 1, $pos_y) { - !test() -} - -!redraw() \ No newline at end of file diff --git a/src/board/board.nim b/src/board/board.nim index aecfcdf..3f48144 100644 --- a/src/board/board.nim +++ b/src/board/board.nim @@ -3,8 +3,8 @@ import ../gfx/glutils type LightBoard* = ref object - width: int - height: int + width*: int + height*: int data: ref array[1024 * 1024, GLuint] colors: ref array[1024 * 1024 * 4, GLfloat] diff --git a/src/christmas_proj.nim b/src/christmas_proj.nim index 229b07b..f4783b8 100644 --- a/src/christmas_proj.nim +++ b/src/christmas_proj.nim @@ -1,11 +1,17 @@ import os +import times import tables +import random +import parseutils + +import docopt import opengl import glfw3 as glfw import gfx/window as gfx_window import gfx/glutils as glutils import lang/types/types +import lang/types/ast import lang/program import lang/executer @@ -15,36 +21,90 @@ 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 main() = - let window = gfxWindow.NewWindow(1200, 700, "ASDF") - window.SetKeyCallback(key_down) +proc CreateFuncs(window: gfx_window.Window, board: LightBoard): ExecFuncs = + newTable({ + "say": (proc(ec: ExecutionContext, args: openarray[int32]): int32 {.closure.} = + echo $args + ), - let program = LoadProgram("./data/progs/fibcol.lgt") + "get_width": (proc(ec: ExecutionContext, args: openarray[int32]): int32 {.closure.} = + board.width.int32 + ), - const board_width: int = 128 - const board_height: int = 128 - let board = CreateBoard(board_width, board_height) - board.InitRendering() + "get_height": (proc(ec: ExecutionContext, args: openarray[int32]): int32 {.closure.} = + board.height.int32 + ), - var funcs = newTable({ - "say": (proc(ec: ExecutionContext, args: openarray[int32]): int32 {.closure.} = - echo $args + "in_bounds": (proc(ec: ExecutionContext, args: openarray[int32]): int32 {.closure.} = + if args[0] < 0 or args[1] < 0 or args[0] >= board.width or args[1] >= board.height: + 0 + else: + 1 ), + "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) ), + + "set_a": (proc(ec: ExecutionContext, args: openarray[int32]): int32 {.closure.} = + board.SetA(ec.worker.pos_x.int, ec.worker.pos_y.int, args[0].GLuint) + ), + + "set_r": (proc(ec: ExecutionContext, args: openarray[int32]): int32 {.closure.} = + board.SetR(ec.worker.pos_x.int, ec.worker.pos_y.int, args[0].GLuint) + ), + + "set_g": (proc(ec: ExecutionContext, args: openarray[int32]): int32 {.closure.} = + board.SetG(ec.worker.pos_x.int, ec.worker.pos_y.int, args[0].GLuint) + ), + + "set_b": (proc(ec: ExecutionContext, args: openarray[int32]): int32 {.closure.} = + board.SetB(ec.worker.pos_x.int, ec.worker.pos_y.int, args[0].GLuint) + ), + + "get_col": (proc(ec: ExecutionContext, args: openarray[int32]): int32 {.closure.} = + board.GetCol(ec.worker.pos_x.int, ec.worker.pos_y.int).int32 + ), + + "get_a": (proc(ec: ExecutionContext, args: openarray[int32]): int32 {.closure.} = + board.GetA(ec.worker.pos_x.int, ec.worker.pos_y.int).int32 + ), + + "get_r": (proc(ec: ExecutionContext, args: openarray[int32]): int32 {.closure.} = + board.GetR(ec.worker.pos_x.int, ec.worker.pos_y.int).int32 + ), + + "get_g": (proc(ec: ExecutionContext, args: openarray[int32]): int32 {.closure.} = + board.GetG(ec.worker.pos_x.int, ec.worker.pos_y.int).int32 + ), + + "get_b": (proc(ec: ExecutionContext, args: openarray[int32]): int32 {.closure.} = + board.GetB(ec.worker.pos_x.int, ec.worker.pos_y.int).int32 + ), + + "random": (proc(ec: ExecutionContext, args: openarray[int32]): int32 {.closure.} = + random.rand(args[0].int).int32 + ), + "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 + 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_x += board.width.LightInt ec.worker.pos_y -= 1 ), + + "step_to_linear": (proc(ec: ExecutionContext, args: openarray[int32]): int32 {.closure.} = + ec.worker.pos_x = args[0] mod (board.width.int32) + ec.worker.pos_y = args[0] div (board.width.int32) + ), + "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) @@ -59,14 +119,47 @@ proc main() = ) }) - let ec = MakeExecutionContext(funcs) +let docs = """ +Light Interpreter. + +Usage: + light run [--width=] [--height=] [--win_width=] [--win_height=] + light ast + light (-h | --help) + light --version + +Options: + -h --help Show this screen. + --width= Width of board [default: 64]. + --height= Height of board [default: 64]. + --win_width= Width of window [default: 1200]. + --win_height= Height of window [default: 700]. +""" + +type + RunOptions = object + filename: string + board_width: int + board_height: int + window_width: int + window_height: int + +proc RunProgram(options: RunOptions) = + let window = gfx_window.NewWindow(options.window_width.cint, options.window_height.cint, "Light Visualizer") + window.SetKeyCallback(key_down) + + var program = LoadProgram(options.filename) + + let board = CreateBoard(options.board_width, options.board_height) + board.InitRendering() + + let ec = MakeExecutionContext(CreateFuncs(window, board)) discard ExecuteProgram(ec, program) while not window.ShouldClose(): glClearColor(0, 0, 0, 1) glClear(GL_COLOR_BUFFER_BIT) - board.RebufferColors() board.Render() os.sleep(1) @@ -74,5 +167,39 @@ proc main() = window.CloseWindow() +proc PrintAst(filename: string) = + let program = LoadProgram(filename) + + echo "\n" & filename & "'s Abstract Syntax Tree" + for line in program.code: + echo line + echo "\n" + +proc main() = + random.randomize(getTime().toUnix()) + let args = docopt(docs, version = "Light programming language v0.1.0") + + if args["run"]: + var + board_width: int + board_height: int + window_width: int + window_height: int + discard parseInt($args["--width"], board_width) + discard parseInt($args["--height"], board_height) + discard parseInt($args["--win_width"], window_width) + discard parseInt($args["--win_height"], window_height) + let options = RunOptions( + filename: $args[""], + board_width: board_width, + board_height: board_height, + window_width: window_width, + window_height: window_height, + ) + RunProgram(options) + + if args["ast"]: + PrintAst($args[""]) + when isMainModule: main() diff --git a/src/lang/executer.nim b/src/lang/executer.nim index 4988ee2..7be2cf1 100644 --- a/src/lang/executer.nim +++ b/src/lang/executer.nim @@ -12,7 +12,7 @@ type var_5*, var_6*, var_7*, var_8*: LightInt pos_x*, pos_y*: LightInt - ExecFuncs = TableRef[string, proc(ec: ExecutionContext, args: openarray[LightInt]): LightInt] + ExecFuncs* = TableRef[string, proc(ec: ExecutionContext, args: openarray[LightInt]): LightInt] ExecutionContext* = ref object worker*: LightWorker @@ -113,7 +113,7 @@ proc EvalExpr(ec: ExecutionContext, exp: LightExpr): LightInt = if cond != 0: ExecuteLines(ec, exp.body) else: - 0 + ExecuteLines(ec, exp.else_body) of leWhile: while ec.running: @@ -135,15 +135,15 @@ proc EvalExpr(ec: ExecutionContext, exp: LightExpr): LightInt = ExecuteLines(ec, ec.defined_functions[exp.func_name]) else: - raise newException(ValueError, "Cannot call undefined function") + raise newException(ValueError, "Cannot call undefined function: " & exp.func_name) of leFuncDef: if ec.defined_functions.hasKey(exp.def_func_name): - raise newException(ValueError, "Cannot redefine function") + raise newException(ValueError, "Cannot redefine function: " & exp.def_func_name) else: ec.defined_functions[exp.def_func_name] = exp.func_body - 1 + 0 else: 0 @@ -151,7 +151,7 @@ proc ExecuteLines(ec: ExecutionContext, lines: seq[LightExpr]): LightInt = if not ec.running: return 0 - var last: LightInt + var last: LightInt = 0 for line in lines: last = EvalExpr(ec, line) if not ec.running: break diff --git a/src/lang/lexer.nim b/src/lang/lexer.nim index 6e754c8..aa27709 100644 --- a/src/lang/lexer.nim +++ b/src/lang/lexer.nim @@ -10,16 +10,21 @@ iterator Generate_tokens*(source: string): LightToken = if line.strip.startsWith("//"): continue - for token, is_sep in strutils.tokenize(line, {' ', ';', '\t', ',', '(', ')'}): + 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) + for ch in token.items: + if ch == ',': + yield LightToken(kind: ltParamDelim) + if ch == '{': + yield LightToken(kind: ltBlockStart) + if ch == '}': + yield LightToken(kind: ltBlockEnd) + if ch == '(': + yield LightToken(kind: ltParamStart) + if ch == ')': + yield LightToken(kind: ltParamEnd) + if ch == ';': + yield LightToken(kind: ltExprDelim) continue if token.startsWith('$'): @@ -29,16 +34,16 @@ iterator Generate_tokens*(source: string): LightToken = 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 = varX - elif varString == "pos_y": varName = varY + if varString == "m1": varName = var1 + elif varString == "m2": varName = var2 + elif varString == "m3": varName = var3 + elif varString == "m4": varName = var4 + elif varString == "m5": varName = var5 + elif varString == "m6": varName = var6 + elif varString == "m7": varName = var7 + elif varString == "m8": varName = var8 + elif varString == "x": varName = varX + elif varString == "y": varName = varY else: raise newException(IOError, "Invalid variable name.") @@ -55,6 +60,12 @@ iterator Generate_tokens*(source: string): LightToken = elif token == "=": yield LightToken(kind: ltEq) + elif token.startsWith("-") and token != "-": + var value: int + discard parseutils.parseInt(token, value) + + yield LightToken(kind: ltNum, value: value.LightInt) + elif token.isDigit: var value: int discard parseutils.parseInt(token, value) @@ -63,21 +74,17 @@ iterator Generate_tokens*(source: string): LightToken = elif token.toLowerAscii == "if": yield LightToken(kind: ltIf) + elif token.toLowerAscii == "else": + yield LightToken(kind: ltElse) 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 == "{": + elif token.toLowerAscii == "then" or token.toLowerAscii == "do": yield LightToken(kind: ltBlockStart) - elif token.toLowerAscii == "end" or token == "}": + elif token.toLowerAscii == "end": 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 "+": diff --git a/src/lang/parser.nim b/src/lang/parser.nim index 1019884..c28d4e1 100644 --- a/src/lang/parser.nim +++ b/src/lang/parser.nim @@ -40,11 +40,23 @@ func NextExpr(parser: LightParser, prev: LightExpr, stop_at: set[LightTokenType] parser.tokens.Step() - if curr.kind in {ltNum, ltVar} and prev.kind == leNull: + if curr.kind in {ltNum, ltVar, ltFunc} and prev.kind == leNull: let prevExpr = case curr.kind: of ltNum: LightExpr(kind: leNumLit, value: curr.value) of ltVar: LightExpr(kind: leVar, var_name: curr.var_name) + of ltFunc: + if parser.tokens.Current.kind != ltParamStart: + raise newException(ValueError, "Expected parameter list after function call") + + parser.tokens.Step() + let params = Parse_block(parser.tokens, ltParamDelim, ltParamEnd) + + LightExpr( + kind: leFuncCall, + func_name: curr.func_name, + params: params + ) else: LightExpr(kind: leNull) return parser.NextExpr(prevExpr, stop_at) @@ -71,32 +83,25 @@ func NextExpr(parser: LightParser, prev: LightExpr, stop_at: set[LightTokenType] expression: next ) - elif curr.kind == ltLabel: - return LightExpr( - kind: leLabel, - label: curr.label_name - ) - - elif curr.kind == ltGoto: - let next = parser.tokens.Current - if next.kind != ltLabel: - raise newException(ValueError, "Expected label after goto") - - else: - return LightExpr( - kind: leGoto, - label: next.label_name - ) - elif curr.kind == ltIf: let condition = parser.NextExpr(LightExpr(kind: leNull), {ltBlockStart}) parser.tokens.Step() let body = Parse_block(parser.tokens, ltExprDelim, ltBlockEnd) + let else_body = + if parser.tokens.Current.kind == ltElse: + parser.tokens.Step() + parser.tokens.Step() + Parse_block(parser.tokens, ltExprDelim, ltBlockEnd) + else: + @[] + + return LightExpr( kind: leIf, condition: condition, - body: body + body: body, + else_body: else_body ) elif curr.kind == ltWhile: @@ -114,19 +119,6 @@ func NextExpr(parser: LightParser, prev: LightExpr, stop_at: set[LightTokenType] return LightExpr( kind: leBreak ) - - elif curr.kind == ltFunc: - if parser.tokens.Current.kind != ltParamStart: - raise newException(ValueError, "Expected parameter list after function call") - - parser.tokens.Step() - let params = Parse_block(parser.tokens, ltParamDelim, ltParamEnd) - - return LightExpr( - kind: leFuncCall, - func_name: curr.func_name, - params: params - ) elif curr.kind == ltFuncDef: if parser.tokens.Current.kind != ltBlockStart: diff --git a/src/lang/program.nim b/src/lang/program.nim index 1dbfce0..0a72c14 100644 --- a/src/lang/program.nim +++ b/src/lang/program.nim @@ -1,6 +1,7 @@ import sequtils import tables import ./types/ast +import ./types/tokens import ./lexer import ./parser diff --git a/src/lang/types/ast.nim b/src/lang/types/ast.nim index 1cd98b6..66a587f 100644 --- a/src/lang/types/ast.nim +++ b/src/lang/types/ast.nim @@ -1,3 +1,5 @@ +import sequtils +import strutils import ./types import ./tokens @@ -8,13 +10,11 @@ type leNumLit = 2, leOp = 3, leAssign = 4, - leLabel = 5, - leGoto = 6, - leIf = 7, - leWhile = 8, - leBreak = 9, - leFuncCall = 10, - leFuncDef = 11, + leIf = 5, + leWhile = 6, + leBreak = 7, + leFuncCall = 8, + leFuncDef = 9, LightExpr* = ref object case kind*: LightExprType @@ -29,11 +29,10 @@ type of leAssign: variable*: LightVariable expression*: LightExpr - of leLabel, leGoto: - label*: string of leIf, leWhile: condition*: LightExpr body*: seq[LightExpr] + else_body*: seq[LightExpr] of leFuncCall: func_name*: string params*: seq[LightExpr] @@ -43,17 +42,28 @@ type 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 +func `$`*(exp: LightExpr): string +func printExpr(exp: LightExpr, ind: int): string + +func multiline(things: seq[LightExpr], ind: int): string = + return things.foldl(a & printExpr(b, ind) & "\n", "")[0..^2] + +func printExpr(exp: LightExpr, ind: int): string = + let ts = strutils.repeat(" ", ind) + ts & ( + case exp.kind: + of leVar: "var[" & $exp.var_name & "]" + of leNumLit: "num[" & $exp.value & "]" + of leOp: "op[" & $exp.operation & ", " & printExpr(exp.left, 0) & ", " & printExpr(exp.right, 0) & "]" + of leAssign: "assignment[" & $exp.variable & ", " & printExpr(exp.expression, 0) & "]" + of leIf: "if [" & printExpr(exp.condition, 0) & "] {\n" & multiline(exp.body, ind + 1) & "\n" & ts & "} else {\n" & multiline(exp.else_body, ind + 1) & "\n" & ts & "}" + of leWhile: "while [" & printExpr(exp.condition, 0) & "] {\n" & multiline(exp.body, ind + 1) & "\n" & ts & "}" + of leBreak: "break" + of leFuncCall: "funcCall[" & exp.func_name & ", " & $exp.params & "]" + of leFuncDef: "funcDef[" & exp.def_func_name & "] {\n" & multiline(exp.func_body, ind + 1) & "\n" & ts & "}" + of leNull: "NullExpr[]" + else: "UNDEFINED[]" + ) + +func `$`*(exp: LightExpr): string = + printExpr(exp, 0) diff --git a/src/lang/types/tokens.nim b/src/lang/types/tokens.nim index b9ceaec..8247db8 100644 --- a/src/lang/types/tokens.nim +++ b/src/lang/types/tokens.nim @@ -5,8 +5,7 @@ type ltNull, ltVar, ltNum, ltExprDelim, - ltLabel, ltGoto, - ltIf, ltWhile, + ltIf, ltElse, ltWhile, ltBlockStart, ltBlockEnd, ltBreak, ltFunc, @@ -21,8 +20,6 @@ type var_name*: LightVariable of ltNum: value*: LightInt - of ltLabel: - label_name*: string of ltFunc, ltFuncDef: func_name*: string of ltOp: @@ -51,8 +48,6 @@ proc `$`*(token: LightToken): string = 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"