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
|
||||||
|
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
|
||||||
|
|
|
||||||
|
|
@ -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))
|
||||||
|
|
|
||||||
101
wasp/ast.py
101
wasp/ast.py
|
|
@ -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)
|
||||||
|
|
|
||||||
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_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
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue