aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md111
-rw-r--r--examples/if.lyn15
-rw-r--r--examples/sum.lyn18
3 files changed, 144 insertions, 0 deletions
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..757d157
--- /dev/null
+++ b/README.md
@@ -0,0 +1,111 @@
+# Lyn
+
+Old swedish for lönn. Pardon my ramblings, this is an initial document to
+collect my thoughts about what I might want from this project.
+
+## Concept
+
+Tcl is cool, but no quite enough like Lisp, right? This is my toy embeddable
+scripting language, takes heavy cues from Tcl but goes more in the Lisp
+direction by not requring `$` in front of everything and having a type system
+(though more inspired by ML with implicit type inference. Though the type
+inference thing might be implemented a bit later due to it possibly being a bit
+too heavy for a simple scripting language, but we'll see.
+
+This does mean that the language is **not** suited quite as well for user
+interfacing stuff as Tcl (shells, prompts, etc) but might work decently well as
+an alternative to Lua (games, extensible editors, etc). I don't think people who
+enjoy Lisp will like this language as I'm going for a lot more imperative
+features, like in Tcl.
+
+In an ideal world, I think we would have three languages:
+1. A compiled language for doing the heavy lifting of a program
+2. A light scripting language for exposing functionality within a program
+3. A (light?) shell language for user interfacing
+
+Tcl tries to do 2 and 3, and I personally think it achieves 3 very well. It's
+all about strings, which makes it easy and fast to use as a user interface, but
+this means that as a scripting language there's quite a bit of extra linenoise
+with `$` and some amount of mental overhead of keeping track of what a given string
+really tries to represent (is it an ad-hoc type? A class? Is it just a number?)
+This makes Tcl more difficult to deal with when the scripts grow in size beyond
+some (fairly small?) limit. You could of course argue that Tcl wasn't meant to
+be used to write these huge programs in and it's the programmers fault, but
+it will happen and I think a scripting language should still try to make that
+case as painless as possible.
+
+Speed probably shouldn't be the be-all end-all factor when designing a scripting
+language, but Tcl was for a very long time considered a *slow* language, which
+didn't earn it any favors. Even Python has an on-going performance improvement
+project, so I think speed should at least be considered when designing the language.
+
+## Syntax
+
+As in Tcl, everything is just a bunch of commands.
+
+```
+cmd [arg1 [arg2 [arg3 [...]]]]
+```
+
+Sort of similarly to Tcl, curly brackets, `{}`, are used for grouping together
+commands but not executing them right away. Parentheses, `()`, group together
+commands and evaluate them immediately, producing a value. But here we already
+run into some differences between lyn and Tcl:
+
++ Values can be of different types, `int`, `double`, `string`, etc.
++ Procedures can **only** take values. Command groupings can only be passed to
+ special `syntax` 'macros'.
+
+Here's an example (still up for change but let's go with this for now):
+
+```
+syntax for {init cond post body} {
+ eval init
+ while (eval cond) {
+ eval body
+ eval post
+ }
+}
+
+
+def sum {n} {
+ require n int
+ let s 0
+ for {let i 0} {< i n} {set i (+ i 1)} {
+ set s (+ s i)
+ }
+ return s
+}
+```
+
+They look kind of similar, but note that `for` is a `syntax` 'macro'.
+Effectively, macros can only take command groupings and create a new grouping
+that then later gets executed. Note that the groupings passed to `for` contain `()`,
+which are executed multiple times.
+
+(`syntax` 'macros' can also be defined in C, and presumably a lot of the looping
+constructs will be defined that way for a start)
+
+The `let` command defines a new variable, `set` mutates it.
+
+## Some implementation ideas
+
+I'm currently considering letting the C api define variadic functions, but
+disallowing them from the scripting language (to start with, at least).
+The thing is that the C api can fairly easily define a type checking function
+that runs over the arguments as a list once we know how many arguments there
+are, whereas that is a lot more difficult to do in the script itself. Maybe a
+kind of ugly imbalance?
+
+`syntax` is visually just a procedure, but encountering one in the code probably
+requires a bit of extra handling. I'll have to dig into the exact details, but a
+syntax macro takes the command groups as they are and then can evaluate them
+multiple times in the containing context.
+
+Eventually I might like to implement this thing on top of my `ejit` engine,
+still unsure about some details but presumably this would mean that the most
+common functions should be 'pattern matched' and some equivalent bytecode be
+emitted, like `for/while/if` and mathematical operations etc. with slow paths as
+backups, I suppose? The main issue here is how `syntax` should be handled, if
+each `proc` is equivalent to one bytecode function should each `syntax` be
+inlined? How complex would that be?
diff --git a/examples/if.lyn b/examples/if.lyn
new file mode 100644
index 0000000..294a490
--- /dev/null
+++ b/examples/if.lyn
@@ -0,0 +1,15 @@
+# `if` macro, think of it as a statement I guess?
+# else is used by the `if` command in C, presumably?
+if {< i 10} {
+ println "a"
+} {< i 20} {
+ println "b"
+} else {
+ println "c"
+}
+
+# `if` procedure, think of it as expr-if in other languages I guess
+# note that all arguments get evaluated here, so if you have a slow function in
+# one branch you should probably prefer `if` statements
+
+let x (do-if (< i 10) "a" (< i 20) "b" else "c")
diff --git a/examples/sum.lyn b/examples/sum.lyn
new file mode 100644
index 0000000..a4dcf61
--- /dev/null
+++ b/examples/sum.lyn
@@ -0,0 +1,18 @@
+syntax for {init cond post body} {
+ eval init
+ while (eval cond) {
+ eval body
+ eval post
+ }
+}
+
+def sum {n} {
+ require n int
+ let s 0
+ for {let i 0} {< i n} {set i (+ i 1)} {
+ set s (+ s i)
+ }
+ return s
+}
+
+println (sum 1000000)