GithubHelp home page GithubHelp logo

h3rald / min Goto Github PK

View Code? Open in Web Editor NEW
309.0 16.0 23.0 47.95 MB

A small but practical concatenative programming language and shell

Home Page: https://min-lang.org

License: MIT License

Nim 82.96% CSS 11.85% Dockerfile 0.25% Mustache 2.06% Vim Script 2.87%
nim concatenative functional

min's Introduction

A small but practical
concatenative programming language and shell



► For more info, go to https://min-lang.org.

min's People

Contributors

agentofuser avatar celtic-coder avatar drkameleon avatar h3rald avatar jo-he avatar kiedtl avatar pmunch avatar solitudesf avatar tristanmcd130 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

min's Issues

Getting the entire stack as a list

How would I go about doing that? I tried concating in a loop, but I can't concat things that are ints.

Sorry if this is in the docs, I may not have seen that bit.

no echo

Hello,

after I compiled min some days ago, I just tested the web example and left it.
Now, I find that the REPL stopped echoing the keys I type. So after pressing ENTER, I see the results, but I can't see what I type.

Debian Linux (Windows 10 Linux Subsystem), Nim 1.1.1

I can't tell if this is anything related to min. But I don't know anywhere else to ask.
Any ideas?

Kind greetings, z.

documentation

Hello,

today I took the pleasure to play with min. Thank you for this, it's cool!

As that's the only moment to really read documentation, I did note about spelling issues, strangenesses and whatever. I hope this will help.

Kind regards, and thank you!

zenon


Notes about https://h3rald.com/min/Min_DeveloperGuide.htm
Quotes in bold.

2.2
To exit min shell, press CTRL+C or type exit and press ENTER.

z: For exit to work, there needs to be an int on the stack. Suggested formulations:

  • .. or type 0 exit and press ENTER.
  • .. or use exit. [with link to the function]

3.
..
Then, another list containing two symbols (dup and ) is pushed on the stack. This constitutes a quoted program which, when executed duplicates (dup) the first element on the stack and then multiplies () the two elements together.

z: It can be confusing whether the parens are mentioned or used. I mean, you talk about (dup *) [here i mention the parentheses :-)], and then you use several parentheses. Suggestion:

Then, another list containing two symbols, i.e. dup and *, is pushed on the stack. This constitutes a quoted program which, when executed duplicates the first element on the stack -this is done by dup- and then multiplies -with *- the two elements together.


Parentheses are grouped together one or more elements, so that they are treated as a single element and they are not evaluated immediately.

z: are grouped together -> are used to group together


Symbols can be used to perform operations on the whole stack.

z: Not clear. Does this introduce the concept of symbol?
Do you mean: Symbols, also called words, refer to functions that operate on ..
?

3.1 Data Types

z: the type boolean seems to exist, but is missing.

z: The link to the dict module is broken


3.2.1
..
The synbol**
z: (spelling) synbol -> symbol


.. while the symbol apply can be used to dequote a quotation by pushing its elements on a separate stack.

z: this needs some explanation. until now we only heard of one stack.


3.3 Operators
..
Besides symbols, min provides a set of predefined sigils for commonly-used symbols.

z: I suggest an addition, like:
Besides symbols, min provides a set of predefined sigils as abbreviation for commonly-used symbols.

z: In the sigil list, the links to dget, dset, dhas? are broken


*3.4 Definitions
Being a concatenative language, min does not really need named parameters or variables: simbols just pop..

z: (spell) simbols -> symbols


3.4.1 Lexical scoping and binding

z: broken link to wikipedia


4.2
z: my windows computer doesn't have a HOMEPROFILE environment variable. It has USERPROFILE instead.

I didn'tread the reference yet. Except http; it'll get an extra issue.

Fatal error when inputting special characters

If you run min shell and type a character like è or §, you get a fatal error:

$ ./min -i
[C:/Data/Dev/_other/min]$ #fatal.nim(39)            sysFatal
Error: unhandled exception: index 194 not in 0 .. 31 [IndexError]

Debug stack trace:

[C:/Data/Dev/_other/min]$ C:\Data\Dev\_other\min\min.nim(363) min
C:\Data\Dev\_other\min\min.nim(266) minRepl
C:\Data\Dev\_other\min\min.nim(261) minRepl
C:\Data\Dev\_other\min\packages\nimline\nimline.nim(652) readLine
C:\nim\lib\system\fatal.nim(39) sysFatal
Error: unhandled exception: index 167 not in 0 .. 31 [IndexError]

`load` conflicts with `cd`

To reproduce:

root/file1.min

"File 1 loaded!" puts!

root/dir1/file2.min

("file2.min" file?) (args first dirname cd) unless

"../file1" load

Error scenario:

min root/dir1/file2.min
(!) root/dir1/file2.min(3,15) [load]: File 'root/dir1/../file1.min' does not exists.
    root/dir1/file2.min(3,15) in symbol: load

No problems when run without cd, from the exact dir like the code above suggests, or, without the "unless" line, from anywhere. It's the cd that messes it up. fread, fappend, fwrite, and even read (!!) don't conflict with cd under this scenario.

Error message typo: "does not exists" should be "does not exist".

Like always, big fan of this project. 🥇

Proposal: take

Currently shorten throws Quotation too short error when the quotation is shorter than the given argument. If all we want is to make sure the quotation is no longer than X, a forgiving version of shorten could be useful.

Minlang version:

; quot int -> quot
( :i =q
  (q size i >)
  (q i shorten)
  (q)
  if
) :take

Haskell's take behaves like this. Racket's take raises an exception. In both cases there's also drop counterpart.

All in all, just an idea, as using min version works perfectly fine.

Sockets library

Is it possible for you to implement a mini sockets library? Thanks.

Dynamic library attempt fails

Creating an example dyntest library, importing it and calling the dynplus function works.

Now, trying to create my own thing, that looks like this:

import mindyn

proc dyntools*(i: In) {.dynlib, exportc.} =

  let def = i.define()

  def.symbol("get-pos") do (i: In):
    var res = newSeq[MinValue](0)
    res.add @["line".newVal, i.currSym.line.newVal].newVal(i.scope)
    res.add @["column".newVal, i.currSym.column.newVal].newVal(i.scope)
    i.push res.newVal(i.scope)

  def.finalize("dyntools")

Fails upon calling get-pos with SIGSEGV: Illegal storage access. (Attempt to read from nil?)

This exact function works when defined in lib/min_lang.nim. Probably using something that's not implemented in mindyn? Or it can be my nonexistent Nim skills. Please point me in the right direction! :) Thank you

What's a good way to re-seed `random`?

To replicate, run min -i:

5 random
{1} -> 2
5 random
{2} -> 4
5 random
{3} -> 3
5 random
{4} -> 1

Close interpreter, restart, repeat, observe same sequence.

How to re-seed the random? I'm trying to shuffle a list of tests so that they run independently of each other, just in case some tests might affect others.

Thank you 🥇

Passing args to a script

Min tries to parse all args as filenames.

For a file like:

#!/usr/bin/env min

args puts

We get following results:

$ min demo.min
("demo.min")
$ min demo.min hello
(x) Cannot read from file: hello

We can pass stuff to our scripts using opts, and currently there's no overlap with min's options - either it terminates before running the script, like --help, or ignores the option and passes it to the script, like min -i demo.min. I imagine when there are more switches in the future the overlap will be awkward. Script options and interpreter options should be separate, based on positioning. Scripts should be able to have their own --help.

Let bind and quote-bind put value to top of stack

What are your thoughts on letting bind (@) and quote-bind (#) put their values on top of the stack?

For example, I have this code:

{} :scores ;empty dict for scores to populate
0 :counter
"abcdefghijklmnopqrstuvwxyz" "" split ;add alphabet to stack
(scores swap counter succ @counter counter swap dset) map ;set each letter to their score

and I thought it might look and feel better as:
(scores swap counter succ @counter swap dset) map

Another simpler example is:

1 :x
2 :y
y x + @y x swap
print ;should be 3

Find with multiple predicates & quote-define

Trying to use find like this:

(1 'hello 3) ('hello ==) find

Fails with [==]: Two non-symbol values of similar type are required on the stack. (Which is probably a usecase in it's own - to have a scheme-like hierarchy of eq? eqv? equal? with more-permissive and less-permissive variants).

Trying to safeguard this with quotation?, I cannot figure out a way to apply multiple predicates, because quotation? just executes and puts it's result on the stack, and we have nothing left to check against. Trying to quote-define the argument for reuse like this:

(1 'hello 3) (#item item quotation?) find

Results in [bind]: Attempting to bind undefined symbol: item. In general I couldn't get quote-define to work even in the form it's seen in tutorial:

(1 2 3 4 5) #my-list

Using the github version of Min.

Thank you for your time <3

Min support

Is it possible to support the project? Some kind of donates via Bountysource or something like this...

Some Benchmarks

I'm curious as to the performance of min. Would be nice to see a few benchmarks, maybe for some of these.

Silent ignore of odd entry in dict

{1 :uno 2 :due 3}

gives

{1} -> {
2 :due
1 :uno
}

without any error message, i.e. the leftover 3 is just ignored. I think this is not a good idea. It is not exactly a bug, but I suggest to add the feature of giving an error message here.

'withScope' does not return old scope on exception

While playing in REPL, I typed something like this

[path]$ ("a string" puts!") ->
(!) <repl>(1,14) [puts!"]: Undefined symbol 'puts!"'
    <repl>(1,14) in symbol: puts!"
    <native> in symbol: dequote
    <repl>(1,18) in symbol: ->

and after that Tab-completion stopped working. So I got my nose into the source and found out that the template withScope in core/interpreter.nim does not handle exceptions in body passed to it.
I suggest wrapping body and scope restoring lines in try...finally.

Shebang support

#!/usr/bin/env min

"hello" puts

Min feels like it's made for being an awesome scripting language. Would be awesome to have a special case for a shebang so that we can make script files executable.

Support for Nim dynlib loading

What would be really nice is if we could write modules for min in Nim and compile them as dynlibs (.so/.dll) and have min load them on runtime. If you would like I can have a look at implementing this.

dset and interpolate both use %

In the docs, % is the symbol for both interpolate and dset. In the source:

lib/min_str.nim

def.symbol("%") do (i: In):
    i.push("interpolate".newSym)

lib/min_seq.nim

def.sigil("%") do (i: In):
    i.push("dset".newSym)

In practice interpolate is the one that gets called.

Docs: prompt

This lacks an opening quote:

([$1]$$ " (.) => %)

should be

("[$1]$$ " (.) => %)

Unlike other predefined symbols, this symbol is unsealed

Does not apply to .minrc, which is where we're likely to redefine prompt from

Better support for web scraping

Hey,
First off, I have been having a lot of fun with this language. It makes me think about what I write, and I haven't had that feeling in years.

One shortcoming I have noticed is the lack of web related tools. You do have a sockets library, however I didn't see an easy way to get the HTML of a website. I feel like it would be nice to have GET and POST built in to the library similar to the way Nim handles them. I honestly feel like the example provided was too much and should be abstracted away by a sigil built into min.

I am personally planning on hooking up nimquery by using a dynamic library. Basically, I want an easy way to get the full text of an HTML page.

Feature Request for REPL

The REPL currently assumes that a complete expression has been entered when you press ENTER, or input a line feed; and it gives an error otherwise. This prohibits me from pasting multi line expressions (as I have them in my files) into the REPL, e.g.

{
1 :uno
2 :due
3 :tres
4 :quattro
}

In the REPL of Julia, e.g., I can enter an expression line by line, it recognizes when the expression is done. Navigation in the REPL (cursor key UP) brings me back to the complete expression, so I can change it as a whole.

For min this would need the REPL to recognise quotations and dictionaries, and nested of the same.

This would be cool.

Documentation Findings

Some more comments on the documentation, to get it even better.

Kind greetings from Hamburg!


Types:
z: You may mention that ints (and floats too, I presume) are 64 bit long.

3.4.3
z: spell: pervent -> prevent


in reference-stack

get-stack
Returns a quotation containing the contents of the stack.
z: The stack behavior explains what "returns" means. However, for a person coming from Forth, and looking for the equivalent of .s , it may be helpful to explicitly state:
Puts a quotation containing the contents of the stack on the stack.

clear-stack
z: The stack comment EmptyStack => EmptyStack is wrong, it should be something like:
Anything => EmptyStack


reference-lang

apply
If a dictionary dict is passed, it returns a new dictionary obtained by evaluating each symbol of dict in a separate stack.
z: "each symbol" may mean keys as well as values, but here it seems to refer to values only.
Suggestion:
If a dictionary dict (with values and keys) is passed, it returns a new dictionary obtained by evaluating each value in the dict that is a symbol in a separate stack. (Values that aren't symbols stay as they are.)

1 :uno
2 :due
3 :tres
4 :quattro
{uno :due tres :quattro}
{1} -> {
uno :due
tres :quattro
}
apply
{1} -> {
1 :due
3 :quattro
}

side note that adding an apply solves our issues with the dict literal in the http example.
like this:

{handler :handler 5555 :port} apply
=server-parameters


bool
If a is a non-zero numeric value, it is converted to true, otherwise it is converted to false.
z: natural languages lack parentheses. This can be read as
If a (is a non-zero numeric value, it is converted to true,) otherwise it is converted to false.
The left hand side would apply to anything that is not a number.
Suggestion:
If a is a numeric value, zero is converted to false, otherwise it is converted to true.
If a is a quotation, the empty quotation is converted to false, otherwise it is converted to true.
If a is a string, the empty string and "false" are converted to false, otherwise it is converted to true.

Note: Any dictionary seems to get converted into true.

Note2: This might be nitpicking. Probably every of your readers understands what you intend :-)


dequote
Pushes the contents of quotation quot on the stack.
z: This seems to be something like a transaction.
Suggestion (if I understand it correctly):
Pushes the contents of quotation quot on the stack, as if the elements are put on the stack one by one; except that if any of them fails, the whole operation fails (and the quot stays on the stack).

Function requests: read & parse

Currently there is no way to parse a string into a quoted expression without interpreting it. eval parses and interprets a string, and load parses and interprets a file.

Scheme-like read would parse a file into a quoted expression without interpreting it. A parse function would parse a string into a quoted expression without interpreting it. int and float already do that for ints and floats, so this would behave similarly but for quotes.

Docs: extraneous "debug" declaration

debug

∅ ⇒ ∅

Toggles debug mode.

This conflicts with:

debug

a ⇒ a

Prints a and a new line to STDOUT, if logging level is set to debug or lower.

Couldn't find the first one in sources. Debug mode is in practice toggled with 'debug loglevel.

Error: 'typedesc' metatype is not valid here; typed '=' instead of ':'?

I'm trying to compile min with NIM 020

Nim Compiler Version 0.20.0 [Linux: i386]
Compiled at 2019-06-06
Copyright (c) 2006-2019 by Andreas Rumpf

git hash: e7471cebae2a404f3e4239f199f5a0c422484aac
active boot switches: -d:release

and I'm getting this error

min/packages/nim-miniz/src/nim_miniz.nim(244, 21) Error: 'typedesc' metatype is not valid here; typed '=' instead of ':'?

I'm new to NIM and "min" and can't find what is wrong here. As the "min" code has not been changed for some time, it might be a regression with the new NIM compiler version.

Docs: system

Current version of the docs:

system

'sym ⇒ ∅

Executes the external command 'sym in the current directory.

This differs from actual behavior where system pushes return code on stack.

"ls" system
something.min
{1} -> 0
"ls /wrong" system
ls: cannot access '/wrong': No such file or directory
{2} -> 2

REPL behaviour, question, maybe a feature request

The REPL writes the TOS (when length of stack > 0), prefixed with "[n] ->" or "{n} ->", with n the length (i.e. the number of TOS). The choice of [] or {} is confusing.

Looks like {} is for quotes, [] for anything else including dictionaries (that have the {} in their syntax).
Modules seem to use {} too.
Is there anything else behind?

If not, suggestion:
(n) for quotes
{n} for dictionaries
[], or even no parens otherwise.

Plus: I'd like to be able to switch this off. Having ROOT on the stack is not the only situation where I don't want the TOS to be printed :-)

How to slice a string? And way how not to do that.

I can't find any way how to slice string. There isn't any function in the str module for this purpose.

My idea was at first to split a string a char by char into strings in a quote and then get or slice it by functions from seq module however when I try to do so system gets stuck as if it gets into endless loop. The problem is propably that I wanted to split string by empty string:

"abcdefgh" "" split

How can I slice string by another way? (by which I don't have to insert delimiters between every char)

Thanks

Preferred method of concatenating strings?

What is the preferred method of concatenating two strings? Should we format them using interpolate? Is it reasonable to ask for concat-str? Maybe something I overlooked? Thank you :)

http example, a bit refactored

Hi Fabio,

as I always fool around with code while attempting to understand it, the example changed a bit, to match my own taste. I paste it here so you can decide whether to use it for the docu.

; Define the request handler
(
  ; Assume there is a request on the stack, take it off and give it the name req
  :req
  ; Let's see what we got (print req to standard out)
  "THE REQUEST:" puts! req puts!
  ; The request is a map, we retrieve the value for the key url, and give it the name url
  req /url :url
  "THE URL is '$1'." url quote % puts!
  ; Constuct response body
  (
    (("/datetime" url ==) (timestamp datetime))
    (("/timestamp" url ==) (timestamp string))
    (("/shutdown" url ==) ("Stopping server..." puts! stop-server))
    (("/" url ==) (
      ; this is a bit short, but works with Chrome, IE, Edge, Safari
      "<a href='/datetime'>datetime</a>, <a href='/timestamp'>timestamp</a>, <a href='/shutdown'>stop</a>"
    ))
    ((true) ("Invalid Request: $1" url quote %))
  ) case
  :body
  ; Prepare the response
  {} body %body
  dup puts!
)
; The request handler is ready, give it the name handler
=handler

; Create the parameter dictionary for the server
{}
handler %handler
5555 %port

; Start server
"Server started on port 5555." puts!
"Press Ctrl+C to stop." puts!
start-server

The main changes are a case structure instead of when, and

"Invalid Request: $1" (url) => %

into

"Invalid Request: $1" url quote %

as I deem this to be easyer to understand.

Then a version without variable naming

; Define the request handler
(
  ; Assume there is a request on the stack.
  ; Let's see what we got (print req to standard out)
  "THE REQUEST:" puts! dup puts!
  ; The request is a map, we retrieve the value for the key url
  /url
  "THE URL is '$1'." dup quote % puts!
  ; Constuct response body
  (
    ((dup "/datetime" ==) (timestamp datetime))
    ((dup "/timestamp" ==) (timestamp string))
    ((dup "/shutdown" ==) ("Stopping server..." puts! stop-server))
    ((dup "/" ==) (
      ; this is a bit short, but works with Chrome, IE, Edge, Safari
      "<a href='/datetime'>datetime</a>, <a href='/timestamp'>timestamp</a>, <a href='/shutdown'>stop</a>"
    ))
    ((true) ("Invalid Request: $1" swap quote %))
  ) case
  ; Prepare the response
  {} swap %body
  dup puts!
)
; The request handler is ready, on top of stack

; Create the parameter dictionary for the server
{}
swap %handler
5555 %port

; Start server
"Server started on port 5555." puts!
"Press Ctrl+C to stop." puts!
start-server

Kind greetings,

z

code in description of http module doesn't work

In the documentation, 6.15 http Module, the server example doesn't work.

  1. Error: Symbol: tap - Incorrect values found on the stack
    I removed tap.

  2. Error: Handler is not a quotation.
    Remark: It is confusing that the word "Handler" is uppercase.
    I inserted the handler quotation directly into directory. Now it starts. Yeah!

  3. When accessing http://127.0.0.1:5555/nope
    Error: Response body is not a string.
    I tried adding
    body string @Body
    before
    {body :body}
    But it did't help.
    I changed the line
    {body :body}
    to {"hm" :body}
    Making the server functionality void.

  4. Error: Response headers are not in a dictionary.
    I changed that line to
    {"hm" :body {} :headers}

  5. Error: 'qVal' is not accessible using discriminant 'kind' of type 'MinValueObject'

Now I'm stuck :-)

compile issue

Hi Fabio,

I pulled min, and tried to

nim c -d:release min.nim

again. Got the following error:

Hint: min_math [Processing]
lib/min_math.nim(34, 5) Error: undeclared identifier: 'formatValue'

(As I don't know Nim yet, I don' know where to look.)

(Linux Debian)

Kind greetings.

z.

Native dictionary data type

min should provide a native dictionary data type. This will likely improve performance and also make the language richer and easier to use.

Empty quotations are not allowed

I'm using min 0.15.1, at Linux Mint 18.3.

If you try to push an empty quotation (i.e. () ), it doesn't get on the stack. Instead, nothing happens:

$ ()
{1} -> ()

Is this the expected behaviour? It seems wrong to me since quotations can also represent lists, and an empty list is still a valid one.

Get raw command line arguments

I know that args and opts exist, but I need a way to get the raw input passed to the program.

My use case is that I want to eval what comes after my program, which isn't possible since args gets rid of the quotation marks around strings.

Is it possible to include this in io or lang?

What is a scope, ROOT, etc.?

The documentation has:

ROOT
Returns an empty quotation holding a reference to the ROOT scope.
z: What? How can something empty hold a reference? I see a dictionary.

Question: In the examples I've seen until now there is always only one scope, and it is called ROOT. If there are more, it would be nice to explain their logic, and ways to access them.

related?:

with
Applies quotation quot1 within the scope of quot2.
z: I may completely out of grasp here. I assumed that the second argument has to be a dictionary. (First because I don't understand how a quote can have a scope, second because ROOT looks like a dictionary.)
So I tried

(5 5 plus) {'- :plus} with
get-stack
{4} -> (
5
5
(-)
)

I'm surprised that it isn't executed. Maybe I have a wrong interpretation of the word "apply"?

The example for with uses ROOT, and changes ROOT. This makes it a bit confusing, as in general the environment is only used, not changed; as seen in the following example (Again, assuming that I at least remotely understand what I'm doing here ..)

{'- :plus} :arithmetics--
(5 5 plus) arithmetics-- with
[3] -> (-)
get-stack
{4} -> (
5
5
(-)
)
arithmetics--
[5] -> {'- :plus}

all? always return true

I believe the all? function isn't working correctly. No matter what I provide the function, it always returns true. For example..

(true) (false ==) all?
-> true

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.