mirror of
https://github.com/lloeki/wasp.git
synced 2025-12-06 02:34:39 +01:00
Ten Primitives (and more) achieved
This commit is contained in:
parent
b6560c6484
commit
cb25bf30a3
5 changed files with 232 additions and 72 deletions
13
repl.py
13
repl.py
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
|
|
|||
101
wasp/ast.py
101
wasp/ast.py
|
|
@ -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)
|
||||
|
|
|
|||
146
wasp/lib.py
146
wasp/lib.py
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue