!/usr/bin/env python3
"""
LAW-T Interpreter v0.1 - Time-Native Programming
Author: Peace Thabiwa, SageWorks AI
License: MIT
Usage:
python lawt.py run examples/hello.law
python lawt.py trace examples/counter.law
python lawt.py graph examples/calc.law
"""
import sys
import time
import hashlib
import json
import re
from dataclasses import dataclass, field
from typing import Any, Dict, List, Optional, Union
from collections import defaultdict
from pathlib import Path
============================================================================
TLB (Time-Labeled Binary) Implementation
============================================================================
@dataclass
class TLB:
"""Time-Labeled Binary - Unique identifier for every code element"""
epoch: int # nanoseconds since epoch
lane: int # developer/machine ID
seq: int # sequence number
rand: int # random entropy
proof: str # hash proof
def __str__(self):
return f"@t[{self.epoch};lane={self.lane:08x};seq={self.seq};r={self.rand:08x};p={self.proof[:8]}]"
@staticmethod
def mint(content: str, lane: int = 0xA1B2C3D4, seq: int = 0) -> 'TLB':
"""Generate a new TLB for given content"""
epoch = time.time_ns()
rand = int.from_bytes(hashlib.sha256(f"{epoch}{content}".encode()).digest()[:4], 'big')
# Generate proof hash
proof_input = f"{content}{epoch}{lane}{seq}{rand}".encode()
proof = hashlib.sha256(proof_input).hexdigest()
return TLB(epoch, lane, seq, rand, proof)
============================================================================
AST Nodes
============================================================================
@dataclass
class Node:
"""Base AST node with TLB"""
tlb: TLB
@dataclass
class Literal(Node):
value: Union[int, float, str, bool]
@dataclass
class Variable(Node):
name: str
@dataclass
class BinOp(Node):
op: str
left: Node
right: Node
@dataclass
class Let(Node):
name: str
value: Node
@dataclass
class Function(Node):
name: str
params: List[str]
body: List[Node]
effects: List[str]
@dataclass
class Call(Node):
name: str
args: List[Node]
@dataclass
class If(Node):
condition: Node
then_branch: List[Node]
else_branch: Optional[List[Node]]
@dataclass
class Loop(Node):
var: str
iterable: Node
body: List[Node]
@dataclass
class Return(Node):
value: Node
@dataclass
class Print(Node):
value: Node
============================================================================
Parser
============================================================================
class Parser:
def init(self, source: str):
self.source = source
self.lines = source.strip().split('\n')
self.pos = 0
self.seq_counter = 0
self.lane = int.from_bytes(hashlib.sha256(b"default_lane").digest()[:4], 'big')
def mint_tlb(self, content: str) -> TLB:
"""Mint a new TLB with auto-incrementing sequence"""
tlb = TLB.mint(content, self.lane, self.seq_counter)
self.seq_counter += 1
return tlb
def parse(self) -> List[Node]:
"""Parse entire program"""
nodes = []
while self.pos < len(self.lines):
line = self.lines[self.pos].strip()
if line and not line.startswith('//'):
node = self.parse_statement(line)
if node:
nodes.append(node)
self.pos += 1
return nodes
def parse_statement(self, line: str) -> Optional[Node]:
"""Parse a single statement"""
# Comments
if line.startswith('//'):
return None
# Let binding
if line.startswith('let '):
return self.parse_let(line)
# Function definition
if line.startswith('fn '):
return self.parse_function(line)
# If statement
if line.startswith('if '):
return self.parse_if(line)
# For loop
if line.startswith('for '):
return self.parse_loop(line)
# Return
if line.startswith('return '):
value = self.parse_expression(line[7:])
return Return(self.mint_tlb(line), value)
# Print
if line.startswith('print '):
value = self.parse_expression(line[6:])
return Print(self.mint_tlb(line), value)
# Expression or call
return self.parse_expression(line)
def parse_let(self, line: str) -> Let:
"""Parse: let x = value"""
match = re.match(r'let\s+(\w+)\s*=\s*(.+)', line)
if match:
name = match.group(1)
value_str = match.group(2)
value = self.parse_expression(value_str)
return Let(self.mint_tlb(line), name, value)
raise SyntaxError(f"Invalid let: {line}")
def parse_function(self, line: str) -> Function:
"""Parse: fn name(param1, param2) !{effects} { ... }"""
# Simple version - collect body until we see }
match = re.match(r'fn\s+(\w+)\s*\((.*?)\)\s*(?:!\{(.*?)\})?\s*\{', line)
if not match:
raise SyntaxError(f"Invalid function: {line}")
name = match.group(1)
params_str = match.group(2)
effects_str = match.group(3) or ""
params = [p.strip() for p in params_str.split(',')] if params_str else []
effects = [e.strip() for e in effects_str.split(',')] if effects_str else []
# Parse body
body = []
self.pos += 1
while self.pos < len(self.lines):
body_line = self.lines[self.pos].strip()
if body_line == '}':
break
if body_line and not body_line.startswith('//'):
stmt = self.parse_statement(body_line)
if stmt:
body.append(stmt)
self.pos += 1
return Function(self.mint_tlb(line), name, params, body, effects)
def parse_if(self, line: str) -> If:
"""Parse: if condition { ... } else { ... }"""
match = re.match(r'if\s+(.+?)\s*\{', line)
if not match:
raise SyntaxError(f"Invalid if: {line}")
condition = self.parse_expression(match.group(1))
# Parse then branch
then_branch = []
self.pos += 1
while self.pos < len(self.lines):
then_line = self.lines[self.pos].strip()
if then_line == '}' or then_line.startswith('} else'):
break
if then_line and not then_line.startswith('//'):
stmt = self.parse_statement(then_line)
if stmt:
then_branch.append(stmt)
self.pos += 1
# Parse else branch if present
else_branch = None
if self.pos < len(self.lines) and 'else' in self.lines[self.pos]:
else_branch = []
self.pos += 1
while self.pos < len(self.lines):
else_line = self.lines[self.pos].strip()
if else_line == '}':
break
if else_line and not else_line.startswith('//'):
stmt = self.parse_statement(else_line)
if stmt:
else_branch.append(stmt)
self.pos += 1
return If(self.mint_tlb(line), condition, then_branch, else_branch)
def parse_loop(self, line: str) -> Loop:
"""Parse: for x in iterable { ... }"""
match = re.match(r'for\s+(\w+)\s+in\s+(.+?)\s*\{', line)
if not match:
raise SyntaxError(f"Invalid loop: {line}")
var = match.group(1)
iterable = self.parse_expression(match.group(2))
# Parse body
body = []
self.pos += 1
while self.pos < len(self.lines):
body_line = self.lines[self.pos].strip()
if body_line == '}':
break
if body_line and not body_line.startswith('//'):
stmt = self.parse_statement(body_line)
if stmt:
body.append(stmt)
self.pos += 1
return Loop(self.mint_tlb(line), var, iterable, body)
def parse_expression(self, expr: str) -> Node:
"""Parse an expression"""
expr = expr.strip()
# Literals
if expr.isdigit():
return Literal(self.mint_tlb(expr), int(expr))
if expr.replace('.', '').isdigit() and expr.count('.') == 1:
return Literal(self.mint_tlb(expr), float(expr))
if expr.startswith('"') and expr.endswith('"'):
return Literal(self.mint_tlb(expr), expr[1:-1])
if expr in ['true', 'false']:
return Literal(self.mint_tlb(expr), expr == 'true')
# Binary operations
for op in ['+', '-', '*', '/', '==', '!=', '<', '>', '<=', '>=']:
if op in expr:
parts = expr.split(op, 1)
if len(parts) == 2:
left = self.parse_expression(parts[0])
right = self.parse_expression(parts[1])
return BinOp(self.mint_tlb(expr), op, left, right)
# Function call
if '(' in expr and expr.endswith(')'):
name = expr[:expr.index('(')]
args_str = expr[expr.index('(')+1:-1]
args = [self.parse_expression(a.strip()) for a in args_str.split(',')] if args_str else []
return Call(self.mint_tlb(expr), name, args)
# Range for loops
if expr.startswith('range('):
return self.parse_expression(expr)
# Variable
return Variable(self.mint_tlb(expr), expr)
============================================================================
Interpreter
============================================================================
class Interpreter:
def init(self):
self.globals = {}
self.locals_stack = [{}]
self.trace = []
def eval(self, nodes: List[Node]) -> Any:
"""Evaluate a list of nodes"""
result = None
for node in nodes:
result = self.eval_node(node)
if isinstance(node, Return):
return result
return result
def eval_node(self, node: Node) -> Any:
"""Evaluate a single node"""
self.trace.append((node.tlb, type(node).__name__))
if isinstance(node, Literal):
return node.value
elif isinstance(node, Variable):
# Check locals then globals
for scope in reversed(self.locals_stack):
if node.name in scope:
return scope[node.name]
if node.name in self.globals:
return self.globals[node.name]
raise NameError(f"Variable '{node.name}' not found")
elif isinstance(node, BinOp):
left = self.eval_node(node.left)
right = self.eval_node(node.right)
ops = {
'+': lambda a, b: a + b,
'-': lambda a, b: a - b,
'*': lambda a, b: a * b,
'/': lambda a, b: a / b,
'==': lambda a, b: a == b,
'!=': lambda a, b: a != b,
'<': lambda a, b: a < b,
'>': lambda a, b: a > b,
'<=': lambda a, b: a <= b,
'>=': lambda a, b: a >= b,
}
return ops[node.op](left, right)
elif isinstance(node, Let):
value = self.eval_node(node.value)
self.locals_stack[-1][node.name] = value
return value
elif isinstance(node, Function):
self.globals[node.name] = node
return None
elif isinstance(node, Call):
if node.name == 'range':
# Built-in range
if len(node.args) == 1:
end = self.eval_node(node.args[0])
return list(range(end))
elif len(node.args) == 2:
start = self.eval_node(node.args[0])
end = self.eval_node(node.args[1])
return list(range(start, end))
# User function
func = self.globals.get(node.name)
if not isinstance(func, Function):
raise NameError(f"Function '{node.name}' not found")
# Evaluate arguments
arg_values = [self.eval_node(arg) for arg in node.args]
# Create new scope
new_scope = dict(zip(func.params, arg_values))
self.locals_stack.append(new_scope)
# Execute function body
result = self.eval(func.body)
# Pop scope
self.locals_stack.pop()
return result
elif isinstance(node, If):
condition = self.eval_node(node.condition)
if condition:
return self.eval(node.then_branch)
elif node.else_branch:
return self.eval(node.else_branch)
return None
elif isinstance(node, Loop):
iterable = self.eval_node(node.iterable)
for item in iterable:
self.locals_stack[-1][node.var] = item
result = self.eval(node.body)
if isinstance(node.body[-1] if node.body else None, Return):
return result
return None
elif isinstance(node, Return):
return self.eval_node(node.value)
elif isinstance(node, Print):
value = self.eval_node(node.value)
print(value)
return value
else:
raise NotImplementedError(f"Node type {type(node)} not implemented")
============================================================================
CLI
============================================================================
def run_file(filepath: str, trace_mode: bool = False):
"""Run a LAW-T program file"""
source = Path(filepath).read_text()
print(f"๐ LAW-T Interpreter v0.1")
print(f"๐ Running: {filepath}")
print(f"{'='*60}\n")
# Parse
parser = Parser(source)
ast = parser.parse()
# Execute
interpreter = Interpreter()
result = interpreter.eval(ast)
if trace_mode:
print(f"\n{'='*60}")
print(f"๐ Execution Trace ({len(interpreter.trace)} operations):")
for tlb, node_type in interpreter.trace:
print(f" {node_type:<15} {tlb}")
if result is not None:
print(f"\n{'='*60}")
print(f"โ
Result: {result}")
def generate_graph(filepath: str):
"""Generate execution graph"""
source = Path(filepath).read_text()
parser = Parser(source)
ast = parser.parse()
print("๐ TLB Execution Graph:")
print(f"{'='*60}\n")
for i, node in enumerate(ast):
indent = " " * 0
print(f"{indent}{i}: {type(node).__name__} {node.tlb}")
if hasattr(node, 'body'):
for j, child in enumerate(node.body):
print(f"{indent} {i}.{j}: {type(child).__name__} {child.tlb}")
def main():
if len(sys.argv) < 2:
print("LAW-T Interpreter v0.1 - Time-Native Programming")
print("\nUsage:")
print(" python lawt.py run # Run a program")
print(" python lawt.py trace # Run with TLB trace")
print(" python lawt.py graph # Show TLB graph")
print("\nExamples:")
print(" python lawt.py run examples/hello.law")
print(" python lawt.py trace examples/counter.law")
sys.exit(1)
command = sys.argv[1]
if command == 'run' and len(sys.argv) >= 3:
run_file(sys.argv[2])
elif command == 'trace' and len(sys.argv) >= 3:
run_file(sys.argv[2], trace_mode=True)
elif command == 'graph' and len(sys.argv) >= 3:
generate_graph(sys.argv[2])
else:
print(f"Unknown command: {command}")
sys.exit(1)
if name == 'main':
main()
Top comments (0)