cemc 0.1.2

Cem language compiler - A concatenative language with green threads and linear types
Documentation
# core.cem - Essential Combinators for Cem
#
# These are the foundational building blocks for stack-based programming.
# They are always available and form the basis for all other combinators.

# NOTE: Basic stack operations (dup, drop, swap, over, rot) are built into
# the compiler and don't need definitions here. This file documents their
# signatures and provides higher-level combinators built on top of them.

# ============================================================================
# BASIC STACK OPERATIONS (built-in)
# ============================================================================

# These are provided by the compiler but documented here for reference:

# : dup ( A -- A A )
#   Duplicate the top element of the stack

# : drop ( A -- )
#   Remove the top element of the stack

# : swap ( A B -- B A )
#   Swap the top two elements

# : over ( A B -- A B A )
#   Copy the second element to the top

# : rot ( A B C -- B C A )
#   Rotate the top three elements

# ============================================================================
# FUNDAMENTAL COMBINATORS
# ============================================================================

: dip ( rest A [rest -- rest'] -- rest' A )
  # Execute quotation "under" the top element
  # The quotation sees the stack without the top element
  # After execution, the original top element is restored
  #
  # Example:
  #   10 20 30 [ + ] dip  # Stack: 10 50
  #   # Adds 10 + 20, then puts 30 back on top
  swap call swap ;

: keep ( rest A [rest A -- rest'] -- rest' A )
  # Execute quotation while preserving the top element
  # The quotation receives a copy of the top element
  #
  # Example:
  #   5 [ dup * ] keep  # Stack: 25 5
  #   # Computes 5 * 5 = 25, keeps 5 on stack
  over [ dip ] dip ;

: 2dip ( rest A B [rest -- rest'] -- rest' A B )
  # Execute quotation "under" the top two elements
  # Like dip but preserves two stack items
  swap [ dip ] dip ;

: 2keep ( rest A [rest A A -- rest'] -- rest' A )
  # Execute quotation while preserving top element (passed twice)
  [ [ dup ] dip ] dip ;

: 3dip ( rest A B C [rest -- rest'] -- rest' A B C )
  # Execute quotation "under" the top three elements
  swap [ 2dip ] dip ;

# ============================================================================
# CLEAVE COMBINATORS (apply multiple quotations to same value)
# ============================================================================

: bi ( A [A -- B] [A -- C] -- B C )
  # Apply two quotations to the same value
  # "Bi" = binary = two quotations
  #
  # Example:
  #   5 [ dup * ] [ 2 * ] bi  # Stack: 25 10
  #   # Computes both 5² and 5*2
  [ keep ] dip call ;

: tri ( A [A -- B] [A -- C] [A -- D] -- B C D )
  # Apply three quotations to the same value
  #
  # Example:
  #   5 [ dup * ] [ 2 * ] [ 1 + ] tri  # Stack: 25 10 6
  [ [ keep ] dip keep ] dip call ;

: 2bi ( A B [A B -- C] [A B -- D] -- C D )
  # Apply two quotations to the same two values
  [ 2keep ] dip call ;

# ============================================================================
# SPREAD COMBINATORS (apply different quotations to different values)
# ============================================================================

: bi* ( A B [A -- C] [B -- D] -- C D )
  # Apply first quotation to first value, second to second value
  # "Bi-star" = spread across values
  #
  # Example:
  #   5 10 [ dup * ] [ 2 * ] bi*  # Stack: 25 20
  #   # Computes 5² and 10*2
  [ dip ] dip call ;

: tri* ( A B C [A -- D] [B -- E] [C -- F] -- D E F )
  # Apply three quotations to three values
  [ [ 2dip ] dip dip ] dip call ;

: 2bi* ( A B C D [A B -- E] [C D -- F] -- E F )
  # Apply two quotations to two pairs
  [ 2dip ] dip call ;

# ============================================================================
# APPLY COMBINATORS (quotation manipulation)
# ============================================================================

: bi@ ( A B [A -- C] -- C C )
  # Apply same quotation to two values
  # "Bi-at" = apply at two places
  #
  # Example:
  #   5 10 [ dup * ] bi@  # Stack: 25 100
  dup bi* ;

: tri@ ( A B C [A -- D] -- D D D )
  # Apply same quotation to three values
  dup dup tri* ;

# ============================================================================
# CONDITIONAL COMBINATORS
# ============================================================================

: when ( A Bool [A -- A] -- A )
  # Execute quotation only if condition is true
  # Otherwise, leave value unchanged
  #
  # Example:
  #   -5 [ 0 < ] [ 0 swap - ] when  # Stack: 5 (made positive)
  #   5  [ 0 < ] [ 0 swap - ] when  # Stack: 5 (unchanged)
  swap [ call ] [ drop ] if ;

: unless ( A Bool [A -- A] -- A )
  # Execute quotation only if condition is false
  # Opposite of when
  swap [ drop ] [ call ] if ;

: if* ( A Bool [A -- B] [A -- C] -- B|C )
  # Like if but both branches receive the value
  rot [ call ] [ swap call ] if ;

# ============================================================================
# LOOP COMBINATORS
# ============================================================================

: while ( [-- Bool] [-- ] -- )
  # Execute body while condition is true
  # Both quotations see the same stack state
  #
  # NOTE: Requires tail-call optimization for unbounded loops
  # Without TCO, this will stack overflow on long iterations
  #
  # Example:
  #   10 [ dup 0 > ] [ dup print 1 - ] while drop
  #   # Prints: 10 9 8 7 6 5 4 3 2 1
  swap [ dup call ] dip
  swap [ while ] [ drop drop ] if ;

: until ( [-- Bool] [-- ] -- )
  # Execute body until condition is true
  # Opposite of while
  # TODO: Requires concat implementation
  # [ not ] concat swap while ;
  ;  # Placeholder until concat is implemented

: times ( Int [-- ] -- )
  # Execute quotation N times
  #
  # Example:
  #   5 [ "Hello" println ] times
  #   # Prints "Hello" five times
  [ dup 0 > ]
  [ swap dup call swap 1 - ]
  while drop drop ;

# ============================================================================
# DATA FLOW COMBINATORS
# ============================================================================

: nip ( A B -- B )
  # Remove second element
  swap drop ;

: tuck ( A B -- B A B )
  # Copy top element under second
  swap over ;

: 2dup ( A B -- A B A B )
  # Duplicate top two elements
  over over ;

: 2drop ( A B -- )
  # Drop top two elements
  drop drop ;

: 2swap ( A B C D -- C D A B )
  # Swap top two pairs
  rot [ rot ] dip ;

: 2over ( A B C D -- A B C D A B )
  # Copy second pair to top
  [ over ] dip over ;

: 2nip ( A B C D -- C D )
  # Remove second pair
  2swap 2drop ;

: dupd ( A B -- A A B )
  # Duplicate second element
  [ dup ] dip ;

: swapd ( A B C -- B A C )
  # Swap second and third elements
  [ swap ] dip ;

: overd ( A B C -- A B A C )
  # Copy third element
  [ over ] dip ;

: rotd ( A B C D -- A C D B )
  # Rotate under top element
  [ rot ] dip ;

# ============================================================================
# QUOTATION COMBINATORS
# ============================================================================

: call ( [-- A] -- A )
  # Execute quotation
  # NOTE: This is built-in, documented for completeness
  call ;

# NOTE: Advanced quotation combinators (concat, curry, compose) are defined
# in stdlib/unimplemented.cem as they require compiler support not yet available

# ============================================================================
# UTILITY COMBINATORS
# ============================================================================

: identity ( A -- A )
  # Do nothing (useful for higher-order functions)
  ;

# NOTE: const and flip require closure/quotation manipulation support
# See stdlib/unimplemented.cem for their definitions

# ============================================================================
# BOOLEAN COMBINATORS
# ============================================================================

: not ( Bool -- Bool )
  # Logical negation
  true false if ;

: and ( Bool Bool -- Bool )
  # Logical AND
  # Short-circuits: doesn't evaluate second if first is false
  [ ] [ drop false ] if ;

: or ( Bool Bool -- Bool )
  # Logical OR
  # Short-circuits: doesn't evaluate second if first is true
  [ drop true ] [ ] if ;

: xor ( Bool Bool -- Bool )
  # Logical XOR (exclusive or)
  swap over or rot rot and not and ;

: both ( A [A -- Bool] [A -- Bool] -- Bool )
  # Test if value satisfies both predicates
  bi and ;

: either ( A [A -- Bool] [A -- Bool] -- Bool )
  # Test if value satisfies at least one predicate
  bi or ;

# ============================================================================
# COMPARISON COMBINATORS
# ============================================================================

# NOTE: Basic comparisons (<, >, =, etc.) are built-in primitives

: != ( A A -- Bool )
  # Not equal
  = not ;

: <= ( Int Int -- Bool )
  # Less than or equal
  2dup < rot rot = or ;

: >= ( Int Int -- Bool )
  # Greater than or equal
  2dup > rot rot = or ;

: between ( Int Int Int -- Bool )
  # Check if value is between min and max (inclusive)
  # Stack: value min max
  [ >= ] dip <= and ;

: min ( Int Int -- Int )
  # Return minimum of two values
  2dup < [ drop ] [ swap drop ] if ;

: max ( Int Int -- Int )
  # Return maximum of two values
  2dup > [ drop ] [ swap drop ] if ;

: clamp ( Int Int Int -- Int )
  # Clamp value between min and max
  # Stack: value min max
  [ max ] dip min ;

# ============================================================================
# NOTES ON IMPLEMENTATION
# ============================================================================

# All combinators in this file are fully implemented and ready to use.
#
# Advanced combinators requiring compiler support (concat, curry, compose,
# const, flip, until) have been moved to stdlib/unimplemented.cem for
# documentation purposes. They will be added when the compiler supports:
# 1. Quotation concatenation (for concat, compose, until)
# 2. Closure capture (for curry, const)
# 3. Quotation rewriting (for flip)

# ============================================================================
# EXAMPLES
# ============================================================================

# Example 1: Using bi to compute multiple properties
# : describe-number ( Int -- String String )
#   [ "Even" "Odd" if ]
#   [ "Positive" "Negative" "Zero" if if ]
#   bi ;
#
# 42 describe-number  # Stack: "Even" "Positive"

# Example 2: Using keep to preserve a value while operating on it
# : square-and-original ( Int -- Int Int )
#   [ dup * ] keep ;
#
# 5 square-and-original  # Stack: 25 5

# Example 3: Using dip to apply operation below top element
# : add-to-second ( Int Int Int -- Int Int )
#   [ + ] dip ;
#
# 10 20 30 add-to-second  # Stack: 30 30 (10 + 20, then 30)

# Example 4: Using when for conditional transformation
# : make-positive ( Int -- Int )
#   dup 0 < [ 0 swap - ] when ;
#
# -5 make-positive  # Stack: 5
# 7 make-positive   # Stack: 7

# End of core.cem