docs

How it works

Runtime and Types

Every value in a running kemlang-py program is one of five Python types. This page covers how those types behave, how coercion works, what is truthy, and the full lifecycle of a program from file read to process exit.

KemValue - the runtime type

kemlang/types.py
KemValue = int | float | str | bool | None

# There are no wrapper classes. Python's built-in types ARE the runtime types.
# int   -> 42, 0, -7
# float -> 3.14, 0.5
# str   -> "hello", result of bapu tame bolo
# bool  -> bhai chhe (True), bhai nathi (False)
# None  -> result of failed input coercion
typekemlang-py literalnotes
int42, 0, -7arbitrary precision Python int
float3.14, 0.5, -1.0IEEE 754 double, same as Python float
str"hello"UTF-8, double-quoted, single-line only
boolbhai chhe / bhai nathiPython True/False (subclass of int)
None(no literal)failed input coercion; never user-writable

Dynamic typing

Variables have no declared type. They hold whatever value was assigned to them, and that type can change on reassignment. The interpreter discovers the type of a value at runtime using Python's isinstance().

valid in kemlang-py
kem bhai
  aa x che 42          # x is int
  x che "hello"        # x is now str - perfectly legal
  x che bhai chhe      # x is now bool
aavjo bhai

Truthiness

Conditions accept any KemValue. The interpreter applies the same rules as Python's bool():

valuetruthy?notes
bhai chheyescanonical truthy value
bhai nathinocanonical falsy value
any non-zero intyes0 is falsy; 1, -5, 42 are truthy
0nozero integer
any non-zero floatyes0.0 is falsy
0.0nozero float
non-empty stringyes"hello", "0", " " are all truthy
""noempty string
Nonenoalways falsy

Arithmetic and type promotion

arithmetic type rules

  int   op int    ->  int      5 + 3 = 8
  int   op float  ->  float    5 + 3.0 = 8.0
  float op float  ->  float    1.5 * 2.0 = 3.0

  Division:  7 / 2  uses Python /  ->  3.5  (float, not integer 3)
  Modulo:    7 % 3  ->  1
  Negation:  -5     ->  int
             -3.14  ->  float

The + operator

If either operand is a string, both are stringified and concatenated. Otherwise, numeric addition is performed.

+ operator coercion examples

  10 + 5          ->  15          numeric addition
  10 + 3.14       ->  13.14       int + float promotion
  "score: " + 10  ->  "score: 10" str on left -> stringify right
  10 + " points"  ->  "10 points" str on right -> stringify left
  "a" + "b"       ->  "ab"        both str -> concatenate

  stringify() rules:
    int:   str(n)           -> "42"
    float: str(f)           -> "3.14"
    bool:  True  -> "bhai chhe"   False -> "bhai nathi"
    None:  "none"
kemlang/interpreter.py - + operator implementation
if op == TokenType.PLUS:
    if isinstance(left, str) or isinstance(right, str):
        return self.stringify(left) + self.stringify(right)
    return left + right

Comparison operators

comparison examples

  10 == 10        ->  bhai chhe    (True)
  10 == 10.0      ->  bhai chhe    (True  - int/float equality in Python)
  10 == "10"      ->  bhai nathi   (False - different types)
  "a" < "b"       ->  bhai chhe    (True  - lexicographic)
  bhai chhe == 1  ->  bhai chhe    (True  - bool is int subclass, True == 1)
  bhai nathi == 0 ->  bhai chhe    (True  - False == 0 in Python)

Full execution lifecycle

from kem run to process exit

Error propagation

error typewhen raised
LexerErrorBad character in source. Raised immediately - no parsing or execution.
ParseErrorGrammar violation in token stream. Raised immediately - no execution.
RuntimeErrorBad operation during execution. Caught at interpret() top level, prints message, returns exit code 1.