Making a programming language Part 4 - Hello World


Table of contents, Whole project on github

What good is a language if you cannot do a Hello World program. Every tutorial on every language I ever read has a Hello World in it somewhere, even if it’s a convoluted and sarcastic one.

So what do I need?

In that order. Since this is more of a math lang for now my first hello world can just print 1 - arguably the simplest number.

Println

This one is super easy. Just wrap scala’s println. Here’s the whole code

1
2
3
4
5
6
lazy val sprint: FunctionVarArg = {
  case lst: List[_] =>
    lst --> mkString --> println
  case other =>
    throw ScratInvalidTypeError("expected a commaList but got " + other)
}

And then I put this as “println” into StdLib’s map = global namespace. Since I already have support for functions I just allowed them to do side effects(semantics-no code).
The --> operator might have confused you. It’s in an implicit conversion I defined:

1
2
3
implicit def any2applyFunc[A](a: A) = new AnyRef {
  def -->[B](f: A => B): B = f(a)
}

This is the so called pimp my library pattern in scala. It adds the --> operator to all objects. This operator takes another single argument function, applies it and returns the result. So I can have

1
lst --> mkString --> println

instead of

1
println(mkString(lst))

Think of it like Haskell’s $ operator even if it works in a different way. Oh yes, mkString is another function that I put into StdLib that takes a List(takes Any but does pattern matching) and returns List.mkString

And now I have my Hello Math World

1
println(1)

Strings

First I have to parse strings

1
2
3
4
private def string: Parser[SString] = "\".*?\"".r ^^ { s =>
  SString(s.substring(1, s.length - 1))
}
private def value: Parser[Expression] = number | string | identifier

SString is just a case class wrapper for string that extends Expression so I can use it in other expressions. When I was first writing this I forgot to add the action combinator to strip of the quotes and was greatly mistified by all strings being wrapped in “”. I even spend half an hour debugging my evaluator before it dawned on me. I believe the evaluation of this is trivial.

Now I have a REAL hello world:

1
    println("Hello world")

Well…no. Hello world is a program you run. I need an interpreter to run files.

Interpreter

Not quite that different from REPL. In fact it’s just REL: read, evaluate, loop. Printing is now only with explicit println calls. And I don’t need to catch exceptions and return into the loop.  Whole code for the interpreter

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
object Interpreter {
  def main(args: Array[String]) = {
    if (args.length != 1) {
      println("parameters: filename to interpret")
    } else {
      interpretFile(new File(args(0)))
    }
  }
  val runtime = new ScratRuntime
  def interpretFile(file: File) {
    if (file.canRead) {
      val source = io.Source.fromFile(file)
      source.getLines().foreach(runtime.eval)
      source.close()
    } else {
      println("cannot open file " + file.getPath)
    }
  }
}


And now I can put my hello world in a file and run it.
But I needed to decide on the extension. I know it’s silly but I didn’t want to save the file until I had the extension in mind. And this mean naming the language. Being in “logic mode” I asked my awsome girlfriend who’s more artsy type of a person and she immediately responded “scrat”(she’s huge fan of Scrat the squirrel from Ice Age). And them some more funny names, but scrat stuck with me. So I named the file hello.scrat.

next: variables and decisions


Last modified on 2012-09-01

Previous Making a programming language Part 3 - adding features
Next Making a programming language Part 5 - variables and decisions