Added proposed spec for the language
All checks were successful
ci/woodpecker/push/workflow Pipeline was successful
All checks were successful
ci/woodpecker/push/workflow Pipeline was successful
This commit is contained in:
109
docs/doc.md
Normal file
109
docs/doc.md
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
## Mash
|
||||||
|
|
||||||
|
### Base design:
|
||||||
|
|
||||||
|
#### Paradigm:
|
||||||
|
|
||||||
|
Dynamically typed, functional-first.
|
||||||
|
|
||||||
|
#### Syntax:
|
||||||
|
|
||||||
|
A clean subset of Lisp. It's the simplest to parse and will get us to a working state fastest.
|
||||||
|
|
||||||
|
- Atoms: 123, 4.56, "hello", my-var, true
|
||||||
|
- Lists: (func arg1 arg2)
|
||||||
|
- Almost everything else is syntax sugar that can be added as macros in the standard library. That is also probably easier to implement, and more modular.
|
||||||
|
|
||||||
|
#### Data Types:
|
||||||
|
|
||||||
|
Integer, Float, String, Boolean, List, Symbol, Function. That's it.
|
||||||
|
|
||||||
|
#### Memory:
|
||||||
|
|
||||||
|
Garbage Collected. Let's forget custom allocators for now, and just use Boehm or
|
||||||
|
something.
|
||||||
|
|
||||||
|
#### Standard Library:
|
||||||
|
|
||||||
|
Basic math ops (+, -, *, /), comparison (=, <, >), cons, car, cdr, list, some form of arrays, and I/O functions. Keep it small, at least for the beginning.
|
||||||
|
|
||||||
|
## Basic operations
|
||||||
|
|
||||||
|
### Defining functions and variables
|
||||||
|
|
||||||
|
Let's just copy Scheme here, it has a very simple special form:
|
||||||
|
|
||||||
|
```
|
||||||
|
(define x 5)
|
||||||
|
(define (addTwo x y) (+ x y))
|
||||||
|
```
|
||||||
|
|
||||||
|
This simple syntax is fairly readable and math-like.
|
||||||
|
|
||||||
|
It's a dynamic language, no type inference or funny business,
|
||||||
|
no PhDs required.
|
||||||
|
|
||||||
|
Every form ("expression") evaluates to something. Variable definitions
|
||||||
|
evaluate to the value assigned to the variable, or nil if it's
|
||||||
|
an empty definition.
|
||||||
|
|
||||||
|
Function definitions evaluate to the value of their function.
|
||||||
|
|
||||||
|
Nil is the empty list, (). Common Lisp treats
|
||||||
|
it as the canonical falsy value, scheme has #t and #f, and treats
|
||||||
|
nil as truthy. We can go with either choice but I lean towards
|
||||||
|
Common Lisp here.
|
||||||
|
|
||||||
|
### Macros
|
||||||
|
|
||||||
|
We use CL-style macros, a macro is a function that receives its parameters
|
||||||
|
unevaluated and runs completely at compile time, producing lisp code that
|
||||||
|
will be compiled. Of course, it will produce a list.
|
||||||
|
|
||||||
|
I.e. using a macro `(foo (1 2 3) arg2)` is equivalent to doing
|
||||||
|
`(eval (bar '(1 2 3) 'arg2))` assuming the function bar does the
|
||||||
|
same transformations that foo would have done, except that the
|
||||||
|
macro foo is evaluated at compile time.
|
||||||
|
|
||||||
|
## Special syntax
|
||||||
|
|
||||||
|
Let's NOT add too much syntax to the core.
|
||||||
|
|
||||||
|
The idea is, if we make a small core that has access to lisp macros,
|
||||||
|
we can effectively add *any* syntax sugar we want by simply defining
|
||||||
|
it as part of the standard library.
|
||||||
|
|
||||||
|
That's usually what Common Lisp does actually, most language constructs
|
||||||
|
are actually functions or macros defined in the standard library.
|
||||||
|
|
||||||
|
The greatest power of a Lisp is its ability to extend syntax.
|
||||||
|
Adding too much syntax too early defeats the purpose.
|
||||||
|
Let's keep it small.
|
||||||
|
|
||||||
|
|
||||||
|
#### Dollar sign
|
||||||
|
|
||||||
|
```
|
||||||
|
(define x $(1/3 + 2^60))
|
||||||
|
(define y (map (lambda (n) $(n * n)) (range 0 10)))
|
||||||
|
```
|
||||||
|
|
||||||
|
This can be implemented later as a reader macro,
|
||||||
|
e.g. $(1/3 + 2^60) expands to (math-syntax (1/3 + 2^60))
|
||||||
|
math-syntax is a macro that expands this further to
|
||||||
|
(+ (/ 1 3) (^ 2 60)).
|
||||||
|
|
||||||
|
So at the start, we don't need much syntax at all.
|
||||||
|
|
||||||
|
#### SQL sub-language
|
||||||
|
|
||||||
|
This can trivially be done as a library of functions,
|
||||||
|
and macros can add whatever syntax sugar is desired.
|
||||||
|
|
||||||
|
## Evaluation strategy
|
||||||
|
|
||||||
|
In order for macros to be possible, the compiler must be able to execute
|
||||||
|
code during compilation time. This is fine, we can simply keep a running
|
||||||
|
"image" of all lisp forms compiled so far, and run code there.
|
||||||
|
|
||||||
|
We need a byte code VM for this. Lua bytecode is perfectly acceptable.
|
Reference in New Issue
Block a user