Skip to content
/ fiction Public

A now abandoned Scheme-type Lisp in JavaScript.

License

Notifications You must be signed in to change notification settings

garyb/fiction

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Fiction

Yet another Lisp in JavaScript.

There are still quite a lot of things to be done. Also there are no proper tests at the moment, just the stuff in ./playground/, but that's not a real test setup.

It can be run in the browser by poking around with the files in ./playground, or the reader/expander/compiler pipeline can be run with node.js using:

node ./src/js/main.js <input> <output>

Where <input> is the path to a .fic file, and <output> is the path to a file to write the compiled JavaScript.


The language

Fiction is a Scheme-like Lisp that compiles down to JavaScript.

Although syntactically using s-expressions the language does not use the standard cons based data structure to represent expressions, instead JavaScript arrays are used. For most practical purposes this doesn't matter, aside from the fact it is not possible to create non-list expressions, such as (a . b). This is something I might address later though.

Basic syntax

All syntax items are either literals, or lists. Literals can be strings (delimited by double quotes), numbers (either as decimals or hexadecimal of the form 0xN), booleans (#t for true and #f for false), or symbols.

Symbols are used as identifiers in the language. They're variable names, function names, special form names, etc. They can also be constructed and used as runtime values by using the quote or quasiquote special form, for example, 'foo. Symbol values currently can contain any unicode character that is not whitespace, quotes, commas, semicolons, parenthesis, square brackets, or braces.

Lists are surrounded by parentheses, and are interpreted as expressions to be evaluated, unless appearing inside a quote or quasiquote special form. For example, the list (foo 10 20) would call foo with the arguments 10 and 20. foo could be a special form, a macro, or an identifier for a variable containing a function.

Special forms are the core operations provided by the language that cannot be expressed as normal functions (like var, if, and so on). Macros are operations defined by the programmer that cannot be expressed as normal functions (like and). Functions are... well, functions.

Everything in the language is an expression, so even things like var that are statements in JavaScript return a value. This also means there is no need for a return statement, because the last value in a function is taken instead.

One slight special case to enable better interop with JavaScript is identifiers starting with . are only available as object properties.

Special forms

Variable declarations

syntax: (var <id> <expr>)

Declares a new variable with the name <id> in the current scope and assigns it the value that <expr> evaluates to.

Assignments

syntax: (set! <id> <expr>)
syntax: (set! <obj-prop> <expr>)

Assigns the value that <expr> evaluates to to variable <id> or object property <obj-prop>. See below for details about the syntax for object properties.

Conditionals

syntax: (if <test> <then> <else>)

Evaluates <test>, if the result is true according to JavaScript (not using strict equality), <then> is evaluated, otherwise <else> is.

Quoting

syntax: (quote <datum>)
syntax: '<datum>

Produces <datum> without evaluating it.

Quasiquoting

syntax: (quasiquote <qqtemplate>)
syntax: ```

Evaluates <qqtemplate> to produce a datum-like value, evaluating any unquote or unquote-splicing expressions contained within.

syntax: (unquote <expr>)
syntax: ,<expr>

Evaluates the expression <expr> and inserts it in place of the unquote expression in the <qqtemplate>. Using unquote outside of a quasiquote will raise an error.

syntax: (unquote-splicing <list-expr>)
syntax: ,@<list-expr>

Evaluates the expression <list-expr> that returns a list, and inserts it inline in a place of the unquote-splicing expression in the <qqtemplate>. Using unquote-splicing outside of a list inside a quasiquote will raise an error. If list-expr does not return a list a runtime error might occur (it depends on how JavaScript interprets the value of <list-expr> when passed to Array.concat()).

Import

syntax: (import <name ...>)

Loads the contents of one or more .fic files, specified in the list of strings <name ...> and splices them in at the current position. The .fic extension should be omitted from the <name ...> items. Can be used almost anywhere in a script. There is no specific limit to the number of times the same file can be imported, although recursive imports will be ignored.

Macros

syntax: (define-syntax <syntax-id> <transformer>)
transformer syntax: (syntax-rules (<reserved-id ...>) <rule ...>)
rule syntax: ((<syntax-id> <pattern>) <template>)
pattern syntax: <id>
pattern syntax: <literal>
pattern syntax: (<pattern ...>)
pattern syntax: <pattern> ...
template syntax: <expr>
template syntax: <template> ...
template syntax: (... ...)

They're supposed to work as defined in R5RS, more or less. I've not tested them thoroughly enough to be sure yet, but they're definitely usable. I also need to take some time to write a decent usage description!

About

A now abandoned Scheme-type Lisp in JavaScript.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published