Skip to content

Commit

Permalink
Updated the version to 0.4.0, updated the README, and added more list…
Browse files Browse the repository at this point in the history
… operations.
  • Loading branch information
bluebear94 committed Jan 7, 2014
1 parent 92cf694 commit 05d0219
Show file tree
Hide file tree
Showing 9 changed files with 319 additions and 9 deletions.
102 changes: 100 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,103 @@
amethyst
========

$:hluna("A programming language
Welcome back to the 1980s :P
$:hluna("A programming language by bluebear94

Philosophy
----------

I wanted to invent a language that followed the path of TI-Basic. In October, I wrote an initial attempt at Java (named Labyrinth, since it was supposed to be difficult to understand), but it quickly became messy, so I left the project for a while, until I rewrote it in Scala at the beginning of December (and named it Amethyst).

I made some choices to fulfill the TI-Basic philosophy:

* The interface consists of a top screen (implemented by a BufferedImage, similar to how calculator graphics are implemented) for graphics and a bottom screen resembling the TI-89 homescreen (with the input allowing multiple lines.
* Unclosed parentheses, brackets, braces, quotes, and guillemets are permitted.
* "Global variables" are actually persistent files.
* No optimization is performed for you, especially not tail-call optimization. Do it yourself.
* No objects or even structures. Use lists or maps.
* There is a last-answer variable: one accounting for Void return values, and one not.
* There is no passing by reference; only value.

However, I deviated from typical calculator programming languages in order to reduce the annoyance of using it:

* First class functions and lists, including lambdas (You can pass functions as arguments, as well as nest lists as much as you want, or at least as much as your computer can handle).
* A built-in map type, since maps are frequently used, especially in this code.
* Three numerical types: arbitrary-precision, 64-bit integers, and 64-bit IEEE floating-points (a. k. a. doubles).
* Two list types: arrays (like 83+) and linked lists (like 89), because each has its strengths and weaknesses. Plus, their dimensions are limited only by memory.
* Programs are planned to be stored using bytecode, with an option to compile without running (I think the TI-89's inability to do so was a big annoyance).
* A Void type and value.
* Zero-based, rather than one-based, indexing for lists.

This language is still in its infancy; many commands are still not implemented. However, they will eventually exist.

How to Get
----------

Amethyst is usable at this time, but is not in condition to release.

* Install Git and SBT if you had not already done so.
* Open up a terminal and `cd` into a directory.
* Create a directory (`mkdir amethyst`) and `cd` into it.
* Do `git clone https://github.com/bluebear94/amethyst` to get the project (update with `git pull origin master`)
* Type `sbt`
* As soon as SBT finishes loading, type `run`
* Then wait for everything to compile and choose an option: `1` to start the developer console, and `2` to start the GUI program

Getting Started
---------------

In order to run a piece of code, simply type it in the bottom panel and press the <kbd>Run</kbd> button (or, alternatively, <kbd>Ctrl</kbd> + <kbd>Enter</kbd>).

The current operators are:

* \+
* \-
* @ (average)
* \*
* /
* \\ (int division)
* %
* ==
* \!=
* <
* <=
* >
* >=
* &&
* ||
* ? and :

Precedence can, of course, be specified by parentheses, and `&&` and `||` are short-circuit operators (and they are not guaranteed to return either 0 or 1).

Variables can be assigned using the `=` operator (with no right side, it just deletes the variable). Global variables are denoted by `$`, and they persist through multiple sessions. Some operators also provide an assignment equivalent, as well as doubled versions that can appear before *or* after an lvalue.

Functions use lambdas, and the body is delimited with the `λ` and `Endλ` keywords. The last line defines the return value of the function. The number of arguments can be retrieved with `#0`, and each argument can be retrieved with an octothrope preceding a one-indexed value. Therefore, a function to square a number would be defined as:

square = λ; #1 * #1; Endλ

Lists come in two flavors: *arrays* delimited by *braces*, and *linked lists* delimited by *square brackets*. They can be indexed using brackets as well; e. g. `{3, 5, 7}[1]` returns the second element of a list. They support batch operations as well (`&&` and `||` do not work; newer versions will support `&'` and `|'` which lack short-circuiting but work on lists). Indexing *does* work on strings and even *integers* as well.

Each expression modifies the last-answer variable `Ans`, and `Answer` as well for non-void values.

The `If` keyword, followed by an expression, executes the next line if that expression evaluates to true. The execution of subsequent code does not depend on the truth or falsity of that expression; for example:

If a
$:hluna("a
$:hluna("b

will always print `b`. Note that there is no separate Boolean type; instead, `0`, `↼0`, `0.`, `""`, `{}`, and `[]` all evalute to false.

The `If` statement, if the following code is delimited by `Then` and `EndIf`, will execute the whole block conditionally.

The `For` .. `EndFor` loop will execute a block of code for each value of a variable. Its syntax is:

For variable, start, end [,incr]
(statements)
EndFor

The `While` .. `EndWhile` loop executes the body while its head expression evaluates to true, while the `Repeat` .. `EndRept` loop defers the check to after the body executes.

Documentation of Commands
-------------------------

Coming soon.
98 changes: 98 additions & 0 deletions README.md~
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
amethyst
========

$:hluna("A programming language by bluebear94

Philosophy
----------

I wanted to invent a language that followed the path of TI-Basic. In October, I wrote an initial attempt at Java (named Labyrinth, since it was supposed to be difficult to understand), but it quickly became messy, so I left the project for a while, until I rewrote it in Scala at the beginning of December (and named it Amethyst).

I made some choices to fulfill the TI-Basic philosophy:

* The interface consists of a top screen (implemented by a BufferedImage, similar to how calculator graphics are implemented) for graphics and a bottom screen resembling the TI-89 homescreen (with the input allowing multiple lines.
* Unclosed parentheses, brackets, braces, quotes, and guillemets are permitted.
* "Global variables" are actually persistent files.
* No optimization is performed for you, especially not tail-call optimization. Do it yourself.
* No objects or even structures. Use lists or maps.
* There is a last-answer variable: one accounting for Void return values, and one not.
* There is no passing by reference; only value.

However, I deviated from typical calculator programming languages in order to reduce the annoyance of using it:

* First class functions and lists, including lambdas (You can pass functions as arguments, as well as nest lists as much as you want, or at least as much as your computer can handle).
* A built-in map type, since maps are frequently used, especially in this code.
* Three numerical types: arbitrary-precision, 64-bit integers, and 64-bit IEEE floating-points (a. k. a. doubles).
* Two list types: arrays (like 83+) and linked lists (like 89), because each has its strengths and weaknesses. Plus, their dimensions are limited only by memory.
* Programs are planned to be stored using bytecode, with an option to compile without running (I think the TI-89's inability to do so was a big annoyance).
* A Void type and value.
* Zero-based, rather than one-based, indexing for lists.

This language is still in its infancy; many commands are still not implemented. However, they will eventually exist.

How to Get
----------

Amethyst is usable at this time, but is not in condition to release.

* Install Git and SBT if you had not already done so.
* Open up a terminal and `cd` into a directory.
* Create a directory (`mkdir amethyst`) and `cd` into it.
* Do `git clone https://github.com/bluebear94/amethyst` to get the project (update with `git pull origin master`)
* Type `sbt`
* As soon as SBT finishes loading, type `run`
* Then wait for everything to compile and choose an option: `1` to start the developer console, and `2` to start the GUI program

Getting Started
---------------

In order to run a piece of code, simply type it in the bottom panel and press the <kbd>Run</kbd> button (or, alternatively, <kbd>Ctrl</kbd> + <kbd>Enter</kbd>).

The current operators are:

* \+
* \-
* @ (average)
* \*
* /
* \\ (int division)
* %
* ==
* \!=
* <
* <=
* >
* >=
* &&
* ||
* ? and :

Precedence can, of course, be specified by parentheses, and `&&` and `||` are short-circuit operators (and they are not guaranteed to return either 0 or 1).

Variables can be assigned using the `=` operator (with no right side, it just deletes the variable). Global variables are denoted by `$`, and they persist through multiple sessions. Some operators also provide an assignment equivalent, as well as doubled versions that can appear before *or* after an lvalue.

Functions use lambdas, and the body is delimited with the `λ` and `Endλ` keywords. The last line defines the return value of the function. The number of arguments can be retrieved with `#0`, and each argument can be retrieved with an octothrope preceding a one-indexed value. Therefore, a function to square a number would be defined as:

square = λ; #1 * #1; Endλ

Lists come in two flavors: *arrays* delimited by *braces*, and *linked lists* delimited by *square brackets*. They can be indexed using brackets as well; e. g. `{3, 5, 7}[1]` returns the second element of a list. They support batch operations as well (`&&` and `||` do not work; newer versions will support `&'` and `|'` which lack short-circuiting but work on lists). Indexing *does* work on strings and even *integers* as well.

Each expression modifies the last-answer variable `Ans`, and `Answer` as well for non-void values.

The `If` keyword, followed by an expression, executes the next line if that expression evaluates to true. The execution of subsequent code does not depend on the truth or falsity of that expression; for example:

If a
$:hluna("a
$:hluna("b

will always print `b`. Note that there is no separate Boolean type; instead, `0`, `↼0`, `0.`, `""`, `{}`, and `[]` all evalute to false.

The `If` statement, if the following code is delimited by `Then` and `EndIf`, will execute the whole block conditionally.

The `For` .. `EndFor` loop will execute a block of code for each value of a variable. Its syntax is:

For variable, start, end [,incr]
(statements)
EndFor

The `While` .. `EndWhile` loop executes the body while its head expression evaluates to true, while the `Repeat` .. `EndRept` loop defers the check to after the body executes.
4 changes: 2 additions & 2 deletions src/main/scala/cmdreader/Global.scala
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ object Global {
var current: File = root
val TWO = new BigInteger("2")
val vM = 0
val vm = 3
val vr = 7
val vm = 4
val vr = 0
val version = vM + "." + vm + "." + vr
}
33 changes: 33 additions & 0 deletions src/main/scala/cmdreader/std/Cons.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package cmdreader.std

import cmdreader.Command
import types._
import scala.collection.mutable._

class Cons extends Command {
override def getName(): String = "cons"
override def isValidArg0(n: Int): Boolean = n == 2
override def apply(args: Array[Type]): Type = {
val t = args(0)
val l = args(1)
try {
l match {
case a: LArray => new LArray((t +: a.l).to[ArrayBuffer])
case a: LLinked => new LLinked((t +: a.l).tail.to[ListBuffer])
case s: TString => {
new TString(new String(Array[Char](
t match {
case n: TMountain => n.getVal.longValue.toChar
case n: THill => n.getVal.toChar
case n: TFish => n.getVal.toChar
case _ => throw new RuntimeException
})) + s.getVal)
}
case _ => new TError(1)
}
}
catch {
case e: RuntimeException => new TError(1)
}
}
}
17 changes: 17 additions & 0 deletions src/main/scala/cmdreader/std/ECar.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package cmdreader.std

import cmdreader.Command
import types._

class ECar extends Command {
override def getName(): String = "ecar"
override def isValidArg0(n: Int): Boolean = n == 1
override def apply(args: Array[Type]): Type = {
val l = args(0)
l match {
case a: LList => a.l.last
case s: TString => new THill(s.getVal.last)
case _ => new TError(1)
}
}
}
19 changes: 19 additions & 0 deletions src/main/scala/cmdreader/std/ECdr.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package cmdreader.std

import cmdreader.Command
import types._
import scala.collection.mutable._

class ECdr extends Command {
override def getName(): String = "ecdr"
override def isValidArg0(n: Int): Boolean = n == 1
override def apply(args: Array[Type]): Type = {
val l = args(0)
l match {
case a: LArray => new LArray(a.l.init.to[ArrayBuffer])
case a: LLinked => new LLinked(a.l.init.to[ListBuffer])
case s: TString => new TString(s.getVal.init)
case _ => new TError(1)
}
}
}
33 changes: 33 additions & 0 deletions src/main/scala/cmdreader/std/ECons.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package cmdreader.std

import cmdreader.Command
import types._
import scala.collection.mutable._

class ECons extends Command {
override def getName(): String = "econs"
override def isValidArg0(n: Int): Boolean = n == 2
override def apply(args: Array[Type]): Type = {
val t = args(0)
val l = args(1)
try {
l match {
case a: LArray => new LArray((a.l :+ t).to[ArrayBuffer])
case a: LLinked => new LLinked((a.l :+ t).tail.to[ListBuffer])
case s: TString => {
new TString(s.getVal + new String(Array[Char](
t match {
case n: TMountain => n.getVal.longValue.toChar
case n: THill => n.getVal.toChar
case n: TFish => n.getVal.toChar
case _ => throw new RuntimeException
})))
}
case _ => new TError(1)
}
}
catch {
case e: RuntimeException => new TError(1)
}
}
}
4 changes: 4 additions & 0 deletions src/main/scala/cmdreader/std/Loader.scala
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,9 @@ class Loader {
Global.liblist("std").loadCmd("OGe")
Global.liblist("std").loadCmd("Car")
Global.liblist("std").loadCmd("Cdr")
Global.liblist("std").loadCmd("Cons")
Global.liblist("std").loadCmd("ECar")
Global.liblist("std").loadCmd("ECdr")
Global.liblist("std").loadCmd("ECons")
}
}
18 changes: 13 additions & 5 deletions src/main/scala/gui/Main.scala
Original file line number Diff line number Diff line change
Expand Up @@ -86,12 +86,20 @@ object Main extends SimpleSwingApplication {
println(toRun)
inputArea.text = ""
status = BUSY
val bc = WholeParser.parse(toRun, p)
val tp = Global.top
tp.bytecode = bc
tp.run
try {
val bc = WholeParser.parse(toRun, p)
val tp = Global.top
tp.bytecode = bc
tp.run
println(tp.ans + "\n")
} catch {
case e: RuntimeException => {
println(e.getMessage)
System.out.println(e.getMessage)
System.out.println(e.getStackTrace)
}
}
status = IDLE
println(tp.ans + "\n")
}
}
}
Expand Down

0 comments on commit 05d0219

Please sign in to comment.