impl/

directory
v1.6.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 8, 2026 License: MIT

README

Implementation Package (impl/)

This package contains the runtime implementation of the CalcMark interpreter. While spec/ defines the language specification (parsing, AST, types), impl/ executes it.

Package Overview

Package Purpose
interpreter/ Core expression evaluator - executes AST nodes
document/ Document-level evaluation orchestration
types/ Runtime type operations (arithmetic, conversions)
wasm/ WebAssembly bindings for browser use

In-Memory Data Structures

Understanding how CalcMark represents documents and variables in memory:

Document (spec/document/document.go)
  └── []BlockNode                    // Ordered list of blocks
        ├── ID string                // Unique block identifier
        └── Block                    // Either CalcBlock or TextBlock
              │
              ├── CalcBlock (spec/document/block.go)
              │     ├── source []string      // Raw source lines
              │     ├── statements []Node    // Parsed AST nodes
              │     ├── variables []string   // Variable NAMES defined in this block
              │     ├── dependencies []string // Variable names referenced from other blocks
              │     ├── results []Type       // Per-statement evaluation results
              │     └── lastValue Type       // Result of last statement (not per-variable!)
              │
              └── TextBlock (spec/document/block.go)
                    └── source []string      // Markdown text lines

Evaluator (impl/document/evaluator.go)
  └── env *Environment               // THE source of truth for variable VALUES
        └── vars map[string]Type     // Global variable bindings (e.g., x → 10)

Key Concepts

Global Variable Scope

All variables in CalcMark have global scope. A variable defined in one block is accessible in all subsequent blocks. Reassignment in any block updates the single global binding.

x = 10      # Block 1: defines x
---
y = x + 5   # Block 2: references x from block 1, y = 15
---
x = 100     # Block 3: reassigns global x
Understanding CalcBlock Fields
  • CalcBlock.Variables() returns variable names defined in that block (for dependency tracking and UI display ordering), NOT values.

  • CalcBlock.LastValue() returns the result of the last statement in the block, not individual variable values. For a block with x = 5 followed by y = 10, LastValue() returns 10 (y's value).

  • CalcBlock.Results() returns all per-statement results in order.

The Environment is the Source of Truth

Environment.Get(name) is the single source of truth for current variable values. The Evaluator maintains one Environment across all block evaluations.

eval := NewEvaluator()
eval.Evaluate(doc)

// Get current variable values from the environment
env := eval.GetEnvironment()
value, ok := env.Get("x")  // Returns current value of x
DependencyAnalyzer

DependencyAnalyzer (spec/document/deps.go) is a utility that analyzes a CalcBlock to extract which variable names it defines and references. It populates CalcBlock.variables and CalcBlock.dependencies but doesn't store values.

Evaluation Flow

Single Expression
Source Text
    ↓
Lexer (spec/lexer) → Tokens
    ↓
Parser (spec/parser) → AST Nodes
    ↓
Semantic Checker (spec/semantic) → Validated AST + Diagnostics
    ↓
Interpreter (impl/interpreter) → Results + Updated Environment
Document-Level Evaluation
// Parse source into a document with blocks
doc, err := document.NewDocument(source)
if err != nil {
    // Handle parse error
}

// Create evaluator (holds the Environment)
eval := NewEvaluator()

// Evaluate all blocks top-down
err = eval.Evaluate(doc)
if err != nil {
    // Handle evaluation error
}

// Access results
for _, node := range doc.GetBlocks() {
    if calcBlock, ok := node.Block.(*document.CalcBlock); ok {
        fmt.Println(calcBlock.LastValue())  // Last statement result
    }
}

// Access current variable values
env := eval.GetEnvironment()
if val, ok := env.Get("total"); ok {
    fmt.Printf("total = %v\n", val)
}
Incremental Evaluation (REPL)

For interactive use, reuse the same Evaluator to maintain variable state:

eval := NewEvaluator()

// First evaluation
doc1, _ := document.NewDocument("x = 10\n")
eval.Evaluate(doc1)

// Later: add a new block that references x
result, _ := doc1.InsertBlock(lastBlockID, document.BlockCalculation, []string{"y = x + 5"})
eval.EvaluateBlock(doc1, result.ModifiedBlockID)

// Environment now has both x=10 and y=15
env := eval.GetEnvironment()

Testing

Run interpreter tests:

go test ./impl/interpreter/... -v

Run document evaluation tests:

go test ./impl/document/... -v

Key test files:

  • interpreter/interpreter_test.go - Core evaluation tests
  • document/evaluator_test.go - Document and global scope tests

Directories

Path Synopsis
cmd
calcmark command
Package interpreter provides the CalcMark expression interpreter.
Package interpreter provides the CalcMark expression interpreter.
Package types defines the CalcMark type system
Package types defines the CalcMark type system

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL