Skip to content

Instantly share code, notes, and snippets.

@jdp
Created December 7, 2010 04:59
Show Gist options
  • Save jdp/731475 to your computer and use it in GitHub Desktop.
Save jdp/731475 to your computer and use it in GitHub Desktop.

Revisions

  1. jdp renamed this gist Dec 8, 2010. 1 changed file with 0 additions and 0 deletions.
    File renamed without changes.
  2. jdp revised this gist Dec 8, 2010. 1 changed file with 20 additions and 8 deletions.
    28 changes: 20 additions & 8 deletions dope.py
    Original file line number Diff line number Diff line change
    @@ -7,6 +7,7 @@
    class Runtime:
    def __init__(self, env={}, stack=[]):
    self.env = {
    # Primitive words, not an impressive base but it works
    '.': lambda s,r: sys.stdout.write(repr(s.pop()) + "\n"),
    '+': lambda s,r: self._math(s, operator.add),
    '-': lambda s,r: self._math(s, operator.sub),
    @@ -29,7 +30,7 @@ def __init__(self, env={}, stack=[]):
    '>r': lambda s,r: s.append(r.pop()),
    '?': self._which,
    'curry': self._curry,
    # to be moved to prelude
    # Non-primitive words -- in essence, the prelude
    'dip': ['swap', 'r>', 'call', '>r'],
    'if': ['?', 'call'],
    'when': ['swap', ['call'], ['drop'], 'if'],
    @@ -38,8 +39,8 @@ def __init__(self, env={}, stack=[]):
    }
    self.env.update(env)
    self.stack = stack
    self.frames = []
    self.retain = []
    self.frames = [] # Fudge of Factor's callstack
    self.retain = [] # The retain stack, for >r and r>

    def _swap(self, stack, retain):
    stack[-1], stack[-2] = stack[-2], stack[-1]
    @@ -62,11 +63,6 @@ def _call(self, stack, retain):
    self.frames.append((self.nodes, self.ptr + 1))
    self.ptr, self.nodes = -1, self.stack.pop()

    def _define(self, stack, retain):
    name = stack.pop()
    body = stack.pop()
    self.env[name] = body

    def _math(self, stack, func):
    rhs = stack.pop()
    lhs = stack.pop()
    @@ -78,19 +74,32 @@ def evaluate(self, nodes):
    while True:
    try:
    node = self.nodes[self.ptr]
    # Strings are words, so a lookup is attempted.
    if isinstance(node, str):
    # Check if the word is defined in the environment.
    if self.env.has_key(node):
    defn = self.env[node]
    # Python lists in the environment are quotations.
    # They are from the prelude, or they are user-defined words.
    if isinstance(defn, list):
    # A call frame is only saved if the word being called
    # is not the last word in the quotation.
    # Tail-call optimization achieved. :)
    if self.ptr < len(self.nodes) - 1:
    self.frames.append((self.nodes, self.ptr + 1))
    self.ptr, self.nodes = -1, defn
    else:
    defn(self.stack, self.retain)
    # To keep with Factor syntax, the : word-name definition... ;
    # design choice was made. It would be entirely possible to
    # have definitions be postfix as well, and probably more
    # consistent with the implementation.
    elif ':' == node:
    name = self.nodes[self.ptr + 1]
    body = []
    self.ptr += 2
    # Build a quotation until ; word is found, and add it to
    # the environment.
    while self.nodes[self.ptr] != ';':
    body.append(self.nodes[self.ptr])
    self.ptr += 1
    @@ -100,9 +109,12 @@ def evaluate(self, nodes):
    else:
    self.stack.append(node)
    self.ptr += 1
    # End of quotation reached, so pop off the call frame and
    # start from there.
    except IndexError:
    try:
    (self.nodes, self.ptr) = self.frames.pop()
    # No more call frames. Program is terminated.
    except IndexError:
    return self.stack
    return self.stack
  3. jdp revised this gist Dec 7, 2010. 1 changed file with 4 additions and 1 deletion.
    5 changes: 4 additions & 1 deletion dope.py
    Original file line number Diff line number Diff line change
    @@ -22,7 +22,7 @@ def __init__(self, env={}, stack=[]):
    'dup': lambda s,r: s.append(s[-1]),
    'swap': self._swap,
    'over': lambda s,r: s.append(s[-2]),
    'clear': lambda s,r: s = [],
    'clear': self._clear,
    'quote': lambda s,r: s.append(list(s.pop())),
    'call': self._call,
    'r>': lambda s,r: r.append(s.pop()),
    @@ -44,6 +44,9 @@ def __init__(self, env={}, stack=[]):
    def _swap(self, stack, retain):
    stack[-1], stack[-2] = stack[-2], stack[-1]

    def _clear(self, stack, retain):
    del stack[:]

    def _which(self, stack, retain):
    falseq = stack.pop()
    trueq = stack.pop()
  4. jdp revised this gist Dec 7, 2010. 1 changed file with 92 additions and 71 deletions.
    163 changes: 92 additions & 71 deletions dope.py
    Original file line number Diff line number Diff line change
    @@ -4,58 +4,105 @@
    import types
    import operator

    def _swap(stack, retain):
    stack[-1], stack[-2] = stack[-2], stack[-1]
    class Runtime:
    def __init__(self, env={}, stack=[]):
    self.env = {
    '.': lambda s,r: sys.stdout.write(repr(s.pop()) + "\n"),
    '+': lambda s,r: self._math(s, operator.add),
    '-': lambda s,r: self._math(s, operator.sub),
    '*': lambda s,r: self._math(s, operator.mul),
    '/': lambda s,r: self._math(s, operator.div),
    'mod': lambda s,r: self._math(s, operator.mod),
    '>': lambda s,r: self._math(s, operator.gt),
    '<': lambda s,r: self._math(s, operator.lt),
    '=': lambda s,r: self._math(s, operator.eq),
    'f': lambda s,r: s.append(False),
    'not': lambda s,r: s.append(not s.pop()),
    'drop': lambda s,r: s.pop(),
    'dup': lambda s,r: s.append(s[-1]),
    'swap': self._swap,
    'over': lambda s,r: s.append(s[-2]),
    'clear': lambda s,r: s = [],
    'quote': lambda s,r: s.append(list(s.pop())),
    'call': self._call,
    'r>': lambda s,r: r.append(s.pop()),
    '>r': lambda s,r: s.append(r.pop()),
    '?': self._which,
    'curry': self._curry,
    # to be moved to prelude
    'dip': ['swap', 'r>', 'call', '>r'],
    'if': ['?', 'call'],
    'when': ['swap', ['call'], ['drop'], 'if'],
    'keep': ['over', ['call'], 'dip'],
    'loop': [['call'], 'keep', ['loop'], 'curry', 'when']
    }
    self.env.update(env)
    self.stack = stack
    self.frames = []
    self.retain = []

    def _which(stack, retain):
    falseq = stack.pop()
    trueq = stack.pop()
    stack.append(trueq if stack.pop() else falseq)
    def _swap(self, stack, retain):
    stack[-1], stack[-2] = stack[-2], stack[-1]

    def _curry(stack, retain):
    quot = stack.pop()[:]
    quot.insert(0, stack.pop())
    stack.append(quot)
    def _which(self, stack, retain):
    falseq = stack.pop()
    trueq = stack.pop()
    stack.append(trueq if stack.pop() else falseq)

    def _math(stack, func):
    rhs = stack.pop()
    lhs = stack.pop()
    stack.append(func(lhs, rhs))
    def _curry(self, stack, retain):
    quot = stack.pop()[:]
    quot.insert(0, stack.pop())
    stack.append(quot)

    def evaluate(nodes, stack=[], env={}):
    retain = []
    i = 0
    frames = []
    while True:
    try:
    node = nodes[i]
    if isinstance(node, str):
    if node[0] == ':':
    stack.append(node[1:])
    elif node == 'call':
    if i < len(nodes) - 1:
    frames.append((nodes, i+1))
    i, nodes = -1, stack.pop()
    else:
    if env.has_key(node):
    defn = env[node]
    def _call(self, stack, retain):
    if self.ptr < len(self.nodes) - 1:
    self.frames.append((self.nodes, self.ptr + 1))
    self.ptr, self.nodes = -1, self.stack.pop()

    def _define(self, stack, retain):
    name = stack.pop()
    body = stack.pop()
    self.env[name] = body

    def _math(self, stack, func):
    rhs = stack.pop()
    lhs = stack.pop()
    stack.append(func(lhs, rhs))

    def evaluate(self, nodes):
    self.nodes = nodes
    self.retain, self.frames, self.ptr = [], [], 0
    while True:
    try:
    node = self.nodes[self.ptr]
    if isinstance(node, str):
    if self.env.has_key(node):
    defn = self.env[node]
    if isinstance(defn, list):
    if i < len(nodes) - 1:
    frames.append((nodes, i+1))
    i, nodes = -1, defn
    if self.ptr < len(self.nodes) - 1:
    self.frames.append((self.nodes, self.ptr + 1))
    self.ptr, self.nodes = -1, defn
    else:
    defn(stack, retain)
    defn(self.stack, self.retain)
    elif ':' == node:
    name = self.nodes[self.ptr + 1]
    body = []
    self.ptr += 2
    while self.nodes[self.ptr] != ';':
    body.append(self.nodes[self.ptr])
    self.ptr += 1
    self.env[name] = body
    else:
    raise NameError, "word %s not defined" % node
    else:
    stack.append(node)
    i += 1
    except IndexError:
    try:
    (nodes, i) = frames.pop()
    else:
    self.stack.append(node)
    self.ptr += 1
    except IndexError:
    return stack
    return stack
    try:
    (self.nodes, self.ptr) = self.frames.pop()
    except IndexError:
    return self.stack
    return self.stack

    def read(s):
    return parse(tokenize(s))
    @@ -86,35 +133,9 @@ def atom(token):
    return str(token)

    def repl():
    runtime = Runtime()
    while True:
    result = evaluate(read(raw_input("> ")), [], {
    '.': lambda s,r: sys.stdout.write(repr(s.pop()) + "\n"),
    '+': lambda s,r: _math(s, operator.add),
    '-': lambda s,r: _math(s, operator.sub),
    '*': lambda s,r: _math(s, operator.mul),
    '/': lambda s,r: _math(s, operator.div),
    'mod': lambda s,r: _math(s, operator.mod),
    '>': lambda s,r: _math(s, operator.gt),
    '<': lambda s,r: _math(s, operator.lt),
    '=': lambda s,r: _math(s, operator.eq),
    'f': lambda s,r: s.append(False),
    'not': lambda s,r: s.append(not s.pop()),
    'drop': lambda s,r: s.pop(),
    'dup': lambda s,r: s.append(s[-1]),
    'swap': _swap,
    'over': lambda s,r: s.append(s[-2]),
    'quote': lambda s,r: s.append(list(s.pop())),
    'r>': lambda s,r: r.append(s.pop()),
    '>r': lambda s,r: s.append(r.pop()),
    '?': _which,
    'curry': _curry,
    # to be moved to prelude
    'dip': ['swap', 'r>', 'call', '>r'],
    'if': ['?', 'call'],
    'when': ['swap', ['call'], ['drop'], 'if'],
    'keep': ['over', ['call'], 'dip'],
    'loop': [['call'], 'keep', ['loop'], 'curry', 'when']
    })
    result = runtime.evaluate(read(raw_input("> ")))
    print "-- data stack --"
    print "\n".join(map(lambda el: repr(el), result))

  5. jdp created this gist Dec 7, 2010.
    122 changes: 122 additions & 0 deletions dope.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,122 @@
    #!/usr/bin/env python

    import sys
    import types
    import operator

    def _swap(stack, retain):
    stack[-1], stack[-2] = stack[-2], stack[-1]

    def _which(stack, retain):
    falseq = stack.pop()
    trueq = stack.pop()
    stack.append(trueq if stack.pop() else falseq)

    def _curry(stack, retain):
    quot = stack.pop()[:]
    quot.insert(0, stack.pop())
    stack.append(quot)

    def _math(stack, func):
    rhs = stack.pop()
    lhs = stack.pop()
    stack.append(func(lhs, rhs))

    def evaluate(nodes, stack=[], env={}):
    retain = []
    i = 0
    frames = []
    while True:
    try:
    node = nodes[i]
    if isinstance(node, str):
    if node[0] == ':':
    stack.append(node[1:])
    elif node == 'call':
    if i < len(nodes) - 1:
    frames.append((nodes, i+1))
    i, nodes = -1, stack.pop()
    else:
    if env.has_key(node):
    defn = env[node]
    if isinstance(defn, list):
    if i < len(nodes) - 1:
    frames.append((nodes, i+1))
    i, nodes = -1, defn
    else:
    defn(stack, retain)
    else:
    raise NameError, "word %s not defined" % node
    else:
    stack.append(node)
    i += 1
    except IndexError:
    try:
    (nodes, i) = frames.pop()
    except IndexError:
    return stack
    return stack

    def read(s):
    return parse(tokenize(s))

    def tokenize(s):
    return s.split()

    def parse(tokens, depth=0):
    program = []
    if len(tokens) == 0:
    return program
    while len(tokens) > 0:
    token = tokens.pop(0)
    if '[' == token:
    program.append(parse(tokens))
    elif ']' == token:
    return program
    else:
    program.append(atom(token))
    return program

    def atom(token):
    "Numbers become numbers; every other token is a symbol."
    try: return int(token)
    except ValueError:
    try: return float(token)
    except ValueError:
    return str(token)

    def repl():
    while True:
    result = evaluate(read(raw_input("> ")), [], {
    '.': lambda s,r: sys.stdout.write(repr(s.pop()) + "\n"),
    '+': lambda s,r: _math(s, operator.add),
    '-': lambda s,r: _math(s, operator.sub),
    '*': lambda s,r: _math(s, operator.mul),
    '/': lambda s,r: _math(s, operator.div),
    'mod': lambda s,r: _math(s, operator.mod),
    '>': lambda s,r: _math(s, operator.gt),
    '<': lambda s,r: _math(s, operator.lt),
    '=': lambda s,r: _math(s, operator.eq),
    'f': lambda s,r: s.append(False),
    'not': lambda s,r: s.append(not s.pop()),
    'drop': lambda s,r: s.pop(),
    'dup': lambda s,r: s.append(s[-1]),
    'swap': _swap,
    'over': lambda s,r: s.append(s[-2]),
    'quote': lambda s,r: s.append(list(s.pop())),
    'r>': lambda s,r: r.append(s.pop()),
    '>r': lambda s,r: s.append(r.pop()),
    '?': _which,
    'curry': _curry,
    # to be moved to prelude
    'dip': ['swap', 'r>', 'call', '>r'],
    'if': ['?', 'call'],
    'when': ['swap', ['call'], ['drop'], 'if'],
    'keep': ['over', ['call'], 'dip'],
    'loop': [['call'], 'keep', ['loop'], 'curry', 'when']
    })
    print "-- data stack --"
    print "\n".join(map(lambda el: repr(el), result))

    if __name__ == '__main__':
    repl()