parent
d4b92d96ad
commit
33bee1efaf
@ -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. |
||||
|
@ -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 |
||||
}") |
||||
``` |
@ -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