From 33bee1efaf1142f20c6934f10bbc06ecd3aeee95 Mon Sep 17 00:00:00 2001 From: Brian Picciano Date: Mon, 6 Oct 2014 12:34:04 -0400 Subject: [PATCH] manifesto and half-assed interoperability --- README.md | 151 +++++--------------------------------------------- go-interop.md | 53 ++++++++++++++++++ syntax.md | 147 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 215 insertions(+), 136 deletions(-) create mode 100644 go-interop.md create mode 100644 syntax.md diff --git a/README.md b/README.md index d57c5e0..5ade803 100644 --- a/README.md +++ b/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. diff --git a/go-interop.md b/go-interop.md new file mode 100644 index 0000000..558a8fe --- /dev/null +++ b/go-interop.md @@ -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 + }") +``` diff --git a/syntax.md b/syntax.md new file mode 100644 index 0000000..5cf4783 --- /dev/null +++ b/syntax.md @@ -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)) +```