Verse
Creator: |
Overview
Domain specific languages are growing in popularity, especially implementations that can be natively parsed within a parser for more general languages. Verse is an attempt at a language designed specifically for that purpose. The semantics are extremely simple. Everything is a message to something else, and each message contains exactly one string argument. A method's purpose is usually to parse the argument into a message tree which is then evaluated. The code of the language has no particular syntax of its own, only a standard library (which follows a convention of some sort) and a built-in parser for that library.
Details
Verse is in the extreme early stages of development (less than 100 lines of code). This section lists the intended goals, but these may change over time.
Motivation
"Choose the right tool for the job," they always say. More often than not, the tool chosen for a job is only so because it is the closest fit, not because it is actually right. The purpose of creating Verse is to have a tool that is more malleable and can be made to fit most jobs almost perfectly, even when it doesn't fit upon first glance. The result is intended to make it possible to make clean, clear, concise domain-specific code that can run in the same virtual machine as code from an entirely different project. Indeed, it may even be a good idea sometimes to create multiple domain-specific languages for a single project and run them all in the same virtual machine.
Goals
- simple semantics
- potential for optimization
- low memory overhead
- easy to grok
- easy to apply to multiple situations
- minimal core library
- enough to perform most necessary computations and system calls
- enough to create specialized parsers
- extensive standard library
- dynamically loaded modules
Semantics
The semantics for Verse are very simple.
- Everything is an object.
- There are no classes.
- There is no inheritence.
- Member data is stored in slots.
- Everything is a message.
- If there is one, a called object will call the object in its "call" slot.
- If there is no "call" slot, most objects will return themselves.
- Some objects may have special call behavior in machine code.
- Every message has exactly one argument.
- The argument is always a string.
- A call with no argument implicitly has an empty string argument.
- The argument may be explicitly parsed by the invoked method.
- Messages have some default slots in local scope.
- sender
- receiver
- argument
Core Library
Verse loads with enough core library to do basic computation, the things necessary to get the rest of the program and libraries loaded, and an extensive string library. The core library is not necessarily meant to be very pretty. In fact, it has to be designed to be quite domain-inspecific in order to remain general enough to apply in many places. Therefore, Verse's default parser has a very simple syntax.
<expression> ::= <message> | <expression> <whitespace> <message> <message> ::= <identifier> | <identifier> <opt-whitespace> <argument> <argument> ::= "(" <string> ")" | "[" <expression> "]" | "{" <string> "}" <whitespace> ::= " " <opt-whitespace> <opt-whitespace> ::= <whitespace> <opt-whitespace> | ""
The (string) form is a normal string argument. The [expression] form is evaluated, and the return value's string representation is the argument. The {string} form returns a string such that when it is evaluated it returns the original string. The former form is the most common. In fact, these latter two forms may be unnecessary and could be removed in the future. Also, keep in mind that individual methods in the core library might parse their arguments differently, such as using commas to denote strings that should be treated as multiple arguments.
Keeping in mind what I said about how it isn't designed to be very pretty, here is an example of what a basic Complex class might look like in Verse's "core syntax".
set (Complex, Object new) Complex set (instanceTemplate, Object new) Complex instanceTemplate set (+, lambda ( Parser Verse evalArgStrAsSender (str, other) return (Complex new ( receiver real + (other real), receiver imaginary + (other imaginary) )) ) ) Complex instanceTemplate set (-, lambda ( Parser Verse evalArgStrAsSender (str, other) return (Complex new ( receiver real - (other real), receiver imaginary - (other imaginary) )) ) ) Complex set (new, lambda ( set (result, Complex instanceTemplate clone) Parser Verse evalArgStrAsSender (str, real : 0, imaginary : 0) set result (real, real) set result (imaginary, imaginary) return (result) ) )
Progress
Less than 100 lines of code so far, so not very much worth mentioning.