Skip to content

Latest commit

 

History

222 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Build Status Coverage Status Dependency Status

RichTea

Welcome to my very first programming language! I hope you like it. I implore you to use RichTea in all your production environments regardless of use-case or the fact that it has many limitations... just kidding.

RichTea is a hobby project which, if nothing else, is an interesting resource and reference point to use when learning to design and implement a simple programming language.

Installation

RichTea makes use of the gradle build process - If you are familiar with gradle compilation should be straight forward.

./gradlew build

To run a RichTea program:

./gradlew run -Pargs="path/to/program.tea"

Language Documentation

RichTea programs are sequences of function calls. Every construct — variables, loops, conditionals — is a function. The syntax follows this general shape:

FunctionName(attribute1:value1 attribute2:value2 :branchName{
  // child functions
})

The first (unnamed) attribute is the implicit attribute. _ always refers to the last returned value.


Setup — Import std

Every program needs the standard library imported first. The runtime only ships with Import built-in.

Import("*" from:"modules/std")

1. Variables — Let and Set

Let declares variables in the current scope. Set mutates an existing variable. Multiple attributes can be declared in one Let.

Import("*" from:"modules/std")

// Declare a single variable
Let(name:"Alice")
Print("Hello, { name }!")  // "Hello, Alice!"

// Declare multiple variables at once
Let(x:10 y:20)
Print("x = { x }, y = { y }")  // "x = 10, y = 20"

// Mutate an existing variable
Set(attribute:name to:"Bob")
Print("Hello, { name }!")  // "Hello, Bob!"

2. String Interpolation

Use { variable } inside any string literal to embed a value.

Import("*" from:"modules/std")

Let(language:"RichTea")
Let(year:2016)
Print("{ language } was created around { year }.")

3. Arithmetic & Expressions

RichTea supports the full set of operators: + - * / % ^ and compound-assignment forms += -= *= /=.

Import("*" from:"modules/std")

Let(a:10 b:3)

Print("Sum:        { a + b }")   // 13
Print("Difference: { a - b }")   // 7
Print("Product:    { a * b }")   // 30
Print("Quotient:   { a / b }")   // 3.333...
Print("Remainder:  { a % b }")   // 1
Print("Power:      { a ^ b }")   // 1000.0

// Increment shorthand
Increment(attribute:a by:1)
Print("a after increment: { a }") // 11

4. Conditionals — If and Switch

If uses a then/else branch. The implicit attribute is the boolean expression.

Import("*" from:"modules/std")

Let(score:75)

If(score >= 60 :{
  Print("Pass!")
} :else{
  Print("Fail.")
})

Switch dispatches on a string value. Branch names are the case labels; default is the fallback.

Import("*" from:"modules/std")

Let(day:"Monday")

Switch(value:day
  :Monday{
    Print("Start of the week!")
  }
  :Friday{
    Print("TGIF!")
  }
  :default{
    Print("Midweek: { day }")
  }
)

5. Loops — For, While, and ForEach

For — counted loop

The loop index is exposed as the as variable inside the do branch.

Import("*" from:"modules/std")

For(5 as:"i" :{
  Print("Iteration { i }")
})
// Prints: Iteration 0 ... Iteration 4

While — condition loop

Import("*" from:"modules/std")

Let(count:0)

While(condition:count < 5 :{
  Print("count = { count }")
  Increment(attribute:count by:1)
})

ForEach — iterate a list

The current element is exposed via the as variable.

Import("*" from:"modules/std")

Let(colours:["red", "green", "blue"])

ForEach(in:colours as:"colour" :{
  Print("Colour: { colour }")
})

6. Arrays and Map

Arrays are declared with [...]. Map transforms every element via a mapFunction branch and returns a new list. _ holds the current element value inside the branch.

Import("*" from:"modules/std")

Let(numbers:[1, 2, 3, 4, 5])

// Double every number
Map(input:numbers :mapFunction{
  Return(_ * 2)
})

// _ now holds [2, 4, 6, 8, 10]
ForEach(in:_ as:"n" :{
  Print("{ n }")
})

7. The _ Last-Return Value

_ is always the result of the most recently executed function, making it easy to chain calls without intermediate variables.

Import("*" from:"modules/std")

Let(words:["hello", "world", "richTea"])

// Map to upper-case, then print the results
Map(input:words :mapFunction{
  Return(_.toUpperCase())
})

ForEach(in:_ as:"word" :{
  Print(word)
})
// HELLO
// WORLD
// RICHTEA

8. Node References & First-Class Functions

Prefix a function with @ to capture a reference to it rather than calling it. The reference can be stored in a variable and called later.

Import("*" from:"modules/std")

// Store a greeting function as a value
Let(greeter:@Print(message:"Hello from a stored function!"))

// Call the reference
greeter()

Parameterised first-class functions work the same way:

Import("*" from:"modules/std")

Let(adder:@(x:0 y:0 :{
  Return(x + y)
}))

adder(x:3 y:4)
Print("3 + 4 = { _ }")  // 3 + 4 = 7

9. Scopes and Return

An anonymous scope (:{...}) groups statements and creates a new variable scope. Return sets the last-return value and exits the current scope.

Import("*" from:"modules/std")

(:{
  Let(temp:42)
  Print("Inside scope: { temp }")
  Return(temp)
})

// _ == 42 here; temp is not accessible outside the scope
Print("Returned from scope: { _ }")

10. File I/O — ReadFile and WriteFile

Import("*" from:"modules/std")

// Write a file
WriteFile(path:"output.txt" contents:"Hello, file!\n")

// Read it back (returns a string by default)
ReadFile(path:"output.txt")
Print("File contents: { _ }")

11. Timing with Timer

Timer injects timeStarted, elapsedTime, and currentTime into its branch scope.

Import("*" from:"modules/std")

Timer(:{
  For(1000000 as:"i" :{}) // Do some work
  Print("Elapsed: { elapsedTime }ms")
})

12. Introspection with Man

Man prints the definition of any function reference — its class, implicit attribute/branch names, and default attribute values.

Import("*" from:"modules/std")

Man(target:@Print())
Print(_)
// Print (richTea.std.exports.Print)
//   Implicit attribute name: message
//   Attributes:
//     appendNewLine (Default value: true)
//     prependNewLine (Default value: false)

13. Putting It All Together — FizzBuzz

Import("*" from:"modules/std")

For(count:20 as:"i" :{
  Let(n:i + 1)

  Switch(value:(n % 15 == 0 ? "fizzbuzz" : (n % 3 == 0 ? "fizz" : (n % 5 == 0 ? "buzz" : "number")))
    :fizzbuzz{ Print("FizzBuzz") }
    :fizz{     Print("Fizz")     }
    :buzz{     Print("Buzz")     }
    :number{   Print("{ n }")   }
  )
})

Quick Reference

Construct Function Key Attributes
Declare variable Let any named attributes
Mutate variable Set attribute, to
Increment Increment attribute, by
Output Print message (implicit), appendNewLine, prependNewLine
Branch If expression (implicit), : (then), :else
Multi-branch Switch value, branch per case, :default
Counted loop For count (implicit), as, : (do)
Condition loop While condition, : (do)
List loop ForEach in, as, : (do)
Transform list Map input, :mapFunction
Read file ReadFile path, asString
Write file WriteFile path, contents
Time a block Timer : (block), exposes elapsedTime
Exit SystemExit code (implicit)
Last return value _
Function reference @Fn(...)

About

RichTea runtime

Resources

Stars

9 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages