🌍 Pangea / Pang

How the Interpreter Works

The Evaluation Mechanism

Pangea's interpreter is built around three core functions that work together to parse and execute programs:

program_words() Tokenizer phrase_length() Parser evaluate_word() Evaluator word_definitions{}

Phase 1: Tokenization (program_words)

Input: Text String

print add 5 6

Process:

Output: Token Array

print add 5 6

String Handling Example

print " Hello World "

Tokenizes to: ["print", "Hello World"]

The quotes are removed, and the text between them becomes a single token.

Phase 2: Phrase Length Calculation (phrase_length)

This function determines how many tokens each expression consumes. It's the key to understanding nested expressions.

Algorithm:

function phrase_length(word_index)
  if word is a number → return 1
  if word is a literal (after :) → return 1
  if word is "do" → count to matching "end"
  
  word_definition = lookup(word)
  arity = word_definition.argument_count
  
  length = 1  // the operator itself
  for each argument (1 to arity):
    length += phrase_length(next_position)
  
  return length

Visual Example: add multiply 2 3 4

add multiply 2 3 4

Calculate phrase_length(1) for "add":

  • add has arity 2 → needs 2 arguments
  • Argument 1 starts at position 2

Calculate phrase_length(2) for "multiply":

  • multiply has arity 2
  • Takes position 3 (value: 2) → length 1
  • Takes position 4 (value: 3) → length 1
  • Total: 1 (multiply) + 1 + 1 = 3 tokens
  • Argument 1 length = 3 (the "multiply 2 3" sub-expression)
  • Argument 2 starts at position 5 (2 + 3)
  • Argument 2 is "4" → length 1
  • Total: 1 (add) + 3 + 1 = 5 tokens

Result: The entire expression is 5 tokens long.

Phase 3: Evaluation (evaluate_word)

Now we recursively evaluate the expression using the phrase lengths:

Algorithm:

function evaluate_word(word_index)
  word = words[word_index]
  
  // Base case: number
  if word is a number → return that number
  
  // Get word definition
  word_definition = word_definitions[word]
  arity = word_definition.arity
  function = word_definition.function
  
  // Collect argument indices (not values!)
  arguments = []
  position = word_index + 1
  for i = 1 to arity:
    arguments.push(position)
    position += phrase_length(position)
  
  // Execute function (which will recursively evaluate arguments)
  return function(arguments)

Animated Walkthrough: print add 5 6

🟢 Step 1: evaluate_word(1) - "print"

print add 5 6

✓ Found word_definition for "print"
✓ Arity: 1
✓ Argument 1 at index 2

🟡 Step 2: Call print_function with [2]

print_function needs to evaluate its argument first...

🟢 Step 3: evaluate_word(2) - "add"

print add 5 6

✓ Found word_definition for "add"
✓ Arity: 2
✓ Argument 1 at index 3
✓ Argument 2 at index 4

🟡 Step 4: Call add_function with [3, 4]

add_function evaluates both arguments...

🟢 Step 5: evaluate_word(3) - "5"

print add 5 6

✓ It's a number → return 5

🟢 Step 6: evaluate_word(4) - "6"

print add 5 6

✓ It's a number → return 6

⬅ Step 7: add_function returns

5 + 6 = 11

⬅ Step 8: print_function receives 11

Prints: 11

Output: 11

Call Stack Visualization

For function calls, Pangea maintains a call stack with local variable contexts:

Example: Factorial Recursion

define_word factorial 1
  if equal 0 argument 1
    1
    multiply argument 1 factorial add -1 argument 1

print factorial 3
Call Stack Evolution factorial(3) arg[1] = 3 3 * fact(2) factorial(2) arg[1] = 2 2 * fact(1) arg[1] = 3 waiting... factorial(1) arg[1] = 1 1 * fact(0) arg[1] = 2 arg[1] = 3 factorial(0) → 1 Returns 1 (base case) Unwinding 1 * 1 = 1 2 * 1 = 2 3 * 2 = 6

Key Implementation Details

1. Deferred Evaluation

Functions receive indices to arguments, not values. This allows:

2. The words[] Global Array

All tokens are stored in a single global array. Functions work with indices into this array, making it easy to handle nested expressions and file includes.

3. word_definitions Table Structure

word_definitions = {
  ["print"] = {1, print_function},
  ["add"] = {2, add_function},
  ["if"] = {3, if_function},
  ...
}

-- Format: {arity, function}

4. Translation Layer

The tr() function wraps all keyword access, allowing seamless Italian/English switching:

word_definitions[tr("print")] = {1, print_function}
// Registers as "print" in English mode
// Registers as "stampa" in Italian mode

Complete Flow Diagram

User Input / File program_words() words[] = [token, token, ...] Global token array evaluate_word(index) Recursive evaluation using phrase_length() recursive word_definitions {word: [arity, fn]} Result / Side Effects

🎓 Next Steps

Now that you understand the evaluation mechanism, see it in action with real examples including FizzBuzz and factorial implementations.