Har under en tid implementerat ett enkelt Smalltalk/Javascript/Io-likt dynamiskt, objektorienterat och prototypbaserat programmeringspråk i Java för att öva på att skriva parsers och interpretatorer. Parsern är en enkel "recursive-decent parser" med 1-look-a-head och det abstrakta syntaxträdet körs direkt. Språket kan interopera med Java och har stöd för list-literaler ([1, 2]), strängliteraler ("Hello world"), symboler (:symbol) nummer (1, 2.2 etc).
Det obligatoriska "Hello world"-programmet:
$ java -jar bs.jar
>> System puts "Hello world".
Interoperabilitet (test.bs):
import("java.io.File").
f := java.io.File new ".".
System puts f listFiles.
$ java -jar bs.jar test.bs
[lista med="med" filer="filer"]
Det finns bara en operator, tilldelning (:=) alla andra operationer är meddelanden. Därför är "precedence"-ordningen för + - / * osv inte definierad som i exempelvis C.
Exempelvis:
$ java -jar bs.jar
>> 10 * 10 + 10
200 # dsv 10 * (10 + 10)
Anledningen är att paranteser är frivilliga. Dsv
är samma som
Detta innebär att anrop evalueras i samma ordning som med paranteser:
Syntaxen (en aning inkomplett):
program ::= statements
statements ::= statement { statement }
statement ::= assign | expression "."
assign ::= identifier := expression
expression ::= symbol | call
call ::= symbol [message { message }]
call ::= message { message } # with parentheses
message ::= identifier [ expression ["," {expression}]]
message ::= identifier "(" [ expression ["," {expression}]] ")"
symbol ::= identifier | number | string | list | block
list ::= "[" expression ["," { expression }] "]"
block ::= "{" "|" [identifier ["," {identifier}]] "|"
statement { statement } "}"
Exempel fiboncci (rekursiv):
<<=(:fib, { | n |
(n <= 1) ifTrue {
return(n).
}, {
return(self fib(n - 1) + self fib(n - 2)).
}.
System puts fib 8.
}).
* <<=: definerar en metod, med namnet :fib, och kroppen { | n | ... } som tar ett argument.
* (n <= 1): anropa metoden <= på n med argumentet 1 varpå metoden ifTrue anropas. Om n <= 1 så körs det första blocket annars det andra.
* return(): returnerar ett värde
Exempel (while-loop):
num := 0.
{num <= 10.} whileTrue {
System puts num.
num := num + 1.
}.
* {num <= 10.}: Block som methoden whileTrue anropas på. Sålänge num <= 10 körs blocket som är argument till whileTrue.
Språket stödjer "Exceptions":
e := Proto try {
Error raise "Raising an error!".
}.
e catch Error, { | e |
System puts e getMessage.
}.
Objektorientering:
Person := Proto clone :Person.
Person <<= :init, { | name |
self <<- :name, :age.
age := 10.
}.
Person <<= :setName, { | n |
name := n.
}.
Person <<= :getName, {
return(name).
}.
Person <<= :toString, {
name + age toString.
}.
Person <<= :getAge, {
age.
}.
p := Person clone "Hello World".
System puts p getName.
System puts p toString.
System puts p getCode. # från Proto
System puts p metodSomInteFinns. # NameError
Skapar en ny prototyp av Proto (som är rotobjektet), och lägger till några metoder (<<=).
Ladda ner och testa: https://github.com/isakkarlsson/bs/downloads
Mer information (endast påbörjad): http://isakkarlsson.github.com/bs/
Fler exempel: https://github.com/isakkarlsson/bs/
Notera att prestandan är ganska dålig (ungefär hälften av Ruby senast jag kollade).