manifesto and half-assed interoperability
This commit is contained in:
parent
d4b92d96ad
commit
33bee1efaf
151
README.md
151
README.md
@ -1,147 +1,26 @@
|
||||
# Ginger
|
||||
|
||||
A lisp-like language built on the go programming language. The ideas are still a
|
||||
work-in-progress, and this repo is where I'm jotting down my notes.
|
||||
work-in-progress, and this repo is where I'm jotting down my notes:
|
||||
|
||||
# Goals
|
||||
# Language manifesto
|
||||
|
||||
I have some immediate goals I'm trying to achieve with this syntax:
|
||||
* Anything written in go should be writeable in ginger in as many lines or
|
||||
fewer.
|
||||
|
||||
* Everything is strings (except numbers, functions, and data structures). There
|
||||
is no symbol type, atom type, keyword type, etc... they're all just strings.
|
||||
* When deciding whether to be more go-like or more like an existing lisp
|
||||
language, err on being go-like.
|
||||
|
||||
* There is no `defmacro`. Macro creation and usage is simply an inherent feature
|
||||
of the language syntax.
|
||||
* The fewer built-in functions, the better. The standard library should be
|
||||
easily discoverable and always importable so helper functions can be made
|
||||
available.
|
||||
|
||||
# Walkthrough
|
||||
* When choosing between adding a syntax rule or a datatype and not adding a
|
||||
feature, err on not adding the feature.
|
||||
|
||||
This is a number which evalutates to 5:
|
||||
* It is not a goal to make ginger code be usable from go code.
|
||||
|
||||
```
|
||||
5
|
||||
```
|
||||
* Naming should use words instead of symbols, except when those symbols are
|
||||
existing go operators.
|
||||
|
||||
This is a string, it can contain anything:
|
||||
|
||||
```
|
||||
"! I'm the king of the world !"
|
||||
```
|
||||
|
||||
This is a list. It evaluates to a linked-list of four strings:
|
||||
|
||||
```
|
||||
("a" "b" "c" "d")
|
||||
```
|
||||
|
||||
This is a vector of those same elements. It's like a list, but has some slightly
|
||||
different properties. We'll mostly be using lists:
|
||||
|
||||
```
|
||||
["a" "b" "c" "d"]
|
||||
```
|
||||
|
||||
This is a string
|
||||
|
||||
```
|
||||
"+"
|
||||
```
|
||||
|
||||
`:` is the evaluator. A string beginning with `:` is evaluated to whatever it
|
||||
references. This evaluates to a function which adds its arguments:
|
||||
|
||||
```
|
||||
":+"
|
||||
```
|
||||
|
||||
This evaluates to list whose elements are a function and two numbers:
|
||||
|
||||
```
|
||||
(":+" 1 2)
|
||||
```
|
||||
|
||||
A list whose first element is a `:` calls the second element as a function with
|
||||
the rest of the elements as arguments. This evaluates to the number 5:
|
||||
|
||||
```
|
||||
(":" ":+" 1 2)
|
||||
```
|
||||
|
||||
A bare string (lacking in `"`) is automatically prefixed with a `:`, if it
|
||||
doesn't already have one. So `":+"`, `:+`, and `+`, are equivalent. `":"` and
|
||||
`:` are also equivalent. This is equivalent to the previous example:
|
||||
|
||||
```
|
||||
(: + 1 2)
|
||||
```
|
||||
|
||||
The `fn` function can be used to define a new function. Note the `.` instead of
|
||||
`:`. We'll cover that in a bit. This evaluates to an anonymous function which
|
||||
adds one to its argument and returns it:
|
||||
|
||||
```
|
||||
(. fn [x]
|
||||
(: + x 1))
|
||||
```
|
||||
|
||||
The `def` function can be used to bind some value to a new variable. This
|
||||
defines a variable `foo` which evaluates to the string `"bar"`:
|
||||
|
||||
```
|
||||
(. def foo "bar")
|
||||
```
|
||||
|
||||
This defines a variable `incr` which evaluates to a function which adds one to
|
||||
its argument:
|
||||
|
||||
```
|
||||
(. def incr
|
||||
(. fn [x]
|
||||
(: + x 1)))
|
||||
```
|
||||
|
||||
This uses `defn` as a shortcut for the above:
|
||||
```
|
||||
(. defn incr [x]
|
||||
(: + x 1))
|
||||
```
|
||||
|
||||
There are also maps. A map's keys can be any value(?). A map's values can be any
|
||||
value. This evaluates to a map with 2 key/val pairs:
|
||||
|
||||
```
|
||||
{ "foo" foo
|
||||
"bar" (: incr 4) }
|
||||
```
|
||||
|
||||
`.` is the half-evaluator. It only works on lists, and runs the function given
|
||||
in the first argument with the unevaluated arguments (even if they have `:`).
|
||||
You can generate new code to run on the fly (macros) using the normal `fn`. This
|
||||
evaluates to a `let`-like function, except it forces you to use the capitalized
|
||||
variable names in the body (utterly useless):
|
||||
|
||||
```
|
||||
#
|
||||
# eval evaluates a given value (either a string or list). It has been
|
||||
# implicitely called on all examples so far.
|
||||
#
|
||||
# elem-map maps over every element in a list, embedded or otherwise
|
||||
#
|
||||
# capitalize looks for the first letter in a string and capitalizes it
|
||||
#
|
||||
(. defn caplet [mapping body...]
|
||||
(. eval
|
||||
(. let
|
||||
(: elem-map
|
||||
(. fn [x]
|
||||
(. if (: mapping (: slice x 1))
|
||||
(: capitalize x)
|
||||
x))
|
||||
mapping)
|
||||
body...)))
|
||||
|
||||
#Usage
|
||||
(. caplet [foo "this is foo"
|
||||
dog "this is dog"]
|
||||
(: println Foo)
|
||||
(: println Dog))
|
||||
```
|
||||
* Overloading function should be used as little as possible.
|
||||
|
53
go-interop.md
Normal file
53
go-interop.md
Normal file
@ -0,0 +1,53 @@
|
||||
# Go interop
|
||||
|
||||
Ginger translates down to go code, and many of its conventions and rules follow
|
||||
from go's conventions and rules. In most cases these decisions were made to help
|
||||
with interoperability with existing go code.
|
||||
|
||||
## Referencing go package variables/functions
|
||||
|
||||
See the package doc for more on this
|
||||
|
||||
## Types
|
||||
|
||||
Go types and ginger types share a lot of overlap:
|
||||
|
||||
* Ginger strings are of go's `string` type
|
||||
|
||||
* Ginger integers are of go's `int` type
|
||||
|
||||
* Ginger floats are of go's `float32` type
|
||||
|
||||
* Ginger characters are of go's `rune` type
|
||||
|
||||
* Ginger errors are of go's `error` type
|
||||
|
||||
## Casting
|
||||
|
||||
Each go type has a corresponding ginger casting function:
|
||||
|
||||
```
|
||||
(: int64 5)
|
||||
(: float64 5.5)
|
||||
(: rune 'a')
|
||||
```
|
||||
|
||||
## go-drop
|
||||
|
||||
the `go-drop` form can be used for furthur interoperability. The rationale
|
||||
behind `go-drop` is that there are simply too many cases to be able to create
|
||||
enough individual functions, or a few generic functions, that would cover all
|
||||
cases. Instead we use a single function, `go-drop`, which lets us drop down into
|
||||
go code and interact with it directly. There are a number of pre-made functions
|
||||
which implement commonly needed behaviors, such as `StringSlice` and
|
||||
`ByteSlice`, which cast from either go or ginger types into `[]string` and
|
||||
`[]byte`, respectively.
|
||||
|
||||
```
|
||||
(. go-drop
|
||||
"func StringSlice(v ginger.Elem) []string {
|
||||
ret := []string{}
|
||||
// do some stuff
|
||||
return ret
|
||||
}")
|
||||
```
|
147
syntax.md
Normal file
147
syntax.md
Normal file
@ -0,0 +1,147 @@
|
||||
# Syntax
|
||||
|
||||
This document describes the ginger syntax and data-structures, and how they are
|
||||
evaluated.
|
||||
|
||||
# Goals
|
||||
|
||||
I have some immediate goals I'm trying to achieve with this syntax:
|
||||
|
||||
* Everything is strings (except numbers, functions, and data structures). There
|
||||
is no symbol type, atom type, keyword type, etc... they're all just strings.
|
||||
|
||||
* There is no `defmacro`. Macro creation and usage is simply an inherent feature
|
||||
of the language syntax.
|
||||
|
||||
# Walkthrough
|
||||
|
||||
This is a number which evalutates to 5:
|
||||
|
||||
```
|
||||
5
|
||||
```
|
||||
|
||||
This is a string, it can contain anything:
|
||||
|
||||
```
|
||||
"! I'm the king of the world !"
|
||||
```
|
||||
|
||||
This is a list. It evaluates to a linked-list of four strings:
|
||||
|
||||
```
|
||||
("a" "b" "c" "d")
|
||||
```
|
||||
|
||||
This is a vector of those same elements. It's like a list, but has some slightly
|
||||
different properties. We'll mostly be using lists:
|
||||
|
||||
```
|
||||
["a" "b" "c" "d"]
|
||||
```
|
||||
|
||||
This is a string
|
||||
|
||||
```
|
||||
"+"
|
||||
```
|
||||
|
||||
`:` is the evaluator. A string beginning with `:` is evaluated to whatever it
|
||||
references. This evaluates to a function which adds its arguments:
|
||||
|
||||
```
|
||||
":+"
|
||||
```
|
||||
|
||||
This evaluates to list whose elements are a function and two numbers:
|
||||
|
||||
```
|
||||
(":+" 1 2)
|
||||
```
|
||||
|
||||
A list whose first element is a `:` calls the second element as a function with
|
||||
the rest of the elements as arguments. This evaluates to the number 5:
|
||||
|
||||
```
|
||||
(":" ":+" 1 2)
|
||||
```
|
||||
|
||||
A bare string (lacking in `"`) is automatically prefixed with a `:`, if it
|
||||
doesn't already have one. So `":+"`, `:+`, and `+`, are equivalent. `":"` and
|
||||
`:` are also equivalent. This is equivalent to the previous example:
|
||||
|
||||
```
|
||||
(: + 1 2)
|
||||
```
|
||||
|
||||
The `fn` function can be used to define a new function. Note the `.` instead of
|
||||
`:`. We'll cover that in a bit. This evaluates to an anonymous function which
|
||||
adds one to its argument and returns it:
|
||||
|
||||
```
|
||||
(. fn [x]
|
||||
(: + x 1))
|
||||
```
|
||||
|
||||
The `def` function can be used to bind some value to a new variable. This
|
||||
defines a variable `foo` which evaluates to the string `"bar"`:
|
||||
|
||||
```
|
||||
(. def foo "bar")
|
||||
```
|
||||
|
||||
This defines a variable `incr` which evaluates to a function which adds one to
|
||||
its argument:
|
||||
|
||||
```
|
||||
(. def incr
|
||||
(. fn [x]
|
||||
(: + x 1)))
|
||||
```
|
||||
|
||||
This uses `defn` as a shortcut for the above:
|
||||
```
|
||||
(. defn incr [x]
|
||||
(: + x 1))
|
||||
```
|
||||
|
||||
There are also maps. A map's keys can be any value(?). A map's values can be any
|
||||
value. This evaluates to a map with 2 key/val pairs:
|
||||
|
||||
```
|
||||
{ "foo" foo
|
||||
"bar" (: incr 4) }
|
||||
```
|
||||
|
||||
`.` is the half-evaluator. It only works on lists, and runs the function given
|
||||
in the first argument with the unevaluated arguments (even if they have `:`).
|
||||
You can generate new code to run on the fly (macros) using the normal `fn`. This
|
||||
evaluates to a `let`-like function, except it forces you to use the capitalized
|
||||
variable names in the body (utterly useless):
|
||||
|
||||
```
|
||||
#
|
||||
# eval evaluates a given value (either a string or list). It has been
|
||||
# implicitely called on all examples so far.
|
||||
#
|
||||
# elem-map maps over every element in a list, embedded or otherwise
|
||||
#
|
||||
# capitalize looks for the first letter in a string and capitalizes it
|
||||
#
|
||||
(. defn caplet [mapping body...]
|
||||
(. eval
|
||||
(. let
|
||||
(: elem-map
|
||||
(. fn [x]
|
||||
(. if (: mapping (: slice x 1))
|
||||
(: capitalize x)
|
||||
x))
|
||||
mapping)
|
||||
body...)))
|
||||
|
||||
#Usage
|
||||
(. caplet [foo "this is foo"
|
||||
dog "this is dog"]
|
||||
(: println Foo)
|
||||
(: println Dog))
|
||||
```
|
Loading…
Reference in New Issue
Block a user