aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--interpreter.py20
-rw-r--r--lexer.py67
-rw-r--r--parser.py11
-rw-r--r--structs.py92
4 files changed, 109 insertions, 81 deletions
diff --git a/interpreter.py b/interpreter.py
index 4adb972..e888944 100644
--- a/interpreter.py
+++ b/interpreter.py
@@ -1,4 +1,4 @@
-from parser import Expr
+from structs import Literal, Symbol, List
class Function:
@@ -21,7 +21,6 @@ class Builtin(Function):
def call(self, expr, env):
if self.arities is not None and len(expr.args[1:]) not in self.arities:
- #if self.arity >= 0 and len(args) != self.arity:
fmt = f"[{self.arities[0]}"
for arity in self.arities[1:]:
fmt += f", {arity}"
@@ -38,7 +37,7 @@ class UserFunction(Function):
this_env = Environment(env)
for idx, param in enumerate(self.params):
# TODO this is wrong!!! this won't always be a literal
- this_env.register(param.name, Expr.Literal(evaluate(expr.args[idx+1],env)))
+ this_env.register(param.name, Literal(evaluate(expr.args[idx+1],env)))
return interpret(self.body, this_env)
class Environment:
@@ -81,15 +80,14 @@ def interpret(exprs, env=GLOBALS):
return ret
def evaluate(expr, env):
- if isinstance(expr, Expr.Literal):
+ if isinstance(expr, Literal):
return expr.value
- elif isinstance(expr, Expr.Symbol):
+ elif isinstance(expr, Symbol):
if not env.contains(expr.name):
raise Exception(f"no such symbol: {expr}")
return evaluate(env.get(expr.name), env)
- #name = expr.symbol.name
- if not isinstance(expr.args[0], Expr.Symbol):
+ if not isinstance(expr.args[0], Symbol):
raise Exception("can't evaluate without a symbol")
name = expr.args[0].name
if name == "def":
@@ -234,7 +232,7 @@ def interpretPrint(symbol, args, env):
GLOBALS.register("print", Builtin(interpretPrint, 1))
def interpretDef(symbol, args, env):
- if not isinstance(args[0], Expr.Symbol):
+ if not isinstance(args[0], Symbol):
raise Exception("'def' requires a string literal as a name")
name = args[0].name # NOTE: we are not evaluating the name!!
if not isinstance(name, str):
@@ -285,7 +283,7 @@ def interpretForCount(symbol, args, env):
new_env = Environment(env)
ret = None
for idx in range(0, num):
- new_env.register("idx", Expr.Literal(idx + 1))
+ new_env.register("idx", Literal(idx + 1))
for arg in args[1:]:
ret = evaluate(arg, new_env)
return ret
@@ -300,7 +298,7 @@ def interpretPipe(symbol, args, env):
for arg in args:
if pipe is not None:
new_env.register("items", pipe)
- pipe = Expr.Literal(evaluate(arg, new_env))
+ pipe = Literal(evaluate(arg, new_env))
return pipe
GLOBALS.register("|", Builtin(interpretPipe))
@@ -322,7 +320,7 @@ def interpretFunc(symbol, args, env):
# func <name> (args) (exprs)
if len(args) < 3:
raise Exception("'func' takes a name, arguments, and at least one expression")
- if not isinstance(args[0], Expr.Symbol):
+ if not isinstance(args[0], Symbol):
raise Exception("'func' requires a string literal as a name")
name = args[0].name # NOTE: we are not evaluating the name!!
diff --git a/lexer.py b/lexer.py
index 3b93e41..c2460eb 100644
--- a/lexer.py
+++ b/lexer.py
@@ -1,6 +1,4 @@
-from dataclasses import dataclass
-from enum import Enum, auto
-from typing import Any
+from structs import TokenType, Token
import sys
class LexError(BaseException):
@@ -8,59 +6,6 @@ class LexError(BaseException):
def __init__(self, message, line):
super().__init__(f"line {line}: {message}")
-class TokenType(Enum):
-
- PRINT = auto()
-
- OPEN_PAREN = auto()
- CLOSE_PAREN = auto()
-
- EOF = auto()
-
- # literals
- INT = auto()
- FLOAT = auto()
- STRING = auto()
- TRUE = auto()
- FALSE = auto()
-
- # arithmetic
- PLUS = auto()
- DASH = auto()
- STAR = auto()
- SLASH = auto()
-
- # strings
- DOUBLE_QUOTE = auto()
-
- # comparison
- GREATER = auto()
- GREATER_EQUAL = auto()
- LESS = auto()
- LESS_EQUAL = auto()
- EQUAL = auto()
- NOT = auto()
- AND = auto()
- OR = auto()
-
- # flow
- IF = auto()
- FOR_COUNT = auto()
- PIPE = auto()
-
- # keywords
- DEF = auto()
- LAMBDA = auto()
-
- # symbols
- SYMBOL = auto()
-
- # types
- INT_TYPE = auto()
- FLOAT_TYPE = auto()
- STRING_TYPE = auto()
- ANY_TYPE = auto()
-
types = {
":int": TokenType.INT_TYPE,
":float": TokenType.FLOAT_TYPE,
@@ -88,16 +33,6 @@ keywords = {
"lambda": TokenType.LAMBDA }
-@dataclass
-class Token:
- type_: TokenType
- text: str
- value: Any
- line: int
-
- def __str__(self):
- return f"{self.type_.name} {self.text} {self.line}"
-
WHITESPACE = [" ", "\n", "\t"]
SEPARATORS = WHITESPACE + [")"]
DIGITS = list("0123456789")
diff --git a/parser.py b/parser.py
index 7916a97..a781d50 100644
--- a/parser.py
+++ b/parser.py
@@ -1,3 +1,5 @@
+from structs import TokenType, Literal, Symbol, Type, List
+'''
from lexer import TokenType
class Expr:
@@ -34,6 +36,7 @@ class Expr:
visitor.visitNary(self)
def __str__(self):
return "(" + " ".join(f"{arg}" for arg in self.args) + ")"
+'''
def parseExpression(token, prev, tokens):
idx = 0
@@ -57,16 +60,16 @@ def parseExpression(token, prev, tokens):
idx += inc
prev = token
- return Expr.List(args), idx + 2 # parens
+ return List(args), idx + 2 # parens
def parseSymbol(token, prev, tokens):
- return Expr.Symbol(token.text), 1
+ return Symbol(token.text), 1
def parseLiteral(token, prev, tokens):
- return Expr.Literal(token.value), 1
+ return Literal(token.value), 1
def parseType(token, prev, tokens):
- return Expr.Type(token.text), 1
+ return Type(token.text), 1
def parse(tokens):
idx = 0
diff --git a/structs.py b/structs.py
new file mode 100644
index 0000000..02f2c50
--- /dev/null
+++ b/structs.py
@@ -0,0 +1,92 @@
+from dataclasses import dataclass
+from enum import Enum, auto
+from typing import Any
+
+# tokens and types
+# NOTE: this can probably be simplified
+class TokenType(Enum):
+
+ PRINT = auto()
+
+ OPEN_PAREN = auto()
+ CLOSE_PAREN = auto()
+
+ EOF = auto()
+
+ # literals
+ INT = auto()
+ FLOAT = auto()
+ STRING = auto()
+ TRUE = auto()
+ FALSE = auto()
+
+ # arithmetic
+ PLUS = auto()
+ DASH = auto()
+ STAR = auto()
+ SLASH = auto()
+
+ # strings
+ DOUBLE_QUOTE = auto()
+
+ # comparison
+ GREATER = auto()
+ GREATER_EQUAL = auto()
+ LESS = auto()
+ LESS_EQUAL = auto()
+ EQUAL = auto()
+ NOT = auto()
+ AND = auto()
+ OR = auto()
+
+ # flow
+ IF = auto()
+ FOR_COUNT = auto()
+ PIPE = auto()
+
+ # keywords
+ DEF = auto()
+ LAMBDA = auto()
+
+ # symbols
+ SYMBOL = auto()
+
+ # types
+ INT_TYPE = auto()
+ FLOAT_TYPE = auto()
+ STRING_TYPE = auto()
+ ANY_TYPE = auto()
+
+@dataclass
+class Token:
+ type_: TokenType
+ text: str
+ value: Any
+ line: int
+
+ def __str__(self):
+ return f"{self.type_.name} {self.text} {self.line}"
+
+class Literal:
+ def __init__(self, value):
+ self.value = value
+ def __str__(self):
+ return f"{self.value}"
+
+class Type:
+ def __init__(self, name):
+ self.name = name
+ def __str__(self):
+ return self.name
+
+class Symbol:
+ def __init__(self, name):
+ self.name = name
+ def __str__(self):
+ return f"'{self.name}"
+
+class List:
+ def __init__(self, args):
+ self.args = args
+ def __str__(self):
+ return "(" + " ".join(f"{arg}" for arg in self.args) + ")"