├── .gitignore ├── LICENSE ├── README.md ├── tnim.html ├── tnim.nim └── tnim.nimble /.gitignore: -------------------------------------------------------------------------------- 1 | nimcache/ 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017 jlp765 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # tnim 2 | TinyNim - a REPL for Nim 3 | 4 | *Try* **Nim Playground** *(https://play.nim-lang.org/) for an online experience* 5 | 6 | This is an interactive sandbox for testing Nim code 7 | 8 | `nim secret` also provides an interactive NIM experience (note: `nim secret` uses the VM in Nim, so it only allows the import of a subset of modules) 9 | 10 | *`tnim` is SLOW!!. It is a quick and dirty interactive tool, not a sleek and shiny speed demon.* 11 | 12 | `tnim` is assumed to not work with multitasking (async library, et. al.) 13 | 14 | Instructions are in the **tnim.html** file or **\?** at the tnim command line 15 | 16 | The code buffer is saved to the file **tnim_dat.dat** (in the "current" directory). You can add code to this file if you want to do development using a REPL interface. 17 | 18 | *Note from Nimble doco (ensuring tnim can run):* 19 | 20 | * Nimble stores everything that has been installed in ~/.nimble on Unix systems and in your $home/.nimble on Windows. Libraries are stored in $nimbleDir/pkgs, and binaries are stored in **$nimbleDir/bin**. 21 | 22 | * However, some Nimble packages can provide additional tools or commands. **If you don't add their location ($nimbleDir/bin) to your $PATH** they will not work properly and you won't be able to run them. 23 | 24 | (alternately, you can copy/link the tnim executable to a suitable location) 25 | 26 | ## Changes 27 | 2.0.5 28 | ----- 29 | 30 | * Minor change of .add() to []= for table related code (eliminate deprecation warnings) 31 | * Bug fix: check code length when checking for "block" 32 | 33 | 2.0.4 34 | ----- 35 | 36 | * Minor readability changes. 37 | 38 | 2.0.3 39 | ----- 40 | 41 | * Minor nimble config change. 42 | 43 | 2.0.2 44 | ----- 45 | 46 | * If there is a compilation error, the last line of code is removed from the code buffer. (https://github.com/jlp765/tnim/issues/6) 47 | 48 | NB: This assumes the code was typed and the error is with the last line. If multi lines of code has been pasted into stdin and the last line of code is not in error, 49 | then you will need to add the last line of code back, as well as fix whichever line has an error. 50 | 51 | 2.0.1 52 | ----- 53 | 54 | * EDITOR environment variable if set defines the default editor (thanks **@subsetpark**) 55 | 56 | 2.0.0 57 | ----- 58 | 59 | * uses rdstdin (linenoise) for friendlier input handling (thanks **@subsetpark**) 60 | * **edit the code buffer** (\ed) using an external editor, which defaults to **notepad** on windows and **vi** on linux/macosx (untested on macosx) 61 | * define an external editor (\ec /bin/user/vi) 62 | * bug fix: no longer adds a extra line to the code buffer on exit 63 | * displays version and help commands on startup (to help newbies) before listing the code buffer 64 | -------------------------------------------------------------------------------- /tnim.html: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | Module tnim 20 | 1165 | 1166 | 1167 | 1168 | 1193 | 1194 | 1195 | 1196 |
1197 |
1198 |

Module tnim

1199 |
1200 |
1201 |
1202 | Search: 1204 |
1205 |
1206 | Group by: 1207 | 1211 |
1212 | 1251 | 1252 |
1253 |
1254 |
1255 |

TNim (TinyNim) is a quasi-interactive REPL

1256 |

It is a stop-gap replacement for the functionality that was in old versions of Nim, and is now nim secret (note: nim secret uses the VM in Nim, so it only allows the import of a subset of modules)

1257 |

It compiles and runs code similar to the way you would do this, and does this using a shell command in the background ( nim c -r --verbosity:0 --hints:off <file> )

1258 |

Warning: this is SLOW!!. It is a quick and dirty interactive tool, not a sleek and shiny speed demon.

1259 |

If you need to work with blocks of code as part of some project, then TNim can be primed with this code prior to being run (rather than having to paste chunks of code into TNim). Add this code to the SavedFileName (tnim_dat.dat), then run TNim.

1260 |

If the buffers are not cleared (\qc or \c), then the code will remain in the SavedFileName, and will be available next time TNim is run.

1261 | 1262 |

Commands:

\?,  \h, \help             this information.
1263 | \l,  \list                 list the previous code history (w/ line nr's)
1264 | \ln, \listnn               list with No (line) Numbers (raw code listing).
1265 | \c,  \clear                clear the current history buffer.
1266 | \d,  \delete [f [t]]       delete lines(s) [f [optionally to t]].
1267 |                            delete last line if none specified.
1268 | \e,  \eval                 force the eval (compile/run) of the code buffer.
1269 | \ec, \edconfig <editor>    define the path/name to an external editor
1270 |                            (if not defined, uses notepad (win) or vi)
1271 | \ed, \edit                 edit code in the code buffer.
1272 |                            (then reloads the code buffer, lists the code,
1273 |                             and evals (compile/run) the code)
1274 | \r,  \read <filename>      read code from <filename> and run.
1275 |                            Saved history is read on startup.
1276 |                            data from file is auto evaluated after reading.
1277 | \s,  \set [<option=value>] set {maxBlocks,indent}
1278 | \v,  \version              display the name and version.
1279 | \w,  \write [<filename>]   write code history [to <filename>].
1280 |                            \w by itself overwrites saved history (tnim_dat.dat).
1281 |                            \c followed by \w clears saved history.
1282 | \q,  \quit                 quit, saving code history to tnim_dat.dat file.
1283 | \qc, \quitclear            quit, clearing code history in tnim_dat.dat file.
1284 |

Vars and Consts

The Vars and Consts Sections is included to provide clues about the TNim internal settings.

1285 |

1286 |
1287 |

Imports

1288 |
1289 | strutils, tables, os, osproc, rdstdin 1290 |
1291 |
1292 |

Vars

1293 |
1294 |
maxBlocks = 100000
1295 |
1296 | code blocks, or lines of code not in a code block 1297 | 1298 |
1299 |
indentSize = 2
1300 |
1301 | 1302 | 1303 |
1304 |
editorPath = ""
1305 |
1306 | set this via ec command 1307 | 1308 |
1309 | 1310 |
1311 |
1312 |

Consts

1313 |
1314 |
TnimName = "TNim"
1315 |
1316 | 1317 | 1318 |
1319 |
TnimVersion = 2.01
1320 |
1321 | 1322 | 1323 |
1324 |
TnimStart = "nim> "
1325 |
1326 | the TNim prompt 1327 | 1328 |
1329 |
TnimContinue = ".... "
1330 |
1331 | 1332 | 1333 |
1334 |
SavedFileName = "tnim_dat.dat"
1335 |
1336 | this file will hold the code you have typed (until cleared), or you can add code to this before file prior to running TNim 1337 | 1338 |
1339 | 1340 |
1341 | 1342 |
1343 |
1344 | 1345 |
1346 | 1351 |
1352 |
1353 |
1354 | 1355 | 1356 | 1357 | -------------------------------------------------------------------------------- /tnim.nim: -------------------------------------------------------------------------------- 1 | ## **TNim** (TinyNim) is a quasi-interactive REPL 2 | ## 3 | ## It is a stop-gap replacement for the 4 | ## functionality that was in old versions of Nim, and 5 | ## is now 6 | ## ``nim secret`` 7 | ## (note: nim secret uses the VM in Nim, so it only allows the import of a subset of modules) 8 | ## 9 | ## It compiles and runs code similar to the 10 | ## way you would do this, and does this using a shell 11 | ## command in the background ( 12 | ## ``nim c -r --verbosity:0 --hints:off `` ) 13 | ## 14 | ## *Warning: this is SLOW!!. It is a quick and dirty 15 | ## interactive tool, not a sleek and shiny speed demon.* 16 | ## 17 | ## If you need to work with blocks of code as part of some project, then TNim can be primed with this code 18 | ## prior to being run (rather than having to paste chunks of code into TNim). Add this code to 19 | ## the `SavedFileName<#SavedFileName>`_ (tnim_dat.dat), then run TNim. 20 | ## 21 | ## If the buffers are not cleared (``\qc`` or ``\c``), then the code will remain in 22 | ## the `SavedFileName<#SavedFileName>`_, and 23 | ## will be available next time TNim is run. 24 | ## 25 | ## Commands: 26 | ## --------- 27 | ## .. code-block:: Nim 28 | ## 29 | ## \?, \h, \help this information. 30 | ## \l, \list list the previous code history (w/ line nr's) 31 | ## \ln, \listnn list with No (line) Numbers (raw code listing). 32 | ## \c, \clear clear the current history buffer. 33 | ## \d, \delete [f [t]] delete lines(s) [f [optionally to t]]. 34 | ## delete last line if none specified. 35 | ## \e, \eval force the eval (compile/run) of the code buffer. 36 | ## \ec, \edconfig define the path/name to an external editor 37 | ## (if not defined, uses notepad (win) or vi) 38 | ## \ed, \edit edit code in the code buffer. 39 | ## (then reloads the code buffer, lists the code, 40 | ## and evals (compile/run) the code) 41 | ## \r, \read read code from and run. 42 | ## Saved history is read on startup. 43 | ## data from file is auto evaluated after reading. 44 | ## \s, \set [] set {maxBlocks,indent} 45 | ## \v, \version display the name and version. 46 | ## \w, \write [] write code history [to ]. 47 | ## \w by itself overwrites saved history (tnim_dat.dat). 48 | ## \c followed by \w clears saved history. 49 | ## \q, \quit quit, saving code history to tnim_dat.dat file. 50 | ## \qc, \quitclear quit, clearing code history in tnim_dat.dat file. 51 | ## 52 | ## Vars and Consts 53 | ## ----- 54 | ## The Vars and Consts Sections is included to provide clues about the TNim internal settings. 55 | ## 56 | import strutils, tables, os, osproc, rdstdin 57 | 58 | const 59 | TnimName* = "TNim" 60 | TnimVersion* = 2.06 61 | TnimStart* = "nim> " ## the TNim prompt 62 | TnimContinue* = ".... " # add "..".repeat(n) before this 63 | SavedFileName* = "tnim_dat.dat" ## this file will hold the code you have typed (until cleared), or you can add code 64 | ## to this before file prior to running TNim 65 | 66 | # run-time Configurable but effectively const Config variables 67 | var 68 | maxBlocks* = 100_000 ## code blocks, or lines of code not in a code block 69 | indentSize* = 2 70 | editorPath* = "" ## set this via \ec command 71 | 72 | type 73 | CodeBlock = object ## blocks of code (a block is the outer scope level) 74 | lines: seq[string] 75 | compiles: bool 76 | firstOutput: string 77 | lastOutput: string 78 | 79 | CodeBlocks = seq[CodeBlock] 80 | #PCodeBlocks = ptr CodeBlocks 81 | 82 | EvalOutput = object 83 | msg: seq[string] 84 | output: seq[string] 85 | 86 | EvalOutputs = seq[EvalOutput] 87 | #PEvalOutputs = ptr EvalOutputs 88 | 89 | 90 | var 91 | code: CodeBlocks = @[] # a code block is multi lines for if, proc, block, etc 92 | evalResults: EvalOutputs = @[] 93 | blockNr: int = 0 # index of next block to add, not current blockNr 94 | currIndent = 0 # starts at 0 for no indent at top scope level 95 | inputCmds = initTable[string, proc(w: seq[string])]() 96 | getOut = false # flag to trigger exit of REPL 97 | #currDir = getAppDir() 98 | doEval = false # force re-evaluation of the code buffer 99 | 100 | # ---------------- forward declarations ----------- 101 | proc tnimClear(w: seq[string]) 102 | proc tnimDelete(w: seq[string]) 103 | proc tnimEval(w: seq[string]) 104 | proc tnimEdit(w: seq[string]) 105 | proc tnimEdConfig(w: seq[string]) 106 | proc tnimHelp(w: seq[string]) 107 | proc tnimList(w: seq[string]) 108 | proc tnimNrList(w: seq[string]) 109 | proc tnimQuit(w: seq[string]) 110 | proc tnimQuitClear(w: seq[string]) 111 | proc tnimRead(w: seq[string]) 112 | proc tnimSet(w: seq[string]) 113 | proc tnimWrite(w: seq[string]) 114 | proc tnimVersion(w: seq[string]) 115 | 116 | # ---------------- general stuff ------------------ 117 | proc doInit() = 118 | inputCmds[r"\?" ] = tnimHelp 119 | inputCmds[r"\h" ] = tnimHelp 120 | inputCmds[r"\help" ] = tnimHelp 121 | inputCmds[r"\l" ] = tnimNrList 122 | inputCmds[r"\list" ] = tnimNrList 123 | inputCmds[r"\ln" ] = tnimList 124 | inputCmds[r"\listnn" ] = tnimList 125 | inputCmds[r"\c" ] = tnimClear 126 | inputCmds[r"\clear" ] = tnimClear 127 | inputCmds[r"\d" ] = tnimDelete 128 | inputCmds[r"\delete" ] = tnimDelete 129 | inputCmds[r"\e" ] = tnimEval 130 | inputCmds[r"\eval" ] = tnimEval 131 | inputCmds[r"\ed" ] = tnimEdit 132 | inputCmds[r"\edit" ] = tnimEdit 133 | inputCmds[r"\ec" ] = tnimEdConfig 134 | inputCmds[r"\edconfig" ] = tnimEdConfig 135 | inputCmds[r"\v" ] = tnimVersion 136 | inputCmds[r"\version" ] = tnimVersion 137 | inputCmds[r"\w" ] = tnimWrite 138 | inputCmds[r"\write" ] = tnimWrite 139 | inputCmds[r"\r" ] = tnimRead 140 | inputCmds[r"\read" ] = tnimRead 141 | inputCmds[r"\s" ] = tnimSet 142 | inputCmds[r"\set" ] = tnimSet 143 | inputCmds[r"\q" ] = tnimQuit 144 | inputCmds[r"\quit" ] = tnimQuit 145 | inputCmds[r"\qc" ] = tnimQuitClear 146 | inputCmds[r"\quitclear"] = tnimQuitClear 147 | 148 | proc errMsg(s:string) = 149 | writeLine(stderr, TnimStart & "Error: " & s) 150 | 151 | #proc add(cb: var CodeBlocks, lines: seq[string]) = 152 | # var newCB: CodeBlock 153 | # newCB.lines = lines 154 | # newCB.compiles = false 155 | # cb.add(newCB) 156 | 157 | proc add(cb: var CodeBlocks, line: string) = 158 | var newCB: CodeBlock 159 | newCB.lines = @[line] 160 | newCB.compiles = false 161 | cb.add(newCB) 162 | inc(blockNr) 163 | 164 | proc getCmdLineOpts() = 165 | ## get any configuration and running options 166 | discard 167 | 168 | proc words(s: string): seq[string] {.inline.} = 169 | ## strip leading/trailing space and split into words 170 | ## returning a seq of words (string) 171 | result = s.strip(leading=true, trailing=true).split() 172 | 173 | proc isDigits(s: string): bool = 174 | ## return true if all chars are Digits 175 | result = (s.len > 0) 176 | for c in s: 177 | result = result and (c in Digits) 178 | 179 | proc getIndent(s: string): int = 180 | ## number of indent spaces at start of line 181 | ## base on the setting of indentSize (default=2) 182 | ## so getIndent is 1 for two spaces when indentSize=2 183 | var spaceCnt = 0 184 | result = 0 185 | for i,c in pairs(s): 186 | if c == ' ': inc(spaceCnt) 187 | else: break 188 | let x = spaceCnt.`div`(indentSize) 189 | # allow for end of indent shown by change in indent 190 | if x < currIndent: currIndent = x 191 | # check event nr of spaces 192 | #if spaceCnt != (x * indentSize): 193 | # if spaceCnt < (x * indentSize): 194 | # dec(indentSize) 195 | # result = x 196 | # else: 197 | # errMsg("indentation is incorrect") 198 | # result = -1 199 | #else: 200 | result = x 201 | 202 | proc getInt(s: string): int = 203 | var 204 | i = 0 205 | result = 0 206 | while i < s.len and s[i] notIn Digits: 207 | inc(i) 208 | while i < s.len and s[i] in Digits: 209 | result = 10 * result + ord(s[i]) - ord('0') 210 | inc(i) 211 | 212 | proc getCodeLine(ln: int): string = 213 | # linenumber ln is a 1.. based index, not a seq[] index 214 | var 215 | actLineNr = 0 216 | cIndx = 0 217 | result = "" 218 | while cIndx < code.len: 219 | for j in 0.. define the path/name to an external editor 300 | (if not defined, uses notepad (win) or vi) 301 | \ed, \edit edit code in the code buffer. 302 | (then reloads the code buffer, lists the code, 303 | and evals (compile/run) the code) 304 | \r, \read read code from and run. 305 | Saved history is read on startup. 306 | data from file is auto evaluated after reading. 307 | \s, \set [] set {maxBlocks,indent} 308 | \v, \version display the name and version. 309 | \w, \write [] write code history [to ]. 310 | \w by itself overwrites saved history (tnim_dat.dat). 311 | \c followed by \w clears saved history. 312 | \q, \quit quit, saving code history to tnim_dat.dat file. 313 | \qc, \quitclear quit, clearing code history in tnim_dat.dat file. 314 | """ 315 | 316 | proc deleteCodeLine(lineNrFrom: int, lineNrTo: int) = 317 | var 318 | i = 0 319 | lnTo = if lineNrTo == -1: lineNrFrom else: lineNrTo 320 | lnFrom = lineNrFrom 321 | for cBlock in mitems(code): 322 | for j in 0..= lnFrom and i <= lnTo: 324 | cBlock.lines[j] = "" 325 | inc(i) 326 | dec(i) 327 | 328 | if lineNrFrom == -1: lnFrom = i # delete last line 329 | 330 | for cb in countDown(code.len-1, 0): 331 | for j in countDown(code[cb].lines.len-1, 0): 332 | if i >= lineNrFrom and i <= lnTo and code[cb].lines[j] == "": 333 | code[cb].lines.delete(j) 334 | dec(i) 335 | 336 | proc lastLineNr(): int = 337 | var i = 0 338 | if code.len == 0: return -1 339 | for cBlock in items(code): 340 | for s in cBlock.lines: 341 | inc(i) 342 | return i - 1 343 | 344 | proc deleteLastLine() = 345 | # if an error compiling, then this is called 346 | # to delete last line of code 347 | let lln = lastLineNr() 348 | deleteCodeLine(lln, lln) 349 | 350 | proc listCode(f: File, withln = false) = 351 | var i = 0 352 | if code.len == 0: return 353 | for cBlock in items(code): 354 | for s in cBlock.lines: 355 | if i > 0: f.writeLine("") 356 | if withln: 357 | f.write(align($i,5) & ": " & s) 358 | else: 359 | f.write(s) 360 | inc(i) 361 | 362 | # --------- tnimXXXXX() procedures ----------------- 363 | 364 | proc tnimList(w: seq[string]) = 365 | listCode(stdout) 366 | doEval = false 367 | echo "" 368 | 369 | proc tnimNrList(w: seq[string]) = 370 | listCode(stdout, true) 371 | doEval = false 372 | echo "" 373 | 374 | proc tnimClear(w: seq[string]) = 375 | blockNr = 0 376 | code.setLen(0) 377 | evalResults.setLen(0) 378 | doEval = false 379 | 380 | proc tnimDelete(w: seq[string]) = 381 | var 382 | f, t = -1 383 | if w.len >= 3: t = w[2].parseInt 384 | if w.len >= 2: f = w[1].parseInt 385 | if t == -1 and f != -1: t = f 386 | deleteCodeLine(f, t) 387 | tnimNrList(w) 388 | doEval = false 389 | 390 | proc tnimEval(w: seq[string]) = 391 | doEval = true 392 | 393 | proc tnimWrite(w: seq[string]) = 394 | var 395 | fn = if w.len > 1: w[1] else: SavedFileName 396 | f: File = open(fn, mode=fmWrite) 397 | f.listCode() 398 | f.close() 399 | doEval = false 400 | 401 | proc tnimRead(w: seq[string]) = 402 | var 403 | fn = if w.len > 1: w[1] else: SavedFileName 404 | f: File 405 | hasCode = false 406 | if fileExists(fn): 407 | f = open(fn) 408 | var lines = f.readAll().splitLines() 409 | f.close() 410 | for line in lines: 411 | if not hasCode: 412 | if line.len == 0: 413 | continue 414 | else: hasCode = true 415 | code.add(line) 416 | tnimEval(w) 417 | elif fn != SavedFileName: 418 | errMsg("Unable to find file: " & fn) 419 | 420 | proc tnimSet(w: seq[string]) = 421 | proc showItems() = 422 | echo "maxBlocks: ",maxBlocks 423 | echo "indentSize: ",indentSize 424 | 425 | if w.len <= 1: showItems() 426 | else: 427 | var wrds = w[1.. 1: 484 | editorPath = w[1] 485 | else: 486 | discard checkOrSetEditor() 487 | echo "Editor: ",editorPath 488 | 489 | proc tnimEdit(w: seq[string]) = 490 | ## If an editorPath defined, use that editor 491 | ## Else 492 | ## clear the screen, display the code buffer 493 | ## and change the code 494 | var 495 | res = 0 496 | if not checkOrSetEditor(): return 497 | if not editorPath.fileExists: 498 | echo "Error: " & editorPath & " not found" 499 | editorPath = "" 500 | else: 501 | res = execCmd(editorPath & " tnim_dat.dat") 502 | if res == 0: 503 | tnimClear(@[]) 504 | tnimRead(@[SavedFileName]) 505 | tnimNrList(@[]) 506 | tnimEval(@[]) 507 | else: 508 | echo "Editing failed: returned ",res 509 | 510 | # -------------- EVAL --------------------------- 511 | proc nimEval(inp: string): tuple[res: bool, resStr: string] = 512 | # true if something to print 513 | var 514 | res = false 515 | resStr = "" 516 | iput = inp.words() 517 | 518 | if iput.len == 0: 519 | if currIndent > 0: currIndent = 0 # continue with eval 520 | else: return (res, resStr) 521 | else: 522 | if inputCmds.hasKey(iput[0]): 523 | # eval user commands 524 | var 525 | cmdToRun = inputCmds[iput[0]] # get command to run 526 | cmdToRun(iput) # tnimEval can set the doEval flag 527 | if not doEval: 528 | return (res, resStr) 529 | else: 530 | doEval = false 531 | let (_, rs) = runEval() 532 | return (true, rs) 533 | 534 | if blockNr == maxBlocks: 535 | errMsg("History buffer is full. Write(\\w) and/or Clear (\\c) the history") 536 | return (res, resStr) 537 | # handle a line of code, checking if indent is required 538 | let ident = getIndent(inp) 539 | #if ident == currIndent: # ident should match currIndent 540 | if ident >= 0 and code.len-1 == blockNr: 541 | code[blockNr].lines.add(inp) 542 | else: 543 | code.add(inp) 544 | let lastWrd = iput[iput.len-1] 545 | # if block identified by ':' then inc indent 546 | if lastWrd[lastWrd.len-1] == ':': 547 | inc(currIndent) 548 | # multi-line statement or proc() definition 549 | elif lastWrd[lastWrd.len-1] == ',': # don't eval, more to come 550 | return (res, resStr) 551 | # proc() definition on one line (comment on end of line not handled!) 552 | elif iput[0] in ["proc", "iterator", "method", "converter"] and 553 | lastWrd[lastWrd.len-1] == '=': 554 | inc(currIndent) 555 | # proc() definition on multi lines 556 | elif iput[0] in ["template", "macro"]: 557 | inc(currIndent) 558 | # proc() definition on multi lines 559 | elif ident > 0 and lastWrd[lastWrd.len-1] == '=': 560 | inc(currIndent) 561 | elif iput[0][0..4] == "block": 562 | inc(currIndent) 563 | #elif ident != -1: 564 | # errMsg("indentation is incorrect") 565 | 566 | doEval = false # reset the flag 567 | if currIndent > 0: return (res, resStr) 568 | # 569 | # eval code 570 | # 571 | let (_, rStr) = runEval() 572 | return (true, rStr) 573 | 574 | # -------------- PRINT --------------------------- 575 | proc print(s: string) {.inline.} = 576 | writeLine(stdout, s) 577 | 578 | proc startMsg(): string {.inline.} = 579 | ## when indented, print the "..." else the "nim> " text 580 | result = (if currIndent == 0: TnimStart else: TnimContinue) 581 | 582 | # -------------- READ --------------------------- 583 | proc readFromStdin(msg: string): string = 584 | result = r"\qc" 585 | try: 586 | result = readLineFromStdin(msg) 587 | except: 588 | tnimQuitClear(@[r"\qc"]) 589 | 590 | # -------------- REPL --------------------------- 591 | proc REPL() = 592 | ## main processing loop 593 | var 594 | inp = "" 595 | while not getOut: 596 | inp = readFromStdin(startMsg()) # R 597 | let (res, resStr) = nimEval(inp) # E 598 | if res: print(resStr) # P 599 | 600 | 601 | proc main() = 602 | doInit() 603 | # get previous code 604 | tnimRead(@[SavedFileName]) 605 | # get command line options 606 | getCmdLineOpts() 607 | # display version 608 | tnimVersion(@[]) 609 | # display help commands 610 | tnimHelp(@[]) 611 | print(startMsg()) 612 | # show current code buffer 613 | tnimNrList(@[]) 614 | # and away it runs 615 | REPL() 616 | tnimWrite(@[SavedFileName]) 617 | 618 | when isMainModule: 619 | main() 620 | -------------------------------------------------------------------------------- /tnim.nimble: -------------------------------------------------------------------------------- 1 | [Package] 2 | name = "tnim" 3 | version = "2.0.6" 4 | author = "James Parkinson" 5 | description = "Nim REPL - a sandbox for testing Nim code" 6 | license = "MIT" 7 | 8 | bin = "tnim" 9 | binDir = "bin" 10 | 11 | [Deps] 12 | requires: "nim >= 0.10.0" 13 | --------------------------------------------------------------------------------