• Stars
    star
    24
  • Rank 986,245 (Top 20 %)
  • Language
    Scala
  • Created over 6 years ago
  • Updated almost 6 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

A tiny embedded scripting language implemented in Scala.

Atlas

A tiny embedded scripting language implemented in Scala.

Copyright 2018 Dave Gurnell. Licensed Apache 2.

Build Status Coverage status Maven Central

Why?

Atlas is a super-simple scripting language created for use in Cartographer to allow us to define fragments of logic over user-defined data types. It has the following features:

  • simple, concise, expression-oriented syntax;
  • Scheme-like functional semantics;
  • parser and interpreter written in Scala;
  • serializable in compiled and uncompiled forms;
  • support for "native functions" written in Scala.

Atlas is currently a work-in-progress.

Show me some examples!

Factorials are the "hello world" of scripting languages, right?

let factorial = n ->
  if n <= 1
  then 1
  else n * factorial(n - 1)

factorial(10)

Function bodies are lazily bound allowing letrec-style recursive references:

let even = n ->
  if n == 0 then true else odd(n - 1)

let odd = n ->
  if n == 0 then false else even(n - 1)

even(10)

Quick language reference

Basic literals are Javascript-like:

'foo'      # single-quoted string
"foo"      # double-quoted string
1          # integer
1.2        # double
true       # boolean
null       # null

[a, b]     # array
{a:1, b:2} # object

There are a fixed set of built-in prefix and infix operators. In order of decreasing precedence these are:

!a         # boolean not
-a         # negation
+a         # erm... non-negation

a*b        # multiplication
a/b        # floating point division

a+b        # addition
a-b        # addition

a < b      # comparisons
a > b      # (integer, double, string, or boolean)
a <= b     #
a >= b     #

a == b     # value equality and
a != b     # function reference equality

a && b     # boolean and

a || b     # boolean or

Function literals are written with the -> symbol. Parentheses are optional if there is only one argument:

(a, b) -> a + b
n -> n + 1

In addition to literals, variable references, and infix and prefix operators, there are several types of expression.

Function applications look like Javascript:

max(1, 2)

as do field references:

foo.bar.baz

Conditionals are introduced with the if, then, and else keywords. The else clause is mandatory. The result is the value of the expression in the relevant arm:

if expr then expr else expr

Blocks introduce scopes and allow the definition of intermediate variables. The result is the value of the final expression:

do
  stmt
  stmt
  expr
end

Statements are expressions (evaluated for their side-effects) or declarations, introduced with the let keyword:

let add = (a, b) -> a + b
let ten = add(3, 7)

Function bodies can refer to earlier or later bindings in the block where they are defined, allowing mutually recursive definitions:

let even = n ->
  if n == 0 then true else odd(n - 1)

let odd  = n ->
  if n == 0 then false else even(n - 1)

even(10)

Comments are written with the # symbol and run to the end of the line:

# Calculate a factorial:
let fact = n ->
  if n == 1
  then 1
  else n * fact(n - 1)

Complete programs have the same semantics as blocks but are written without the do and end keywords. If the program ends with a statement, an implicit null expression is added to the end:

let fib = n ->
  if n <= 2
  then 1
  else fib(n - 1) + fib(n - 2)

fib(10)

Interaction with Scala

There are two string interpolators for defining code fragments: expr for expressions and prog for complete programs:

import atlas._
import atlas.syntax._

val anExpression: Expr =
  expr"""
  1 + 2 + 3
  """

val aProgram: Expr =
  prog"""
  let fib = n ->
    if n <= 2
    then 1
    else fib(n - 1) + fib(n - 2)

  fib(10)
  """

Syntax errors raised by the macros result in a Scala compilation error.

You can alternatively use the Parser.expr or Parser.prog methods to parse a regular Scala string: Syntax errors using the parser result in an Either:

val anotherExpression: Either[Parser.Error, Expr] =
  Parser.expr("1 + 2 + 3")

Expressions (and, by extension, programs) can be evaluated using the Eval.apply method. Runtime errors are captured in an Either:

Eval(anExpression) // => Right(IntValue(6))

Eval(aProgram)     // => Right(IntValue(55))

You can optionally pass an Env object to Eval.apply specifying an initial environment:

val program = prog"a + b"
val env = Env.create
  .set("a", 10)
  .set("b", 32)
Eval(program, env) // => Right(IntValue(42))

Although Eval can internally mutate environments to enable mutually recursive function bodies, any environment you pass to Eval.apply should be returned unharmed.

You can implement "native functions" in Scala:

val program = prog"average(10, 5)"
val env = Env.create
  .set("average", native((a: Double, b: Double) => (a + b) / 2))
Eval(program, env) // => Right(DoubleValue(7.5))

Conversion between Atlas and Scala values is implemented using a pair of type classes called ValueEncoder and ValueDecoder. These can be used with the as[A] and asValue extension methods from atlas.syntax:

123.asValue      // => IntValue(123)

IntValue.as[Int] // => Right(123)

Acknowledgements

Thanks to Nic Pereira for naming the project and saving us all from "davescript" :)

More Repositories

1

bridges

Generate bindings for Scala types in other programming languages.
Scala
56
star
2

unindent

Indent-adjusted multiline string literals for Scala.
Shell
48
star
3

checklist

Validation library for Scala.
Scala
47
star
4

bulletin

Automatically perform shallow merges on case classes. Treat your data with the latest updates!
Scala
42
star
5

meowsynth

The mighty meowing synthesizer!
Scala
30
star
6

validation

Scala data validation library
Scala
29
star
7

typelevel-todomvc

Scala
25
star
8

shapeless-guide

The Type Astronaut's Guide to Shapeless
19
star
9

functional-data-validation

Slides and code samples for a talk on thinking functionally (and validating web forms).
Scala
18
star
10

99-ways-to-di

Slides from my lightning talk on Dependency Injection at Scala Central #5.
14
star
11

css-selector

Lift-style CSS selector transforms based on Scalate's Scuery
Scala
10
star
12

tipi

Tiny templating language written in Scala.
Scala
10
star
13

macros-vs-shapeless

Slides and code samples on meta-programming techniques in Scala.
Scala
10
star
14

spandoc

Write Pandoc filters in Scala.
Scala
7
star
15

scalalol-2011-talk

Slides and code samples for talk at Scala Lift-Off London 2011.
Scala
6
star
16

scala-opengl

Simple OpenGL examples using Scala, LWJGL, and sbt-lwjgl
Scala
6
star
17

shapeless-guide-slides

Slides for my Scala World 2016 workshop on shapeless.
6
star
18

smartypants

Simple smart constructor generation for Scala.
Scala
4
star
19

scalax2gether-2017

Workshop and hack proposals for the Scala Exchange Hack Day (ScalaX2gether 2017)
4
star
20

shapeless-sandbox

Scala
3
star
21

scalax-2014

Slides and code samples for my Scala Exchange 2014 talk on Functional Data Validation.
3
star
22

typelevel-philly-2016

3
star
23

sbt-less

Superseded by sbt-less in https://github.com/untyped/sbt-plugins.
Scala
3
star
24

akka-streams-case-study

Scala
2
star
25

poker-case-study

Poker hand comparison in Scala. A fairly advanced "Essential Scala" case study.
Scala
2
star
26

interpreter-case-study

Scala case study about building an interpreter and a simple DSL.
Scala
2
star
27

cats-error-case-study

Scala
2
star
28

bus-driver-case-study

Gossiping Bus Drivers Kata
Scala
2
star
29

scala-rpg-test

A sandbox project for playing with Scala and the graphics from Browserquest.
Scala
2
star
30

concurrency-case-study

Scala
2
star
31

versionit

Grab your Git commit hash as a Scala String.
Scala
2
star
32

advanced-scala-scalax15

Code written at Advanced Scala at Scala Exchange 2015
Scala
1
star
33

spectaskular-iphone

iPhone todo list app
Objective-C
1
star
34

brighton-java-sample-app

Scala talk for Brighton Java
CSS
1
star
35

session-cell

Cookie-based in-memory session storage for the Racket HTTP Server.
Scheme
1
star
36

kitties-case-study

Meow!
Scala
1
star
37

gilded-rose-case-study

Code refactoring kata
Scala
1
star
38

conway-case-study

Scala
1
star
39

mars-rover-case-study

Scala
1
star
40

asyncjs-creative-fp

Creative Functional Programming talk for AsyncJS.
1
star
41

parallel-case-study

Scala
1
star
42

bank-ocr-case-study

Scala
1
star
43

play-json-case-study

Scala
1
star
44

calc-case-study

Scala
1
star
45

bowling-case-study

Scala
1
star
46

advanced-scala

The old source code repository for Scala with Cats
1
star
47

paths-case-study

Essential Scala case study: selecting paths from a route finder service
Scala
1
star
48

typeclub

Scala
1
star
49

tagless-case-study

Scala
1
star
50

composejs

Javascript port of Compose (https://github.com/underscoreio/compose).
JavaScript
1
star
51

doodlejs

Javascript port of Doodle
JavaScript
1
star
52

fpinscala

My attempts at the exercises in Functional Programming in Scala.
Scala
1
star
53

shapeless-guide-code

The Type Astronaut's Guide to Shapeless (Example Code)
1
star
54

scaladays-berlin-2016

1
star
55

property-based-testing-workshop

Scala
1
star
56

advanced-scala-exercises

Scala
1
star
57

away-with-the-types

Scala
1
star
58

cats-effect-sandbox

An empty SBT project with dependencies on Cats and Cats Effect.
Scala
1
star