Ten Primitives (and more) achieved

This commit is contained in:
Loic Nageleisen 2014-01-27 22:49:20 +01:00
parent b6560c6484
commit cb25bf30a3
5 changed files with 232 additions and 72 deletions

13
repl.py
View file

@ -1,4 +1,5 @@
import wasp import wasp
import wasp.ast
import readline import readline
@ -35,13 +36,19 @@ if __name__ == "__main__":
continue continue
try: try:
ast = context['read'](line) ast = context['read'](wasp.ast.String(line), context)
except wasp.lib.ReadError, e: except wasp.lib.ReadError, e:
print "Parse error:", e.message print "Parse error:", e.message
continue continue
try: try:
print context['eval'](ast, context) result = context['eval'](ast, context)
except wasp.SymbolError, e: except wasp.SymbolError, e:
print "Undefined symbol:", e.message print "Eval error:", e.message
continue
try:
context['print'](result, context)
except Exception, e:
print "Print error:", e.message
continue continue

View file

@ -1,6 +1,6 @@
from __future__ import print_function from __future__ import print_function
from copy import copy
import wasp.lib as lib import wasp.lib as lib
@ -13,19 +13,43 @@ class SymbolError(Exception):
class Context(object): class Context(object):
symbols = { symbols = {
'+': lib.plus, 'nil': lib.nil,
'-': lib.minus, 'true': lib.true,
'*': lib.multiply, 'false': lib.false,
'/': lib.div,
'read': lib.read, 'read': lib.read,
'eval': lib.eval, 'eval': lib.eval,
'print': lib.print, 'print': lib.print,
'apply': lib.apply, 'apply': lib.apply,
'quote': lib.quote, 'quote': lib.quote,
'car': lib.car,
'cdr': lib.cdr,
'list': lib.list,
'cons': lib.cons,
'cond': lib.cond,
'eq': lib.eq,
'append': lib.append,
'def': lib.label,
'lambda': lib.lambda_,
'+': lib.plus,
'-': lib.minus,
'*': lib.multiply,
'/': lib.div,
} }
def __init__(self, symbols={}):
self.symbols = dict(self.symbols.items() + symbols.items())
def __getitem__(self, symbol): def __getitem__(self, symbol):
try: try:
return self.symbols[symbol] return self.symbols[symbol]
except KeyError: except KeyError:
raise SymbolError(symbol) raise SymbolError(symbol)
def __setitem__(self, symbol, value):
self.symbols[symbol] = value
def __add__(self, context):
return Context(dict(self.symbols.items() + context.symbols.items()))
def copy(self):
return self.__class__(copy(self.symbols))

View file

@ -2,36 +2,71 @@ class Node(object):
pass pass
class List(Node):
def __init__(self, car, cdr=None):
self.car = car
self.cdr = cdr
def eval(self, context):
return context['apply'](self.car, self.cdr, context)
def __repr__(self):
return "<List %r %r>" % (self.car, self.cdr)
class Atom(Node): class Atom(Node):
pass pass
class Operator(Node): class Nil(Atom):
pass def __init__(self):
self.car = self
self.cdr = self
def iter(self):
return []
def __str__(self):
return "nil"
def __repr__(self):
return "<Nil>"
class Truth(Atom):
def __init__(self, true=True):
self.true = true
def __str__(self):
return ("%s" % self.true).lower()
def __repr__(self):
return "<%s>" % self.true
class List(Node):
def __init__(self, car, cdr=Nil()):
self.car = car
self.cdr = cdr
def iter(self):
car = self.car
cdr = self.cdr
while not type(cdr) is Nil:
yield car
car = cdr.car
cdr = cdr.cdr
else:
yield car
def __str__(self):
return "(%s)" % (' '.join(str(i) for i in self.iter()))
def __repr__(self):
return "<List %r %r>" % (self.car, self.cdr)
class Number(Atom): class Number(Atom):
def __init__(self, value): def __init__(self, value):
self.value = value self.value = value
def eval(self, context): def __str__(self):
return self.value return "%s" % self.value
def __repr__(self): def __repr__(self):
return "<%s %s>" % (type(self).__name__, self.value) return "<%s %s>" % (type(self).__name__, self.value)
def __eq__(self, other):
return self.value == other.value
class Integer(Number): class Integer(Number):
pass pass
@ -42,37 +77,47 @@ class Float(Number):
class Symbol(Atom): class Symbol(Atom):
def __init__(self, value): def __init__(self, name):
self.value = value self.name = name
def eval(self, context): def __str__(self):
return context[self.value] return "%s" % self.name
def __repr__(self): def __repr__(self):
return "<Symbol %s>" % self.value return "<Symbol %s>" % self.name
class String(Atom): class String(Atom):
def __init__(self, value): def __init__(self, value):
self.value = value self.value = value
def eval(self, context): def __str__(self):
return self.value return '"%s"' % self.value
def __repr__(self): def __repr__(self):
return "<String %s>" % self.value return "<String %s>" % self.value
class Quote(Node): class Quote(List):
def __init__(self, sexpr): def __init__(self, sexpr):
self.sexpr = sexpr self.car = Symbol('quote')
self.cdr = sexpr
self.sexpr = self.cdr
def eval(self, context): def __str__(self):
return context['quote'](self.sexpr) return "'%s" % self.sexpr
def __repr__(self): def __repr__(self):
return "<Quote %r>" % self.sexpr return "<Quote %r>" % self.sexpr
class Lambda(Node): class Lambda(Node):
pass def __init__(self, args, body):
self.args = args
self.body = body
def __str__(self):
return "lambda %s %s" % (self.args, self.body)
def __repr__(self):
return "<Lambda %r %r>" % (self.args, self.body)

View file

@ -1,64 +1,156 @@
from __future__ import print_function from __future__ import print_function, division
import wasp.parser import wasp.parser as parser
from wasp.ast import List, Atom, Lambda, Symbol, Nil, Truth
import wasp
py_print = print py_print = print
py_eval = eval py_eval = eval
py_list = list
class ReadError(Exception): class ReadError(Exception):
pass pass
def plus(a, b): nil = Nil()
return a + b true = Truth()
false = Truth(False)
def minus(a, b): def atom(expr):
return a - b return isinstance(expr, Atom)
def multiply(a, b): def car(expr, context):
return a * b return expr.car.car
def div(a, b): def cdr(expr, context):
return a / b return expr.car.cdr
def read(string): def label(expr, context):
symbol = expr.car
value = expr.cdr.car
context[symbol.name] = value
return value
def read(string, context):
try: try:
ptree = wasp.parser.parse(string) ptree = parser.parse(string.value)
except ValueError, e: except ValueError, e:
raise ReadError(e.message) raise ReadError(e.message)
py_print(" ^ %s" % ptree) #py_print(" ^ %s" % ptree)
try: try:
ast = ptree.ast() ast = ptree.ast()
except ValueError, e: except ValueError, e:
raise ReadError(e.message) raise ReadError(e.message)
py_print("%r" % ast) #py_print(" ‡ %r" % ast)
return ast return ast
def eval(ast, context): def quote(expr, context):
# eval value unless list return expr
# eval args unless lazy
# eval call
return ast.eval(context)
def apply(a, b, context): def eval(expr, context):
# move to eval if atom(expr):
args = [arg.eval(context) for arg in b] if type(expr) is Symbol:
return a.eval(context)(*args) return context[expr.name]
else:
return expr
# else it's a list
symbol = expr.car
args = expr.cdr
x_args = Nil()
if symbol.name in ['quote', 'lambda', 'cond']:
x_args = args
elif symbol.name in ['def']:
for arg in reversed(py_list(args.cdr.iter())):
x_args = List(eval(arg, context), x_args)
x_args = List(args.car, x_args)
else:
for arg in reversed(py_list(args.iter())):
x_args = List(eval(arg, context), x_args)
expr = List(symbol, x_args)
return apply(expr, context)
def quote(a): def print(string, context):
return a py_print(str(string))
def print(string): def apply(expr, context):
py_print(string) symbol = expr.car
args = expr.cdr
l = eval(symbol, context)
if type(l).__name__ == 'function':
return l(args, context)
else:
symbol_names = (symbol.name for symbol in l.args.iter())
args_dict = dict(zip(symbol_names, args.iter()))
arg_context = wasp.Context(args_dict)
context = context + arg_context
return eval(l.body, context)
def lambda_(expr, context):
args = expr.car
body = expr.cdr.car
return Lambda(args, body)
def list(expr, context):
return expr
def cons(expr, context):
return List(expr.car, expr.cdr.car)
def cond(expr, context):
for clause in expr.iter():
condition = eval(clause.car, context)
if condition != false and type(condition) != Nil:
return eval(clause.cdr.car, context)
return Nil()
def eq(expr, context):
if expr.car == expr.cdr.car:
return true
else:
return false
def append(expr, context):
result = Nil()
for item in reversed(py_list(expr.cdr.car.iter())):
result = List(item, result)
for item in reversed(py_list(expr.car.iter())):
result = List(item, result)
return result
def plus(args, context):
return args.car.value + args.cdr.car.value
def minus(args, context):
return args.car.value - args.cdr.car.value
def multiply(args, context):
return args.car.value * args.cdr.car.value
def div(args, context):
return args.car.value / args.cdr.car.value

View file

@ -29,19 +29,11 @@ class Pair(BaseBox):
y = self.y y = self.y
return "(%s . %s)" % (self.x, y) return "(%s . %s)" % (self.x, y)
def _r_cdr(self, cdr):
if self.y is None:
return (self.x.ast(), )
else:
return cdr + (self.x.ast(), ) + self.y._r_cdr(cdr)
def ast(self): def ast(self):
car = self.x.ast() car = self.x.ast()
if self.y is None: if self.y is None:
cdr = None cdr = ast.Nil()
elif type(self.y) is Pair:
cdr = list(self.y._r_cdr(()))
else: else:
cdr = self.y.ast() cdr = self.y.ast()