all repos — min @ f7bff82a771fdd3b2ef20f94203900a33731b88a

A small but practical concatenative programming language.

Finished documenting lang module.
h3rald h3rald@h3rald.com
Sun, 26 Mar 2017 17:35:19 +0200
commit

f7bff82a771fdd3b2ef20f94203900a33731b88a

parent

2b199bfdf8342cf9736a2bc2cc514840cb75ed71

M core/utils.nimcore/utils.nim

@@ -155,6 +155,10 @@ return res.newVal(i.scope)

# Validators +proc reqStackSize*(i: var MinInterpreter, n: int) = + if i.stack.len < n: + raiseEmptyStack() + proc reqBool*(i: var MinInterpreter, a: var MinValue) = a = i.pop if not a.isBool:
M lib/min_lang.nimlib/min_lang.nim

@@ -206,17 +206,6 @@ let sym = i.scope.getSymbol(s)

i.apply(sym) i.scope = origScope - .symbol("inspect") do (i: In): - var scope: MinValue - i.reqQuotation scope - var symbols = newSeq[MinValue](0) - if scope.scope.isNil: - i.push symbols.newVal(i.scope) - else: - for s in scope.scope.symbols.keys: - symbols.add s.newVal - i.push symbols.newVal(i.scope) - .symbol("raise") do (i: In): var err: MinValue i.reqDictionary err

@@ -346,7 +335,8 @@ var q: MinValue

i.reqQuotation q i.push q.qVal.len.newVal - .symbol("contains") do (i: In): + .symbol("in?") do (i: In): + i.reqStackSize(2) let v = i.pop var q: MinValue i.reqQuotation q

@@ -456,6 +446,7 @@ while check.isBool and check.boolVal == true:

i.unquote(d) i.unquote(b) check = i.pop + discard i.pop .symbol("filter") do (i: In): var filter, list: MinValue

@@ -681,13 +672,10 @@ .symbol(":") do (i: In):

i.push("define".newSym) .symbol("@") do (i: In): - i.push("define".newSym) + i.push("bind".newSym) .symbol("^") do (i: In): i.push("call".newSym) - - .symbol("%") do (i: In): - i.push("interpolate".newSym) .symbol("'") do (i: In): i.push("quote".newSym)
M lib/min_str.nimlib/min_str.nim

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

.symbol("=~") do (i: In): i.push("regex".newSym) + .symbol("%") do (i: In): + i.push("interpolate".newSym) + .finalize("str")
M min.vimmin.vim

@@ -11,7 +11,7 @@

setl iskeyword=@,36-39,+,-,/,*,.,:,~,!,48-57,60-65,94-95,192-255 setl iskeyword+=^ -syntax keyword minDefaultSymbol ! != $ & ' * + # - % ^ -> . .. / : < <= == => =~ > >= @ ROOT aes all? and any? append ask at atime b bind bool bool? bury1 bury2 bury3 c call call! capitalize case cd chmod choose column-print concat confirm cons cp cpu crypto ctime datetime ddel debug decode define delete dget dictionary? dig1 dig2 dig3 dip dir? dirname div dprint dprint! dset dup dupd encode env? error eval even? exists? exit fappend fatal file? filename filter first float float? foreach fperms fread from-json format-error fs fsize fstats ftype fwrite gets getenv hardlink hidden? id ift ifte import indent info inspect int int? interpolate interval io join k keys length linrec load load-symbol logic loglevel loglevel? lowercase ls ls-r map match md5 mkdir mod module module-symbols module-sigils mtime mv newline newstack not notice now num number? odd? os password pop popd pred prepend print print! prompt publish puts puts! putenv q quotation? quote quote-bind quote-define random raise regex remove-symbol repeat replace rest reverse rm rmdir run save-symbol scope scope? seal search sha1 sha224 sha256 sha384 sha512 sigils sip size sleep sort source split stack startup stored-symbols str string string? strip succ swap swapd swons symbols symlink symlink? sys system take tformat time timeinfo times timestamp titleize to-json try unquote unstack uppercase unzip values version warn which while with xor zip contains +syntax keyword minDefaultSymbol ! != $ & ' * + # - % ^ -> . .. / : < <= == => =~ > >= @ ROOT aes all? and any? append ask at atime b bind bool bool? bury1 bury2 bury3 c call call! capitalize case cd chmod choose column-print concat confirm cons cp cpu crypto ctime datetime ddel debug decode define delete dget dictionary? dig1 dig2 dig3 dip dir? dirname div dprint dprint! dset dup dupd encode env? error eval even? exists? exit fappend fatal file? filename filter first float float? foreach fperms fread from-json format-error fs fsize fstats ftype fwrite gets getenv hardlink hidden? id ift ifte import in? indent info int int? interpolate interval io join k keys length linrec load load-symbol logic loglevel loglevel? lowercase ls ls-r map match md5 mkdir mod module module-symbols module-sigils mtime mv newline newstack not notice now num number? odd? os password pop popd pred prepend print print! prompt publish puts puts! putenv q quotation? quote quote-bind quote-define random raise regex remove-symbol repeat replace rest reverse rm rmdir run save-symbol scope scope? seal search sha1 sha224 sha256 sha384 sha512 sigils sip size sleep sort source split stack startup stored-symbols str string string? strip succ swap swapd swons symbols symlink symlink? sys system take tformat time timeinfo times timestamp titleize to-json try unquote unstack uppercase unzip values version warn which while with xor zip syntax match minDefaultSigil ;\<[:@'~!$%&$=<>#^*#+/]; contained
M site/assets/styles/min-lang.csssite/assets/styles/min-lang.css

@@ -19,13 +19,19 @@ header .luxbar-menu i {

vertical-align: text-bottom; } -main { - margin-top: 40px; +.pure-g > section { + box-sizing: border-box; } +article { + margin-top: 40px; +} -.pure-g > section { - box-sizing: border-box; +:target:before { + content:""; + display:block; + height:60px; + margin:-60px 0 0; } article, section {

@@ -205,3 +211,36 @@ .tip p, .warning p, .note p, .sidebar p {

margin: 0 auto; line-height: 1.7em; } + +.sigil { + color: #009926; +} +.sigil:before { + color: #009926; + background-color: #d8f5cd; + padding: 0 3px 0; + display: inline-block; + width: auto; + margin: 1px; + -webkit-border-radius: 2px; + -moz-border-radius: 2px; + border-radius: 2px; + -moz-background-clip: padding; + -webkit-background-clip: padding-box; + background-clip: padding-box; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.8); + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + padding: 1px 1px 1px 1px; + line-height: 95%; + width: 70px; + text-align: center; + margin-right: 3px; + box-shadow: none; + font-size: 90%; + font-variant: small-caps; + font-weight: bold; + content: "sigil"; +}
M site/contents/_includes/_defs_.mdsite/contents/_includes/_defs_.md

@@ -1,6 +1,7 @@

{#op => -## $1 +<a id="op-$1"></> +## $1 > %operator% > [ $2 **&rArr;** $3](class:kwd)

@@ -8,12 +9,33 @@ >

> $4 #} +{#alias => +## $1 + +> %operator% +> [ $1 **&rArr;** $2](class:kwd) +> +> See [$2](#op-$2). + #} + +{#sig => +## $1 [](class:sigil) + +> %operator% +> [ $1S **&rArr;** S $2](class:kwd) +> +> See [$2](#op-$2). + #} + {# link-module => [`$1` Module](/reference-$1/) #} {{q => [(\*)](class:kwd)}} {{1 => [(1)](class:kwd)}} {{2 => [(2)](class:kwd)}} +{{3 => [(3)](class:kwd)}} +{{4 => [(4)](class:kwd)}} {{e => [(E)](class:kwd)}} +{{d => [(D)](class:kwd)}} {{i => [I](class:kwd)}} {{n => [N](class:kwd)}} {{any => [\*](class:kwd)}}
M site/contents/_includes/_reference-lang_.mdsite/contents/_includes/_reference-lang_.md

@@ -1,7 +1,52 @@

{@ _defs_.md || 0 @} -{#op||append||\* (\*)||(\*)|| -Returns a new quotation containing the contents of {{q}} with [\*](class:kwd) appended. #} +{#sig||'||quote#} + +{#alias||'||quote#} + +{#sig||:||define#} + +{#alias||:||define#} + +{#sig||~||delete#} + +{#sig||+||module#} + +{#sig||^||call#} + +{#alias||^||call#} + +{#sig||/||dget#} + +{#sig||@||bind#} + +{#alias||@||bind#} + +{#sig||%||dset#} + +{#sig||>||save-symbol#} + +{#sig||<||load-symbol#} + +{#alias||->||unquote#} + +{#alias||=>||apply#} + +{#sig||#||quote-define#} + +{#sig||=||quote-bind#} + +{#op||all?||(2) (1)||B|| +Applies predicate {{1}} to each element of {{2}} and returns {{t}} if all elements of {{2}} satisfy predicate {{1}}. #} + +{#op||any?||(2) (1)||B|| +Applies predicate {{1}} to each element of {{2}} and returns {{t}} if at least one element of {{2}} satisfies predicate {{1}}. #} + +{#op||append||\* (1)||(\*)|| +Returns a new quotation containing the contents of {{1}} with {{any}} appended. #} + +{#op||apply||(1)||(\*)|| +Returns a new quotation {{q}} obtained by evaluating each element of {{1}} in a separate stack.#} {#op||at||(\*) I||\*|| Returns the {{i}}^th element of {{q}}.#}

@@ -12,9 +57,31 @@

{#op||call||(\*) §||\*?|| Calls operator {{sl}} defined in scope {{q}}. #} +{#op||case||(1)||\*?|| +> {{1}} is a quotation containing _n_ different conditional branches. +> +> Each branch must be a quotation containing two quotations, and it is processed as follows: +> +> * if the first quotation evaluates to {{t}}, then the second quotation is executed. +> * if the first quotation evaluates to {{f}}, then the following branch is processed (if any). +> +> > %sidebar% +> > Example +> > +> > The following program prints "Smaller than 3": +> > +> > 2 ( +> > ((> 3) ("Greater than 3" put!)) +> > ((< 3) ("Smaller than 3" put!)) +> > ((true) ("Exactly 3" put!)) +> > ) case #} + {#op||concat||(2) (1)||(\*)|| Concatenates {{2}} with {{1}}. #} +{#op||ddel||(D) §||(D')|| +Returns a copy of {{d}} without the element with key {{sl}}. #} + {#op||debug||{{null}}||{{null}}|| Toggles debug mode. #}

@@ -27,15 +94,46 @@

{#op||delete||§||{{null}}|| Deletes the specified symbol {{sl}}.#} +{#op||dget||(D) §||\*|| +Returns the value of key {{sl}}. #} + +{#op||dhas?||(D) §||B|| +> Returns {{t}} if dictionary {{d}} contains the key {{sl}}. +> +> > %sidebar% +> > Example +> > +> > The following program returns {{t}}: +> > +> > ((a1 true) (a2 "aaa") (a3 false)) 'a2 dhas? + #} + +{#op||dset||(D) \* §||(D')|| +Sets the values of the {{sl}} of {{d}} to {{any}}, and return a modified copy of {{d}}. #} + {#op||eval||S||\*?|| Parses and interprets {{s}}. #} {#op||exit||{{null}}||{{null}}|| Exits the program or shell. #} +{#op||filter||(2) (1)||(\*)|| +> Returns a new quotation {{q}} containing all elements of {{2}} that satisfy predicate {{1}}. +> +> > %sidebar% +> > Example +> > +> > The following program returns [(2 6 8 12)](class:kwd): +> > +> > (1 37 34 2 6 8 12 21) +> > (dup 20 < swap even? and) filter #} + {#op||first||(\*)||\*|| Returns the first element of {{q}}. #} +{#op||foreach||(2) (1)||\*?|| +Applies the quotation {{1}} to each element of {{2}}.#} + {#op||format-error||(E)||S|| Formats the error {{e}} as a string.

@@ -51,30 +149,60 @@

{#op||from-json||S||\*|| Converts a JSON string into {{M -> min}} data.#} +{#op||ifte||(2) (1)||\*?|| +If {{2}} evaluates to {{t}} then evaluates {{1}}.#} + +{#op||ifte||(3) (2) (1)||\*?|| +If {{3}} evaluates to {{t}} then evaluates {{2}}, otherwise evaluates {{1}}.#} + {#op||import||§||{{null}}|| Imports the a previously-loaded module {{sl}}, defining all its symbols in the current scope. #} -{#op||inspect||(\*)||(S+)|| -Returns a list of symbols published on {{q}}'s scope. #} +{#op||in?||(\*) \*||B|| +Returns {{t}} if {{any}} is contained in {{q}}.#} + +{#op||keys||(D)||(S+)|| +Returns a quotation containing all the keys of dictionary {{d}}. #} + +{#op||linrec||(4) (3) (2) (1)||\*?|| +> Implements linear recursions as follows: +> +> 1. Evaluates {{4}}. +> * If {{4}} evaluates to {{t}}, then it evaluates {{3}}. +> * Otherwises it executes {{2}} and recurses using the same four quotations. +> 2. Finally, it executes {{1}}. +> +> > %sidebar% +> > Example +> > +> > The following programs returns [120](class:kwd), the factorial of 5: +> > +> > (dup 0 ==) 'succ (dup pred) '* linrec + #} {#op||load||S||\*?|| Parses and interprets the specified {{M}} file {{s}}, adding [.min](class:ext) if not specified. #} + +{#op||load-symbol||§||\*|| +Loads the contents of symbol {{sl}} from the [.min\_symbols](class:file) file. #} {#op||loglevel||§||{{null}}|| -Sets the current logging level to {{sl}}. {{sl}} must be one of the following strings or quoted symbols: +> Sets the current logging level to {{sl}}. {{sl}} must be one of the following strings or quoted symbols: +> +> * debug +> * info +> * notice +> * warn +> * error +> * fatal +> +> > %note% +> > Note +> > +> > The default logging level is _notice_.#} - * debug - * info - * notice - * warn - * error - * fatal - -> %note% -> Note -> -> The default logging level is _notice_. - #} +{#op||map||(2) (1)||(\*)|| +Returns a new quotation {{q}} obtained by applying {{1}} to each element of {{2}}.#} {#op||module||(\*) §||{{null}}|| Creates a new module {{sl}} based on quotation {{q}}. #}

@@ -93,31 +221,67 @@ Publishes symbol {{sl}} to the scope of [(\*)](class:kwd).

> > > %sidebar% > > Example -> > +> > > Publish symbol [my-local-symbol](class:kwd) to [ROOT](class:kwd) scope: > > `'my-local-symbol ROOT publish` #} {#op||quote||\*||(\*)|| Wraps [\*](class:kwd) in a quotation. #} +{#op||quote-bind||\* §||{{null}}|| +Quotes {{any}} and binds the quotation to the existing symbol {{sl}}. #} + +{#op||quote-define||\* §||{{null}}|| +Quotes {{any}} and assigns the quotation to the symbol {{sl}}, creating it if not already defined. #} + {#op||raise||(E)||{{null}}|| Raises the error specified via the dictionary {{e}}.#} +{#op||remove-symbol||§||{{null}}|| +Removes the symbol {{sl}} from the [.min\_symbols](class:file) file. #} + {#op||rest||(\*)||(\*)|| Returns a new quotation containing all elements of the input quotation except for the first. #} +{#op||reverse||(1)||(\*)|| +Returns a new quotation {{q}} containing all elements of {{1}} in reverse order. #} + +{#op||save-symbol||§||{{null}}|| +Saves the contents of symbol {{sl}} to the [.min\_symbols](class:file) file. #} + +{#op||seal||§||{{null}}|| +Seals symbol {{sl}}, so that it cannot be re-assigned. #} + {#op||sigils||{{null}}||(S+)|| Returns a list of all sigils defined in the [ROOT](class:kwd) scope.#} +{#op||size||(\*)||I|| +Returns the length of {{q}}.#} + +{#op||sort||(2) (1)||(\*)|| +> Sorts all elements of {{2}} according to predicate {{1}}. +> +> > %sidebar% +> > Example +> > +> > The following programs returns [(1 3 5 7 9 13 16)](class:kwd): +> > +> > (1 9 5 13 16 3 7) '> sort #} + {#op||source||§||(\*)|| Display the source code of symbol {{sl}} (if it has been implemented a {{M}} quotation). #} + +{#op||stored-symbols||{{null}}||(S+)|| +Returns a quotation containing all symbols stored in the [.min\_symbols](class:file) file. #} {#op||symbols||{{null}}||(S+)|| Returns a list of all symbols defined in the [ROOT](class:kwd) scope.#} +{#op||times||(\*) I||\*?|| +Applies the quotation {{q}} {{i}} times.#} + {#op||to-json||(\*)||S|| Converts a quotation into a JSON string {{s}}.#} - {#op||try||(\*)||\*?|| Evaluates quotation {{q}} as a try/catch/finally block.

@@ -128,19 +292,40 @@ > 1. A quotation containing the code to be evaluated (_try_ block).

> 1. _(optional)_ A quotation containing the code to execute in case of error (_catch_ block). > 1. _(optional)_ A quotation containing the code to execute after the code has been evaluated, whether an error occurred or not (_finally_ block). > ->> %sidebar% ->> Example ->> ->> The following program executed on an empty stack prints the message "Insufficient items on the stack" and pushes 0 on the stack: ->> ->> ( ->> (pop) ->> (format-error puts) ->> (0) ->> ) try #} +> > %sidebar% +> > Example +> > +> > The following program executed on an empty stack prints the message "Insufficient items on the stack" and pushes 0 on the stack: +> > +> > ( +> > (pop) +> > (format-error puts) +> > (0) +> > ) try #} {#op||unquote||(\*)||\*|| Pushes the contents of quotation {{q}} on the stack. #} + +{#op||unseal||§||{{null}}|| +Unseals symbol {{sl}}, so that it can be re-assigned. #} + +{#op||values||(D)||(\*+)|| +Returns a quotation containing all the values of dictionary {{d}}. #} + +{#op||version||{{null}}||S|| +Returns the current min version number. #} + +{#op||while||(2) (1)||\*?|| +> Executes {{1}} while {{2}} evaluates to {{t}}. +> +> > %sidebar% +> > Example +> > +> > The following program prints all natural numbers from 0 to 10: +> > +> > 0 :count +> > (count 10 <=) +> > (count puts succ @count) while #} {#op||with||(2) (1)||\*?|| Applies quotation {{2}} within the scope of {{1}}. #}
M site/contents/_includes/_reference_.mdsite/contents/_includes/_reference_.md

@@ -27,8 +27,10 @@ ## Notation

The following notation is used in the signature of all min operators: -\* +{{any}} : Any value. +[\*?](class:kwd) +: Zero or more values of any type. B : A boolean value. {{q}}

@@ -37,6 +39,12 @@ {{1}}

: The first quotation on the stack. {{2}} : The second quotation on the stack. +{{3}} +: The third quotation on the stack. +{{4}} +: The fourth quotation on the stack. +{{d}} +: A dictionary quotation. {{e}} : An error dictionary: <pre><code>(
M site/contents/home.mdsite/contents/home.md

@@ -2,6 +2,10 @@ -----

content-type: page title: Welcome to min ----- +<div class="note"> + <p>Under Construction</p> + <p>This site is under construction and the language documentation is incomplete. However, you can already <a href="/download/">download</a> a pre-release of min to try it out.</p> +</div> <div class="pure-g"> <section class="pitch pure-u-1 pure-u-md-2-3"> <em>min</em> is a functional, concatenative programming language
M tests/lang.mintests/lang.min

@@ -13,10 +13,10 @@

(2 'a define (3 a + (5 'a define a) -> +) -> a + 12 ==) assert - (symbols "a" contains false ==) assert + (symbols "a" in? false ==) assert 5 :five - (symbols "five" contains) assert + (symbols "five" in?) assert ( ((1 2 3 4 5 6)) :test-data

@@ -36,18 +36,15 @@ ) assert

~five - (symbols "five" contains false ==) assert + (symbols "five" in? false ==) assert ( (+) :myplus ) +mymath - (symbols "mymath" contains) assert + (symbols "mymath" in?) assert - - (() inspect () ==) assert - - ('mymath import symbols "myplus" contains) assert + ('mymath import symbols "myplus" in?) assert ('mymath import 2 3 myplus 5 ==) assert

@@ -89,8 +86,8 @@

((1 2 3 4) 2 at 3 ==) assert ((1 2 3) size 3 ==) assert - ((1 2 3 4) 5 contains false ==) assert - ((1 2 3 4) 2 contains) assert + ((1 2 3 4) 5 in? false ==) assert + ((1 2 3 4) 2 in?) assert ((1 2 3 4) (2 +) map (3 4 5 6) ==) assert

@@ -170,11 +167,11 @@ (((a 1)(b 2)(c 3)) keys (a b c) ==) assert

(((a 1)(b 2)(c 3)) values (1 2 3) ==) assert - (((1 2 3)) :sym1 >sym1 stored-symbols "sym1" contains) assert + (((1 2 3)) :sym1 >sym1 stored-symbols "sym1" in?) assert - (<sym1 symbols "sym1" contains) assert + (<sym1 symbols "sym1" in?) assert - ('sym1 remove-symbol stored-symbols "sym1" contains false ==) assert + ('sym1 remove-symbol stored-symbols "sym1" in? false ==) assert (0 :temp (1 2 3) (temp + @temp) foreach 6 temp ==) assert
M tests/sys.mintests/sys.min

@@ -25,7 +25,7 @@ ('dir2 ls 'dirname map ("dir2") ==) assert

('dir1 rmdir 'dir2 rmdir 'dir1 dir? 'dir2 dir? or false ==) assert - ("systest" mkdir . ls (. "systest") => "/" join contains) assert + ("systest" mkdir . ls (. "systest") => "/" join in?) assert ("systest" cd . "systest" match) assert .. cd

@@ -52,22 +52,22 @@ ("test.txt" "test2.txt" cp "test2.txt" file?) assert

("test.txt" "test1.txt" mv "test1.txt" file?) assert - ("test2.txt" rm "test1.txt" rm . ls (. "test1.txt") => "/" join contains :t1 . ls "test2" contains t1 and false ==) assert + ("test2.txt" rm "test1.txt" rm . ls (. "test1.txt") => "/" join in? :t1 . ls "test2" in? t1 and false ==) assert ("systest" cd "TEST" "test.txt" fwrite "TEST1" "test1.txt" fwrite "TEST2" "test2.txt" fwrite "TEST3" "test3.txt" fwrite - . ls "test.zip" zip . ls (. "test.zip") => "/" join contains) assert + . ls "test.zip" zip . ls (. "test.zip") => "/" join in?) assert - ("test.zip" "extracted" unzip "extracted" ls "extracted/test1.txt" contains) assert + ("test.zip" "extracted" unzip "extracted" ls "extracted/test1.txt" in?) assert "extracted" ls 'rm foreach . ls 'rm foreach .. cd - ("systest" rmdir . ls (. "systest") => "/" join contains false ==) assert + ("systest" rmdir . ls (. "systest") => "/" join in? false ==) assert