commit cce68e439dbfd91731dadef85caad06c45cc6075 Author: Seviche CC Date: Fri Jun 9 23:35:51 2023 +0800 init diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..5c80254 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,6 @@ +{ + "[python]": { + "editor.defaultFormatter": "ms-python.autopep8" + }, + "python.formatting.provider": "none" +} diff --git a/Python3/lis.py b/Python3/lis.py new file mode 100644 index 0000000..2d031ad --- /dev/null +++ b/Python3/lis.py @@ -0,0 +1,145 @@ +################ Lispy: Scheme Interpreter in Python + +## (c) Peter Norvig, 2010-16; See http://norvig.com/lispy.html + +from __future__ import division +import math +import operator as op + +################ Types + +Symbol = str # A Lisp Symbol is implemented as a Python str +List = list # A Lisp List is implemented as a Python list +Number = (int, float) # A Lisp Number is implemented as a Python int or float + +################ Parsing: parse, tokenize, and read_from_tokens + +def parse(program): + "Read a Scheme expression from a string." + return read_from_tokens(tokenize(program)) + +def tokenize(s): + "Convert a string into a list of tokens." + return s.replace('(',' ( ').replace(')',' ) ').split() + +def read_from_tokens(tokens): + "Read an expression from a sequence of tokens." + if len(tokens) == 0: + raise SyntaxError('unexpected EOF while reading') + token = tokens.pop(0) + if '(' == token: + L = [] + while tokens[0] != ')': + L.append(read_from_tokens(tokens)) + tokens.pop(0) # pop off ')' + return L + elif ')' == token: + raise SyntaxError('unexpected )') + else: + return atom(token) + +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 Symbol(token) + +################ Environments + +def standard_env(): + "An environment with some Scheme standard procedures." + env = Env() + env.update(vars(math)) # sin, cos, sqrt, pi, ... + env.update({ + '+':op.add, '-':op.sub, '*':op.mul, '/':op.truediv, + '>':op.gt, '<':op.lt, '>=':op.ge, '<=':op.le, '=':op.eq, + 'abs': abs, + 'append': op.add, + 'apply': apply, + 'begin': lambda *x: x[-1], + 'car': lambda x: x[0], + 'cdr': lambda x: x[1:], + 'cons': lambda x,y: [x] + y, + 'eq?': op.is_, + 'equal?': op.eq, + 'length': len, + 'list': lambda *x: list(x), + 'list?': lambda x: isinstance(x,list), + 'map': map, + 'max': max, + 'min': min, + 'not': op.not_, + 'null?': lambda x: x == [], + 'number?': lambda x: isinstance(x, Number), + 'procedure?': callable, + 'round': round, + 'symbol?': lambda x: isinstance(x, Symbol), + }) + return env + +class Env(dict): + "An environment: a dict of {'var':val} pairs, with an outer Env." + def __init__(self, parms=(), args=(), outer=None): + self.update(zip(parms, args)) + self.outer = outer + def find(self, var): + "Find the innermost Env where var appears." + return self if (var in self) else self.outer.find(var) + +global_env = standard_env() + +################ Interaction: A REPL + +def repl(prompt='lis.py> '): + "A prompt-read-eval-print loop." + while True: + val = eval(parse(raw_input(prompt))) + if val is not None: + print(lispstr(val)) + +def lispstr(exp): + "Convert a Python object back into a Lisp-readable string." + if isinstance(exp, List): + return '(' + ' '.join(map(lispstr, exp)) + ')' + else: + return str(exp) + +################ Procedures + +class Procedure(object): + "A user-defined Scheme procedure." + def __init__(self, parms, body, env): + self.parms, self.body, self.env = parms, body, env + def __call__(self, *args): + return eval(self.body, Env(self.parms, args, self.env)) + +################ eval + +def eval(x, env=global_env): + "Evaluate an expression in an environment." + if isinstance(x, Symbol): # variable reference + return env.find(x)[x] + elif not isinstance(x, List): # constant literal + return x + elif x[0] == 'quote': # (quote exp) + (_, exp) = x + return exp + elif x[0] == 'if': # (if test conseq alt) + (_, test, conseq, alt) = x + exp = (conseq if eval(test, env) else alt) + return eval(exp, env) + elif x[0] == 'define': # (define var exp) + (_, var, exp) = x + env[var] = eval(exp, env) + elif x[0] == 'set!': # (set! var exp) + (_, var, exp) = x + env.find(var)[var] = eval(exp, env) + elif x[0] == 'lambda': # (lambda (var...) body) + (_, parms, body) = x + return Procedure(parms, body, env) + else: # (proc arg...) + proc = eval(x[0], env) + args = [eval(exp, env) for exp in x[1:]] + return proc(*args) \ No newline at end of file diff --git a/Python3/lisp.py b/Python3/lisp.py new file mode 100644 index 0000000..1789917 --- /dev/null +++ b/Python3/lisp.py @@ -0,0 +1,47 @@ +## (c) Peter Norvig, 2010-16; See http://norvig.com/lispy.html + +program = "(begin (define r 10) (* pi (* r r)))" +################ Types + +Symbol = str +List = list +Number = (int, float) +Atom = (Symbol, Number) +Exp = (Atom, list) +Env = dict + +################ Parsing: parse, tokenize, and read_from_tokens + +def parse(program:str) -> Exp: + "Read a Scheme expression from a string." + return read_from_tokens(tokenize(program)) + +def tokenize(chars: str) -> list: + "Convert a string of characters into list of tokens." + return chars.replace('(', ' ( ').replace(')', ' ) ').split() + +def read_from_tokens(tokens: list) -> Exp: + "Read an expression from a sequence of tokens." + if len(tokens) == 0: + raise SyntaxError('unexpected EOF while reading') + token = tokens.pop(0) + if token == '(': + L = [] + while tokens[0] != ')': + L.append(read_from_tokens(tokens)) + tokens.pop(0) + return L + elif token == ')': + raise SyntaxError('unexpected )') + else: + return atom(token) + +def atom(token: str) -> Atom: + "Numbers become numbers; every other token is a symbol." + try: return int(token) + except ValueError: + try: return float(token) + except ValueError: + return Symbol(token) + +print(parse(program)) \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..3799312 --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +Reference: +- [(How to Write a (Lisp) Interpreter (in Python))](http://norvig.com/lispy.html) \ No newline at end of file diff --git a/TypeScript/lisp.ts b/TypeScript/lisp.ts new file mode 100644 index 0000000..7f71d55 --- /dev/null +++ b/TypeScript/lisp.ts @@ -0,0 +1,67 @@ +// Lispts: Scheme Interpreter in TypeScript +const program = '(begin (define r 10) (* pi (* r r)))' + +type LSymbol = Symbol // A Lisp Symbol(alias TSymbol) is implemented as TypeScript string +type LNumber = number // A Lisp Symbol(alias TSymbol) is implemented as TypeScript number +type Atom = LSymbol | number // A Lisp Atom is a Symbol or Number impl +type List = Array // A Lisp List is implemented as a TypeScript array +type Exp = Atom | List // A Lisp expression is an Atom or List +type Env = Object // A Lisp environment is a mapping of {variable: value} + +class ValueError extends Error{ + constructor(message:string) { + super(message) + this.name = 'ValueError' + } +} + +/** + * Convert a string into a list of tokens. + */ +const tokenize = (char: string): string[] => + char + .replaceAll('(', ' ( ') + .replaceAll(')', ' ) ') + .split(' ') + .filter((s) => s) + +/** + * Numbers become numbers; every other token is a symbol(LSymbol). + */ +const atom = (token: string): Atom => { + try { + if (Number.isNaN(token)) { + throw new ValueError('Value Error') + } + } catch (error) { + if (error === ValueError) { + + } + } +} + +/** + * Read an expression from a sequence of tokens + */ +const read_from_tokens = (tokens: string[]): Exp => { + if (tokens.length === 0) { + throw new Error('unexpected EOF while reading') + } + + const token = tokens.shift() + if (token === '(') { + const l = [] + while (token[0] !== ')') { + l.push(read_from_tokens(tokens)) + } + tokens.shift() + return l + } else if (token === ')') { + throw new Error ('unexpected )') + } else { + return atom(token) + } +} + + +console.log(tokenize(program)) diff --git a/TypeScript/tsconfig.json b/TypeScript/tsconfig.json new file mode 100644 index 0000000..76bb9c3 --- /dev/null +++ b/TypeScript/tsconfig.json @@ -0,0 +1,19 @@ +{ + "compilerOptions": { + "target": "es5", + "lib": ["dom","dom.iterable","ESNext"], + "allowJs": true, + "skipLibCheck": true, + "strict": true, + "forceConsistentCasingInFileNames": true, + "noEmit": true, + "esModuleInterop": true, + "module": "esnext", + "moduleResolution": "node", + "resolveJsonModule": true, + "incremental": true, + }, + "include": [ + "./*.ts", + ], +}