Initial commit - fix problems & refactor code
This commit is contained in:
@@ -0,0 +1,24 @@
|
||||
from core.tokens import BinaryOperator
|
||||
from core.exceptions import runtimeError
|
||||
from core.environment import RepresentateAST
|
||||
|
||||
def evalBinaryOperator(op: BinaryOperator, a, b):
|
||||
try:
|
||||
match op:
|
||||
case BinaryOperator.ADD:
|
||||
return a + b
|
||||
case BinaryOperator.SUB:
|
||||
return a - b
|
||||
case BinaryOperator.MUL:
|
||||
return a * b
|
||||
case BinaryOperator.DIV:
|
||||
if type(a) is type(b) is int:
|
||||
return a // b
|
||||
return a / b
|
||||
case BinaryOperator.MOD:
|
||||
return a % b
|
||||
case BinaryOperator.STRCONCAT:
|
||||
return RepresentateAST(a) + RepresentateAST(b)
|
||||
|
||||
except Exception as e:
|
||||
raise runtimeError(f'cannot apply {repr(op)} to {repr(a)} and {repr(b)}') from e
|
||||
@@ -0,0 +1,14 @@
|
||||
from core.tokens import BinaryPredicate
|
||||
from core.exceptions import runtimeError
|
||||
|
||||
def evalBinaryPredicate(op: BinaryPredicate, a, b):
|
||||
try:
|
||||
match op:
|
||||
case BinaryPredicate.LT:
|
||||
return a < b
|
||||
case BinaryPredicate.GT:
|
||||
return a > b
|
||||
case BinaryPredicate.EQ:
|
||||
return a == b
|
||||
except Exception as e:
|
||||
raise runtimeError(f'cannot apply {repr(op)} to {repr(a)} and {repr(b)}') from e
|
||||
@@ -0,0 +1,53 @@
|
||||
from core.primitives.list import NIL, cons, car, cdr
|
||||
from core.primitives.symbol import isSymbol, symbolName
|
||||
|
||||
from core.exceptions import syntaxError
|
||||
|
||||
from core.tokens import Lambda
|
||||
from core.tail_recursion import tailRecursion
|
||||
|
||||
# from core.evaluator.naively_evaluate import naivelyEvaluate
|
||||
from core.evaluator.utils.getFirstN import getFirstN
|
||||
|
||||
from core.environment import TCO
|
||||
|
||||
def evalCall(head, tail, environment, environmentParent, strict):
|
||||
from core.evaluator.naively_evaluate import naivelyEvaluate
|
||||
args = head.args
|
||||
|
||||
if args == NIL and tail != NIL:
|
||||
raise syntaxError(f'more than zero args for {repr(head)}')
|
||||
|
||||
while args != NIL:
|
||||
firstArg = car(args)
|
||||
if not isSymbol(firstArg):
|
||||
raise syntaxError(f'cannot take non-symbol as argument: {repr(firstArg)}')
|
||||
if symbolName(firstArg) == '.':
|
||||
firstArg = getFirstN(args, 2)[1]
|
||||
arr = []
|
||||
while tail != NIL:
|
||||
arr.append(naivelyEvaluate(car(tail), environmentParent, True))
|
||||
tail = cdr(tail)
|
||||
arg = NIL
|
||||
for elem in reversed(arr):
|
||||
arg = cons(elem, arg)
|
||||
args = NIL
|
||||
else:
|
||||
if tail == NIL:
|
||||
break
|
||||
arg = naivelyEvaluate(car(tail), environmentParent, True)
|
||||
args = cdr(args)
|
||||
tail = cdr(tail)
|
||||
environment.add(firstArg, arg)
|
||||
|
||||
if tail != NIL:
|
||||
raise syntaxError(f'extra args {repr(tail)}\nfor not variable lambda {repr(head)}')
|
||||
|
||||
if args != NIL:
|
||||
return Lambda(args, head.body, environment)
|
||||
|
||||
if not TCO:
|
||||
return naivelyEvaluate(head.body, environment, True)
|
||||
|
||||
ret = tailRecursion(naivelyEvaluate, head.body, environment, False)
|
||||
return tailRecursion.eval(ret) if strict else ret
|
||||
@@ -0,0 +1,49 @@
|
||||
from core.primitives.list import cons, car, cdr, NIL
|
||||
from core.primitives.symbol import symbolName, symbolKey
|
||||
|
||||
from core.tokens import Macro
|
||||
from core.exceptions import syntaxError
|
||||
|
||||
from core.tail_recursion import tailRecursion
|
||||
from core.macro_expand import macroExpand
|
||||
|
||||
# from core.evaluator.naively_evaluate import naivelyEvaluate
|
||||
from core.evaluator.utils.getFirstN import getFirstN
|
||||
|
||||
from core.environment import TCO
|
||||
|
||||
def evalMacro(head, tail, environment, strict):
|
||||
from core.evaluator.naively_evaluate import naivelyEvaluate
|
||||
d = dict()
|
||||
args = head.args
|
||||
|
||||
if args == NIL and tail != NIL:
|
||||
raise syntaxError(f'more than zero args for {repr(head)}')
|
||||
|
||||
while args != NIL:
|
||||
firstArg = car(args)
|
||||
if symbolName(firstArg) == '.':
|
||||
firstArg = getFirstN(args, 2)[1]
|
||||
arg = tail
|
||||
args = NIL
|
||||
tail = NIL
|
||||
else:
|
||||
if tail == NIL:
|
||||
break
|
||||
arg = car(tail)
|
||||
args = cdr(args)
|
||||
tail = cdr(tail)
|
||||
d[symbolKey(firstArg)] = arg
|
||||
|
||||
if tail != NIL:
|
||||
raise syntaxError(f'extra args {repr(tail)}\nfor not variable macro {repr(head)}')
|
||||
expanded = macroExpand(head.body, d)
|
||||
|
||||
if args != NIL:
|
||||
return Macro(args, expanded)
|
||||
|
||||
if not TCO:
|
||||
return naivelyEvaluate(expanded, environment, True)
|
||||
|
||||
ret = tailRecursion(naivelyEvaluate, expanded, environment, False)
|
||||
return tailRecursion.eval(ret) if strict else ret
|
||||
@@ -0,0 +1,137 @@
|
||||
from core.tokens import (
|
||||
SpecialForm,
|
||||
Lambda,
|
||||
Macro,
|
||||
Pure
|
||||
)
|
||||
|
||||
from core.primitives.list import (
|
||||
cons,
|
||||
car,
|
||||
cdr,
|
||||
isList
|
||||
)
|
||||
from core.primitives.symbol import symbol
|
||||
|
||||
|
||||
from core.environment import NIL, RepresentateAST
|
||||
from core.primitives.symbol import isSymbol
|
||||
from core.exceptions import (
|
||||
syntaxError,
|
||||
runtimeError
|
||||
)
|
||||
|
||||
# from core.evaluator.naively_evaluate import naivelyEvaluate
|
||||
from core.evaluator.utils.getFirstN import getFirstN
|
||||
from core.parser.parse_expression import parseExpression
|
||||
|
||||
def evalSpecialForm(head, tail, env, strict):
|
||||
from core.evaluator.naively_evaluate import naivelyEvaluate
|
||||
match head:
|
||||
case SpecialForm.QUOTE:
|
||||
return getFirstN(tail, 1)[0]
|
||||
|
||||
case SpecialForm.EVAL:
|
||||
return naivelyEvaluate(naivelyEvaluate(getFirstN(tail, 1)[0], env, True), env, strict)
|
||||
|
||||
case SpecialForm.TYPEOF:
|
||||
a = naivelyEvaluate(getFirstN(tail, 1)[0], env, True)
|
||||
return 'List' if isList(a) else 'Symbol' if isSymbol(a) else str(a.__class__.__name__)
|
||||
|
||||
case SpecialForm.CONS:
|
||||
a, b = getFirstN(tail, 2)
|
||||
evaluated_b = naivelyEvaluate(b, env, True)
|
||||
if not isList(evaluated_b):
|
||||
raise syntaxError('cannot add element to non-list')
|
||||
return cons(naivelyEvaluate(a, env, True), evaluated_b)
|
||||
|
||||
case SpecialForm.CAR:
|
||||
a = naivelyEvaluate(getFirstN(tail, 1)[0], env, True)
|
||||
if not isList(a):
|
||||
return a # config moment
|
||||
if a == NIL:
|
||||
raise syntaxError("NIL's head???") # config moment
|
||||
return car(a)
|
||||
|
||||
case SpecialForm.CDR:
|
||||
a = naivelyEvaluate(getFirstN(tail, 1)[0], env, True)
|
||||
if not isList(a):
|
||||
return NIL # config moment
|
||||
if a == NIL:
|
||||
raise syntaxError("NIL's tail???") # config moment
|
||||
return cdr(a)
|
||||
|
||||
case SpecialForm.IF:
|
||||
a, b, c = getFirstN(tail, 3) # a ? b : c
|
||||
evaled_a = naivelyEvaluate(a, env, True)
|
||||
if type(evaled_a) is bool:
|
||||
return naivelyEvaluate(b, env, strict) if evaled_a else naivelyEvaluate(c, env, strict)
|
||||
raise syntaxError(f'not boolean {a} in (++ {repr(head)} {repr(tail)})') # TODO
|
||||
|
||||
case SpecialForm.DO:
|
||||
if tail == NIL:
|
||||
return NIL
|
||||
ev = NIL
|
||||
while cdr(tail) != NIL:
|
||||
ev = naivelyEvaluate(car(tail), env, True)
|
||||
tail = cdr(tail)
|
||||
return naivelyEvaluate(car(tail), env, strict)
|
||||
|
||||
case SpecialForm.PRINT:
|
||||
print(RepresentateAST(naivelyEvaluate(getFirstN(tail, 1)[0], env, True)), end='')
|
||||
return NIL
|
||||
|
||||
case SpecialForm.FLUSH:
|
||||
print(end='', flush=True)
|
||||
return NIL
|
||||
|
||||
case SpecialForm.READ:
|
||||
getFirstN(tail, 0)
|
||||
s = input('\nreading: ')
|
||||
return parseExpression(s)[0]
|
||||
|
||||
case SpecialForm.SYMBOL:
|
||||
a = naivelyEvaluate(getFirstN(tail, 1)[0], env, True)
|
||||
if not isinstance(a, str):
|
||||
raise syntaxError('cannot make symbol from non-string')
|
||||
return symbol(a)
|
||||
|
||||
case SpecialForm.DEF:
|
||||
a, b = getFirstN(tail, 2)
|
||||
if isSymbol(a):
|
||||
env.add(a, naivelyEvaluate(b, env, True))
|
||||
return NIL
|
||||
raise syntaxError('cannot define non-symbol')
|
||||
|
||||
case SpecialForm.SET:
|
||||
a, b = getFirstN(tail, 2)
|
||||
if isSymbol(a):
|
||||
env.set(a, naivelyEvaluate(b, env, True))
|
||||
return NIL
|
||||
raise syntaxError('cannot set non-Symbol')
|
||||
|
||||
case SpecialForm.LAMBDA:
|
||||
a, b = getFirstN(tail, 2)
|
||||
if isList(a):
|
||||
return Lambda(a, b, env)
|
||||
raise syntaxError(f'wrong args form for lambda: {repr(a)}')
|
||||
|
||||
# some errors may be here
|
||||
case SpecialForm.PURE:
|
||||
a, b = getFirstN(tail, 2)
|
||||
if isList(a):
|
||||
return Pure(a, b)
|
||||
raise syntaxError(f'wrong args form for pure: {repr(a)}')
|
||||
|
||||
case SpecialForm.MACRO:
|
||||
a, b = getFirstN(tail, 2)
|
||||
if isList(a):
|
||||
return Macro(a, b)
|
||||
raise syntaxError(f'wrong args form for macro: {repr(a)}')
|
||||
|
||||
case SpecialForm.RAISE:
|
||||
cause = naivelyEvaluate(getFirstN(tail, 1)[0], env, True)
|
||||
raise runtimeError(RepresentateAST(cause))
|
||||
|
||||
case _:
|
||||
raise syntaxError
|
||||
@@ -0,0 +1,73 @@
|
||||
from core.tokens import (
|
||||
BinaryOperator,
|
||||
BinaryPredicate,
|
||||
SpecialForm,
|
||||
Lambda,
|
||||
Pure,
|
||||
Macro,
|
||||
)
|
||||
|
||||
# debug
|
||||
import sys
|
||||
|
||||
from core.primitives.symbol import (
|
||||
isSymbol
|
||||
)
|
||||
from core.primitives.list import (
|
||||
cons, car, cdr,
|
||||
isList,
|
||||
NIL
|
||||
)
|
||||
from core.environment import EVAL_NIL, Environment, RepresentateAST
|
||||
|
||||
from core.evaluator.evaluate_binary_operator import evalBinaryOperator
|
||||
from core.evaluator.evaluate_binary_predicate import evalBinaryPredicate
|
||||
from core.evaluator.evaluate_special_form import evalSpecialForm
|
||||
from core.evaluator.evaluate_call import evalCall
|
||||
from core.evaluator.evaluate_macro import evalMacro
|
||||
|
||||
from core.evaluator.utils.getFirstN import getFirstN
|
||||
|
||||
from core.exceptions import error, syntaxError, typeError
|
||||
|
||||
def naivelyEvaluate(value, localEnvironment, strict):
|
||||
if isSymbol(value):
|
||||
return localEnvironment.get(value)
|
||||
|
||||
elif isList(value):
|
||||
if value == NIL:
|
||||
return EVAL_NIL()
|
||||
head = naivelyEvaluate(car(value), localEnvironment, True)
|
||||
tail = cdr(value)
|
||||
|
||||
try:
|
||||
if isinstance(head, (BinaryOperator, BinaryPredicate)):
|
||||
try:
|
||||
a, b = getFirstN(tail, 2)
|
||||
evaledA = naivelyEvaluate(a, localEnvironment, True)
|
||||
evaledB = naivelyEvaluate(b, localEnvironment, True)
|
||||
if isinstance(head, BinaryOperator):
|
||||
return evalBinaryOperator(head, evaledA, evaledB)
|
||||
return evalBinaryPredicate(head, evaledA, evaledB)
|
||||
except syntaxError as e:
|
||||
raise syntaxError(f'wrong args for: {repr(value)}') from e
|
||||
|
||||
elif isinstance(head, SpecialForm):
|
||||
return evalSpecialForm(head, tail, localEnvironment, strict)
|
||||
|
||||
elif isinstance(head, (Lambda, Pure)):
|
||||
if isinstance(head, Lambda):
|
||||
environment = Environment(head.env)
|
||||
else:
|
||||
environment = Environment(parent=localEnvironment)
|
||||
return evalCall(head, tail, environment, localEnvironment, strict)
|
||||
|
||||
elif isinstance(head, Macro):
|
||||
return evalMacro(head, tail, localEnvironment, strict)
|
||||
|
||||
except error as e:
|
||||
raise syntaxError(f'wrong args for {repr(head)}: {repr(cdr(value))}') from e
|
||||
|
||||
raise typeError(f'wrong head form: {RepresentateAST(head)}')
|
||||
|
||||
return value
|
||||
@@ -0,0 +1,32 @@
|
||||
from typing import Any
|
||||
from core.primitives.list import cons, car, cdr, NIL
|
||||
from core.exceptions import syntaxError
|
||||
from core.printer import Representation
|
||||
|
||||
def getFirstN(_list: Any, n: int) -> list[Any]:
|
||||
"""Get first N elements.
|
||||
|
||||
Args:
|
||||
_list: A list.
|
||||
n: The expected number of elements.
|
||||
|
||||
Returns:
|
||||
A list of the extracted elements.
|
||||
|
||||
Raises:
|
||||
syntaxError: If the list has wrong number of elements.
|
||||
"""
|
||||
result: list[Any] = []
|
||||
current: Any = _list
|
||||
|
||||
while current != NIL and len(result) < n:
|
||||
result.append(car(current))
|
||||
current = cdr(current)
|
||||
|
||||
if current != NIL:
|
||||
raise syntaxError(f"extra elems: {Representation(current)}")
|
||||
|
||||
if len(result) < n:
|
||||
raise syntaxError("lack of elems")
|
||||
|
||||
return result
|
||||
Reference in New Issue
Block a user