all repos — min @ 3dbe830d6e0fa242953b2a7f80034c0a9669e497

A small but practical concatenative programming language.

Now statically linking OpenSSL, using min for release management, etc.
h3rald h3rald@h3rald.com
Fri, 04 Dec 2020 18:10:12 +0100
commit

3dbe830d6e0fa242953b2a7f80034c0a9669e497

parent

f4cda958d6d369c3b5abbced9ced71a396f6541b

M core/consts.nimcore/consts.nim

@@ -1,5 +1,20 @@

-const - pkgName* = "min" - pkgVersion* = "0.22.0" - pkgAuthor* = "Fabio Cevasco" - pkgDescription* = "A tiny concatenative programming language and shell." +import + strutils + +const ymlconfig = "../min.yml".slurp + +var pkgName* {.threadvar.}: string +var pkgVersion* {.threadvar.}: string +var pkgAuthor* {.threadvar.}: string +var pkgDescription* {.threadvar.}: string + +for line in ymlconfig.split("\n"): + let pair = line.split(":") + if pair[0].strip == "name": + pkgName = pair[1].strip + if pair[0].strip == "version": + pkgVersion = pair[1].strip + if pair[0].strip == "author": + pkgAuthor = pair[1].strip + if pair[0].strip == "description": + pkgDescription = pair[1].strip
M core/env.nimcore/env.nim

@@ -6,7 +6,11 @@ HOME = getenv("USERPROFILE")

if not defined(windows): HOME = getenv("HOME") -let MINRC* = HOME / ".minrc" -let MINSYMBOLS* = HOME / ".min_symbols" -let MINHISTORY* = HOME / ".min_history" -let MINLIBS* = HOME / ".minlibs" +var MINRC* {.threadvar.} : string +MINRC = HOME / ".minrc" +var MINSYMBOLS* {.threadvar.} : string +MINSYMBOLS = HOME / ".min_symbols" +var MINHISTORY* {.threadvar.} : string +MINHISTORY = HOME / ".min_history" +var MINLIBS* {.threadvar.} : string +MINLIBS = HOME / ".minlibs"
M core/parser.nimcore/parser.nim

@@ -87,7 +87,7 @@ parent*: ref MinScope

symbols*: CritBitTree[MinOperator] sigils*: CritBitTree[MinOperator] kind*: MinScopeKind - MinOperatorProc* = proc (i: In) {.closure.} + MinOperatorProc* = proc (i: In) {.closure, gcsafe.} MinOperatorKind* = enum minProcOp minValOp
M lib/min_http.nimlib/min_http.nim

@@ -6,7 +6,8 @@ ../core/value,

../core/interpreter, ../core/utils -let minUserAgent = "$1 http-module/$2" % [pkgName, pkgVersion] +var minUserAgent {.threadvar.} : string +minUserAgent = "$1 http-module/$2" % [pkgName, pkgVersion] proc newCli(): HttpClient = return newHttpClient(userAgent = minUseragent)

@@ -23,7 +24,7 @@

proc http_module*(i: In)= let def = i.define() - def.symbol("request") do (i: In): + def.symbol("request") do (i: In) {.gcsafe.}: let vals = i.expect "dict" let req = vals[0] let cli = newCli()

@@ -65,7 +66,7 @@ let url = vals[1]

let cli = newCli() cli.downloadFile(url.getString, file.getString) - def.symbol("start-server") do (ii: In): + def.symbol("start-server") do (ii: In) {.gcsafe.}: let vals = ii.expect "dict" let cfg = vals[0] if not cfg.dhas("port"):
M lib/min_io.nimlib/min_io.nim

@@ -62,7 +62,7 @@ if c mod n.intVal == 0:

echo "" echo "" - def.symbol("gets") do (i: In): + def.symbol("gets") do (i: In) {.gcsafe.}: var ed = initEditor() i.push ed.readLine().newVal

@@ -75,17 +75,17 @@ if ch[0].getString.len != 1:

raiseInvalid("Symbol putch requires a string containing a single character.") putchr(ch[0].getString[0].cint) - def.symbol("password") do (i: In): + def.symbol("password") do (i: In) {.gcsafe.}: var ed = initEditor() i.push ed.password("Enter Password: ").newVal - def.symbol("ask") do (i: In): + def.symbol("ask") do (i: In) {.gcsafe.}: var ed = initEditor() let vals = i.expect("string") let s = vals[0] i.push ed.readLine(s.getString & ": ").newVal - def.symbol("confirm") do (i: In): + def.symbol("confirm") do (i: In) {.gcsafe.}: var ed = initEditor() let vals = i.expect("string") let s = vals[0]

@@ -100,7 +100,7 @@ stdout.write "Invalid answer. Please enter 'yes' or 'no': "

return confirm() i.push confirm().newVal - def.symbol("choose") do (i: In): + def.symbol("choose") do (i: In) {.gcsafe.}: var ed = initEditor() let vals = i.expect("'sym", "quot") let s = vals[0]
M lib/min_lang.nimlib/min_lang.nim

@@ -529,7 +529,7 @@ i.push pkgVersion.newVal

# Save/load symbols - def.symbol("save-symbol") do (i: In): + def.symbol("save-symbol") do (i: In) {.gcsafe.}: let vals = i.expect("'sym") let s = vals[0] let sym = s.getString
M lib/min_str.nimlib/min_str.nim

@@ -175,6 +175,33 @@ if major.kind != minInt or minor.kind != minInt or patch.kind != minInt:

raiseInvalid("major, minor, and patch values are not integers") i.push(newVal("$#.$#.$#" % [$major, $minor, $patch])) + def.symbol("semver-inc-major") do (i: In): + i.push("from-semver".newSym) + var d = i.pop + let cv = i.dget(d, "major") + let v = cv.intVal + 1 + i.dset(d, "major", v.newVal) + i.push(d) + i.push("to-semver".newSym) + + def.symbol("semver-inc-minor") do (i: In): + i.push("from-semver".newSym) + var d = i.pop + let cv = i.dget(d, "minor") + let v = cv.intVal + 1 + i.dset(d, "minor", v.newVal) + i.push(d) + i.push("to-semver".newSym) + + def.symbol("semver-inc-patch") do (i: In): + i.push("from-semver".newSym) + var d = i.pop + let cv = i.dget(d, "patch") + let v = cv.intVal + 1 + i.dset(d, "patch", v.newVal) + i.push(d) + i.push("to-semver".newSym) + def.symbol("=~") do (i: In): i.push("regex".newSym)
M min.nimmin.nim

@@ -50,6 +50,11 @@ value,

scope, min_lang + + +#-d:ssl -p:. -d:noOpenSSLHacks --dynlibOverride:ssl- --dynlibOverride:crypto- -d:sslVersion:"(" --passL:-Lpath/to/openssl/lib +#--passL:-Bstatic --passL:-lssl --passL:-lcrypto --passL:-Bdynamic + const PRELUDE* = "prelude.min".slurp.strip var customPrelude = ""

@@ -201,22 +206,24 @@ proc minString*(buffer: string) =

minStream(newStringStream(buffer), "input") proc minFile*(filename: string) = + var fn = filename + if fn != "stdin" and not filename.endsWith(".min"): + fn &= ".min" var fileLines = newSeq[string](0) var contents = "" try: - fileLines = filename.readFile().splitLines() + fileLines = fn.readFile().splitLines() except: - fatal("Cannot read from file: " & filename) + fatal("Cannot read from file: " & fn) quit(3) - if fileLines[0].len >= 2 and fileLines[0][0..1] == "#!": contents = fileLines[1..fileLines.len-1].join("\n") else: contents = fileLines.join("\n") - minStream(newStringStream(contents), filename) + minStream(newStringStream(contents), fn) proc minFile*(file: File, filename="stdin") = - var stream = newFileStream(stdin) + var stream = newFileStream(filename) if stream == nil: fatal("Cannot read from file: " & filename) quit(3)
D min.nim.cfg

@@ -1,11 +0,0 @@

-# https://blog.filippo.io/easy-windows-and-linux-cross-compilers-for-macos/ - -# https://gist.github.com/Drakulix/9881160 -amd64.windows.gcc.path = "/usr/local/bin" -amd64.windows.gcc.exe = "x86_64-w64-mingw32-gcc" -amd64.windows.gcc.linkerexe = "x86_64-w64-mingw32-gcc" - -# http://crossgcc.rts-software.org/doku.php?id=compiling_for_linux -amd64.linux.gcc.path = "/usr/local/bin" -amd64.linux.gcc.exe = "x86_64-linux-musl-gcc" -amd64.linux.gcc.linkerexe = "x86_64-linux-musl-gcc"
M min.nimblemin.nimble

@@ -7,7 +7,7 @@ version = pkgVersion

author = pkgAuthor description = pkgDescription license = "MIT" -bin = @["min"] +bin = @[pkgName] installFiles = @["core/consts.nim"] # Dependencies
A min.nims

@@ -0,0 +1,38 @@

+# https", //blog.filippo.io/easy-windows-and-linux-cross-compilers-for-macos/ + +# https", //gist.github.com/Drakulix/9881160 +switch("amd64.windows.gcc.path", "/usr/local/bin") +switch("amd64.windows.gcc.exe", "x86_64-w64-mingw32-gcc") +switch("amd64.windows.gcc.linkerexe", "x86_64-w64-mingw32-gcc") + +# http", //crossgcc.rts-software.org/doku.php?id=compiling_for_linux +switch("amd64.linux.gcc.path", "/usr/local/bin") +switch("amd64.linux.gcc.exe", "x86_64-linux-musl-gcc") +switch("amd64.linux.gcc.linkerexe", "x86_64-linux-musl-gcc") + +switch("define", "ssl") +switch("opt", "size") +switch("threads", "on") + +switch("passL","-Bstatic") +when defined(windows): + # TODO", change once issue nim#15220 is resolved + switch("define", "noOpenSSLHacks") + switch("dynlibOverride", "ssl-") + switch("dynlibOverride", "crypto-") + switch("passL","-Lvendor/openssl/windows") + switch("passL","-lssl") + switch("passL","-lcrypto") + switch("passL","-lws2_32") + switch("define", "sslVersion:(") +else: + switch("dynlibOverride", "ssl") + switch("dynlibOverride", "crypto") + if defined(linux): + switch("passL","-Lvendor/openssl/linux") + switch("passL","-lssl") + switch("passL","-lcrypto") + elif defined(macos): + switch("passL","-Lvendor/openssl/macos") + switch("passL","-lssl") + switch("passL","-lcrypto")
A min.yml

@@ -0,0 +1,4 @@

+name: min +version: 0.22.0 +author: Fabio Cevasco +description: A tiny concatenative programming language and shell.
A run.min

@@ -0,0 +1,16 @@

+#!/usr/bin/env min + +; Validation +(args size 2 <) ("No task specified" error 1 exit) when + +args 1 get ":" split =taskspec +taskspec 0 get :task +"" :subtask +(taskspec size 1 >) (taskspec 1 get @subtask) when + +"./tasks/$#.min" (task) =% :task-file + +(task-file exists? not) ("Task '$1' does not exist" (task) =% error 2 exit) when + +; Execute task +task-file load
M site/contents/home.mdsite/contents/home.md

@@ -6,7 +6,7 @@ <div class="pure-g">

<section class="pitch pure-u-1 pure-u-md-2-3"> <em>min</em> is a functional, concatenative programming language with a minimalist syntax, a small but practical standard library, and an advanced - REPL. All packed in about 1MB<sup>*</sup>. + REPL. All packed in a single file<sup>*</sup>. </section> <section class="centered pure-u-1 pure-u-md-1-3"> <a class="pure-button pure-button-primary" href="/download/"><i class="ti-download"></i> download min v{{$version}}</a><br />

@@ -53,6 +53,6 @@ </section>

</div> <div class="pure-g"> <section class="pure-u-1"> - <small><sup>*</sup>: On Windows is actually more than 1MB, but on macOS and Linux it is considerably less. Let's just say 1MB is a good compromise.</small> + <small><sup>*</sup>: I used to boast that the min executable was around 1MB in size&#8230; well, that was before it statically linked OpenSSL!</small> </section> </div>
M site/contents/reference-str.mdsite/contents/reference-str.md

@@ -19,6 +19,10 @@

{#op||chr||{{i}}||{{s}}|| Returns the single character {{s}} obtained by interpreting {{i}} as an ASCII code.#} +{#op||from-semver||{{s}}||{{d}}|| +Given a basic [SemVer](https://semver.org)-compliant string (with no additional labels) {{s}}, +it pushes a dictionary {{d}} on the stack containing a **major**, **minor**, and **patch** key/value pairs.#} + {#op||indent||{{sl}} {{i}}||{{s}}|| Returns {{s}} containing {{sl}} indented with {{i}} spaces.#}

@@ -145,6 +149,15 @@ > > `"192.168.1.1, 127.0.0.1" "[0-9]+\.[0-9]+\.([0-9]+)\.([0-9]+)" search`

> > > > produces: `("192.168.1.1", "1", "1")`#} +{#op||semver-inc-major||{{s1}}||{{s2}}|| +Increments the major digit of the [SemVer](https://semver.org)-compliant string (with no additional labels) {{s1}}. #} + +{#op||semver-inc-minor||{{s1}}||{{s2}}|| +Increments the minor digit of the [SemVer](https://semver.org)-compliant string (with no additional labels) {{s1}}. #} + +{#op||semver-inc-patch||{{s1}}||{{s2}}|| +Increments the patch digit of the [SemVer](https://semver.org)-compliant string (with no additional labels) {{s1}}. #} + {#op||split||{{sl1}} {{sl2}}||{{q}}|| Splits {{sl1}} using separator {{sl2}} and returns the resulting strings within the quotation {{q}}. #}

@@ -156,6 +169,9 @@ Returns a substring {{s2}} obtained by retriving {{i2}} characters starting from index {{i1}} within {{s1}}.#}

{#op||titleize||{{sl}}||{{s}}|| Returns a copy of {{sl}} in which the first character of each word is capitalized.#} + +{#op||to-semver||{{d}}||{{s}}|| +Given a a dictionary {{d}} containing a **major**, **minor**, and **patch** key/value pairs , it pushes a basic [SemVer](https://semver.org)-compliant string (with no additional labels) {{s}} on the stack.#} {#op||uppercase||{{sl1}}||{{sl2}}|| Returns a copy of {{sl}} converted to uppercase.#}
A tasks/build.min

@@ -0,0 +1,25 @@

+#!/usr/bin/env min + +; Define subtasks +{} :subtasks +subtasks +( + ("nim" which "" ==) ("Nim is not available" error 1 exit) when + "nim c -d:release min" ! +) %native +( + ("hastyscribe" which "" ==) ("HastyScribe is not available" error 2 exit) when + "hastyscribe Min_DeveloperGuide.md --field/version=$#" (version) =% ! +) %guide +( + ("hastysite" which "" ==) ("HastySite is not available" error 3 exit) when + "cd site && hastysite build && cd .." ! +) %site +@subtasks + +(subtasks subtask dhas?) + ; Check if subtask exists, otherwise do a native build + (subtasks subtask dget ->) + ; Execute subtask + (subtasks /native ->) +if
M tests/http.mintests/http.min

@@ -4,7 +4,7 @@

"http" describe "postman-echo.com" :host - "http://$1" (host) => % :url + "https://$1" (host) => % :url ("$1/get" (url) => % get-content from-json /headers /user-agent "min http-module/$1" (version) => % ==) assert

@@ -52,7 +52,7 @@ {} (

("$1/delete" (url) => % %url) ("DELETE" %method) (request) - ) tap /body from-json /url "http://$1/delete" (host) => % == + ) tap /body from-json /url "https://$1/delete" (host) => % == ) assert report
M tests/lang.mintests/lang.min

@@ -45,14 +45,6 @@ ('mymath import 2 3 myplus 5 ==) assert

(2 3 mymath ^myplus 5 ==) assert - ; Extend an existing scope - ;( - ; ('mymath import - ; (-) :myminus - ; ) @mymath 5 2 mymath ^myminus 3 ==) assert - ; - ;(mymath inspect ("myminus" "myplus") ==) assert - ("3 4 +" eval 7 ==) assert ("2 2 +" "tests/testload.min" fwrite 'testload load 4 ==) assert
M tests/str.mintests/str.min

@@ -54,6 +54,16 @@

((1 3 "test") ", " join "1, 3, test" ==) assert ("PWD: $pwd" ("pwd" .) =% ("PWD: " .) => "" join ==) assert + + ("1.2.3" from-semver {1 :major 2 :minor 3 :patch} ==) assert + + ({2 :major 25 :minor 300 :patch} to-semver "2.25.300" ==) assert + + ("2.3.6" semver-inc-major "3.3.6" ==) assert + + ("2.3.6" semver-inc-minor "2.4.6" ==) assert + + ("2.3.6" semver-inc-patch "2.3.7" ==) assert report clear-stack