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.ast
import readline
@ -35,13 +36,19 @@ if __name__ == "__main__":
continue
try:
ast = context['read'](line)
ast = context['read'](wasp.ast.String(line), context)
except wasp.lib.ReadError, e:
print "Parse error:", e.message
continue
try:
print context['eval'](ast, context)
result = context['eval'](ast, context)
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

View file

@ -1,6 +1,6 @@
from __future__ import print_function
from copy import copy
import wasp.lib as lib
@ -13,19 +13,43 @@ class SymbolError(Exception):
class Context(object):
symbols = {
'+': lib.plus,
'-': lib.minus,
'*': lib.multiply,
'/': lib.div,
'nil': lib.nil,
'true': lib.true,
'false': lib.false,
'read': lib.read,
'eval': lib.eval,
'print': lib.print,
'apply': lib.apply,
'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):
try:
return self.symbols[symbol]
except KeyError:
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
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):
pass
class Operator(Node):
pass
class Nil(Atom):
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):
def __init__(self, value):
self.value = value
def eval(self, context):
return self.value
def __str__(self):
return "%s" % self.value
def __repr__(self):
return "<%s %s>" % (type(self).__name__, self.value)
def __eq__(self, other):
return self.value == other.value
class Integer(Number):
pass
@ -42,37 +77,47 @@ class Float(Number):
class Symbol(Atom):
def __init__(self, value):
self.value = value
def __init__(self, name):
self.name = name
def eval(self, context):
return context[self.value]
def __str__(self):
return "%s" % self.name
def __repr__(self):
return "<Symbol %s>" % self.value
return "<Symbol %s>" % self.name
class String(Atom):
def __init__(self, value):
self.value = value
def eval(self, context):
return self.value
def __str__(self):
return '"%s"' % self.value
def __repr__(self):
return "<String %s>" % self.value
class Quote(Node):
class Quote(List):
def __init__(self, sexpr):
self.sexpr = sexpr
self.car = Symbol('quote')
self.cdr = sexpr
self.sexpr = self.cdr
def eval(self, context):
return context['quote'](self.sexpr)
def __str__(self):
return "'%s" % self.sexpr
def __repr__(self):
return "<Quote %r>" % self.sexpr
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_eval = eval
py_list = list
class ReadError(Exception):
pass
def plus(a, b):
return a + b
nil = Nil()
true = Truth()
false = Truth(False)
def minus(a, b):
return a - b
def atom(expr):
return isinstance(expr, Atom)
def multiply(a, b):
return a * b
def car(expr, context):
return expr.car.car
def div(a, b):
return a / b
def cdr(expr, context):
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:
ptree = wasp.parser.parse(string)
ptree = parser.parse(string.value)
except ValueError, e:
raise ReadError(e.message)
py_print(" ^ %s" % ptree)
#py_print(" ^ %s" % ptree)
try:
ast = ptree.ast()
except ValueError, e:
raise ReadError(e.message)
py_print("%r" % ast)
#py_print(" ‡ %r" % ast)
return ast
def eval(ast, context):
# eval value unless list
# eval args unless lazy
# eval call
return ast.eval(context)
def quote(expr, context):
return expr
def apply(a, b, context):
# move to eval
args = [arg.eval(context) for arg in b]
return a.eval(context)(*args)
def eval(expr, context):
if atom(expr):
if type(expr) is Symbol:
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):
return a
def print(string, context):
py_print(str(string))
def print(string):
py_print(string)
def apply(expr, context):
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
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):
car = self.x.ast()
if self.y is None:
cdr = None
elif type(self.y) is Pair:
cdr = list(self.y._r_cdr(()))
cdr = ast.Nil()
else:
cdr = self.y.ast()