aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--neb/__init__.py49
-rw-r--r--neb/parser.py11
-rw-r--r--neb/std/core.py4
-rw-r--r--neb/std/types.py29
-rw-r--r--neb/structs.py34
5 files changed, 97 insertions, 30 deletions
diff --git a/neb/__init__.py b/neb/__init__.py
index 71d06e5..e3167b9 100644
--- a/neb/__init__.py
+++ b/neb/__init__.py
@@ -3,6 +3,7 @@ from .parser import parse
from .exceptions import *
from .typeclass import TypeEnum, is_subtype_of
from .structs import *
+from copy import deepcopy
def interpret(exprs, env, ns=None):
ret = None
@@ -15,9 +16,21 @@ def evaluate(expr, env, ns=None):
return expr
elif isinstance(expr, Symbol) or isinstance(expr, Type):
if env.contains(expr.name):
- return evaluate(env.get(expr.name), env, ns)
+ if isinstance(expr, Type) and expr.inner is not None:
+ typecopy = deepcopy(env.get(expr.name))
+ inner = env.get(f"{expr.inner}")
+ typecopy.name.inner = inner
+ return evaluate(typecopy, env, ns)
+ else:
+ return evaluate(env.get(expr.name), env, ns)
elif ns is not None and env.contains(f"{ns}/{expr.name}"):
- return evaluate(env.get(f"{ns}/{expr.name}"), env, ns)
+ if isinstance(expr, Type) and expr.inner is not None:
+ typecopy = deepcopy(env.get(f"{ns}/{expr.name}"))
+ inner = env.get(f"{expr.inner}")
+ typecopy.name.inner = inner
+ return evaluate(typecopy, env, ns)
+ else:
+ return evaluate(env.get(f"{ns}/{expr.name}"), env, ns)
else:
if isinstance(expr, Symbol):
raise NebPanic(f"no such symbol: {expr}")
@@ -47,7 +60,8 @@ class Callable:
self.body = body
self.args = args
self.many = many
- self.type_ = TypeEnum.ANY # TODO no it's not
+ #self.type_ = TypeEnum.ANY # TODO no it's not
+ self.type_ = Type(":any") # TODO no it's not
self.return_type = Type(":any")
def describe(self, name=None):
@@ -108,8 +122,7 @@ class Function(Callable):
else:
arg = self.many
ev = evaluate(param, env, ns)
- expected_name = f"{arg.type_}"
- expected_type = env.get(expected_name)
+ expected_type = evaluate(arg.type_, env, ns)
valid = expected_type.validate_type(ev, env, ns)
if not valid.value:
exp = f"{arg.type_}"
@@ -170,9 +183,11 @@ class UserFunction(Function):
prev_type = False
elif isinstance(param, Type) and not prev_type and not first:
if many is None:
- args[-1].type_ = param.name
+ #args[-1].type_ = param.name
+ args[-1].type_ = param
else:
- many.type_ = param.name
+ #many.type_ = param.name
+ many.type_ = param
prev_type = True
else:
raise NebPanic("invalid :func signature", param)
@@ -195,7 +210,7 @@ class UserFunction(Function):
class TypeWrap:
def __init__(self, name, parent, is_func):
- self.name = name
+ self.name = ALL_TYPES[name]
self.parent = parent
self.is_func = is_func
self.type_ = TypeEnum.TYPE
@@ -204,15 +219,16 @@ class TypeWrap:
# if it's an any type, it's valid
if self.parent is None:
return Bool(True)
- if isinstance(self.is_func, UserFunction):
- valid = self.is_func.call(Expr([None, target]), env, ns)
+ if isinstance(self.is_func, Function):
+ valid = self.is_func.call(Expr([self.name, target]), env, ns)
else:
- valid = self.is_func(None, [target], env, ns)
+ valid = self.is_func(self.name, [target], env, ns)
if valid.value == True:
return valid
- parent_type = env.get(f"{target.type_}")
+
+ parent_type = env.get(target.type_.name)
while valid.value != True and parent_type.parent is not None:
- parent_type = env.get(f"{parent_type.parent}")
+ parent_type = env.get(parent_type.parent.name.name)
valid = Bool(self.name == parent_type.name) # TODO wrong
return valid
@@ -224,4 +240,9 @@ class NebType(TypeWrap):
pass
class UserType(TypeWrap):
- pass
+
+ def __init__(self, name, parent, is_func):
+ if name in ALL_TYPES:
+ raise NebPanic(f"already a type called {name}")
+ ALL_TYPES[name] = Type(name)
+ super().__init__(name, parent, is_func)
diff --git a/neb/parser.py b/neb/parser.py
index bbaf7a8..d5712d2 100644
--- a/neb/parser.py
+++ b/neb/parser.py
@@ -47,6 +47,17 @@ def parseType(token, prev, tokens):
# if the next token is a symbol, combine for a type
if len(tokens) > 0 and tokens[0].type_ == TokenType.SYMBOL:
return Type(f":{tokens[0].text}"), 2
+ elif tokens[0].type_ == TokenType.OPEN_BRACKET:
+ # only format currently supported:
+ # [ <type> ]
+ if tokens[1].type_ != TokenType.COLON:
+ raise ParseError("invalid type definition (expecting colon)", tokens[1].line)
+ typ, counter = parseType(tokens[1], tokens[0], tokens[2:])
+ if tokens[1+counter].type_ != TokenType.CLOSE_BRACKET:
+ raise ParseError("invalid type definition (expecting close bracket)", tokens[1+counter].line)
+ return Type(f":[]", typ), counter + 3
+ else:
+ raise ParseError("invalid type definition!", tokens[0].line)
def parse(tokens):
idx = 0
diff --git a/neb/std/core.py b/neb/std/core.py
index 9e2e743..9240b98 100644
--- a/neb/std/core.py
+++ b/neb/std/core.py
@@ -224,9 +224,9 @@ def interpretType(symbol, args, env, ns):
parent_type = evaluate(args[1], env, ns)
if not isinstance(parent_type, TypeWrap):
raise InterpretPanic(symbol, "parent must be a valid type", parent_type)
- elif not env.contains(parent_type.name):
+ elif not env.contains(f"{parent_type}"):
raise InterpretPanic(symbol, f"no such type {parent_type}")
- parent = env.get(parent_type.name)
+ parent = env.get(f"{parent_type}")
func = evaluate(args[2], env, ns)
if not isinstance(func, Function):
diff --git a/neb/std/types.py b/neb/std/types.py
index 0d3db03..35dca42 100644
--- a/neb/std/types.py
+++ b/neb/std/types.py
@@ -1,4 +1,4 @@
-from .. import TypeEnum, Environment, Arg, Builtin, evaluate, InterpretPanic, NebType
+from .. import TypeEnum, Environment, Arg, Builtin, evaluate, InterpretPanic, NebType, TypeWrap
from ..structs import *
TYPES = Environment()
@@ -25,7 +25,26 @@ def interpretIsInt(symbol, args, env, ns):
TYPES.register("int?", Builtin("int?", interpretIsInt, [Arg("arg", TypeEnum.ANY)], return_type=Type(":bool")))
def interpretIsList(symbol, args, env, ns):
- return Bool(isinstance(args[0], List))
+
+ # if it's not a list, we're done
+ if not isinstance(args[0], List):
+ return Bool(False)
+
+ # if the symbol isn't a type, we're done
+ elif not isinstance(symbol, Type):
+ return Bool(True)
+
+ inner = symbol.inner
+ if inner is None or inner.name == ":any":
+ return Bool(True)
+
+ inner_type = env.get(f"{inner.name}")
+ for arg in args[0].args:
+ valid = inner_type.validate_type(arg, env, ns)
+ if valid.value is False:
+ return Bool(False)
+ return Bool(True)
+
TYPES.register("list?", Builtin("list?", interpretIsList, [Arg("arg", TypeEnum.ANY)], return_type=Type(":bool")))
@@ -83,7 +102,8 @@ TYPES.register("type?", Builtin("type?", interpretIsType, [Arg("arg", TypeEnum.A
any_type = NebType(":any", None, interpretIsAny)
literal_type = NebType(":literal", any_type, interpretIsLiteral)
string_type = NebType(":string", literal_type, interpretIsString)
-list_type = NebType(":list", any_type, interpretIsList)
+#list_type = NebType(":list", any_type, interpretIsList)
+bracket_type = NebType(":[]", any_type, interpretIsList)
bool_type = NebType(":bool", literal_type, interpretIsBool)
number_type = NebType(":number", literal_type, interpretIsNumber)
int_type = NebType(":int", number_type, interpretIsInt)
@@ -94,7 +114,8 @@ type_type = NebType(":type", any_type, interpretIsType)
TYPES.register(":any", any_type)
TYPES.register(":literal", literal_type)
TYPES.register(":string", string_type)
-TYPES.register(":list", list_type)
+#TYPES.register(":list", list_type)
+TYPES.register(":[]", bracket_type)
TYPES.register(":bool", bool_type)
TYPES.register(":number", number_type)
TYPES.register(":int", int_type)
diff --git a/neb/structs.py b/neb/structs.py
index df7127f..45e69a7 100644
--- a/neb/structs.py
+++ b/neb/structs.py
@@ -61,33 +61,34 @@ class Literal:
def __init__(self, value, type_=None):
self.value = value
if type_ is None:
- self.type_ = TypeEnum.ANY
+ #self.type_ = TypeEnum.ANY
+ self.type_ = ALL_TYPES[":literal"]
else:
- self.type_ = type_
+ self.type_ = ALL_TYPES[type_]
def __str__(self):
return f"{self.value}:literal"
class Int(Literal):
def __init__(self, value):
- super().__init__(value, TypeEnum.INT)
+ super().__init__(value, ":int")
def __str__(self):
return f"{self.value}"
class Float(Literal):
def __init__(self, value):
- super().__init__(value, TypeEnum.FLOAT)
+ super().__init__(value, ":float")
def __str__(self):
return f"{self.value}"
class Bool(Literal):
def __init__(self, value):
- super().__init__(value, TypeEnum.BOOL)
+ super().__init__(value, ":bool")
def __str__(self):
return f"#{str(self.value).lower()}"
class String(Literal):
def __init__(self, value):
- super().__init__(value, TypeEnum.STRING)
+ super().__init__(value, ":string")
def __str__(self):
return f'"{repr(self.value)[1:-1]}"'
@@ -99,10 +100,20 @@ class Handle:
return f"{self.file.name} :handle"
class Type:
- def __init__(self, name):
+ def __init__(self, name, inner=None):
self.name = name
+ self.inner = inner
def __str__(self):
- return self.name
+ if self.name == ":[]":
+ if self.inner is None:
+ return f":[:any]"
+ else:
+ return f":[{self.inner}]"
+ else:
+ return self.name
+
+_native_types = ":any :literal :string :bool :number :int :float :[] :handle :type"
+ALL_TYPES = {x: Type(x) for x in _native_types.split(" ")}
class Symbol:
def __init__(self, name, line):
@@ -122,7 +133,7 @@ class Expr:
class List:
def __init__(self, args):
self.args = args
- self.type_ = TypeEnum.LIST
+ self.type_ = ALL_TYPES[":[]"]
def __str__(self):
return "(" + " ".join(f"{arg}" for arg in self.args) + ")"
@@ -131,7 +142,10 @@ class Arg:
def __init__(self, name, type_, *, optional=False):
self.name = name
- self.type_ = type_
+ if f"{type_}" == ":list":
+ self.type_ = ALL_TYPES[":[]"]
+ else:
+ self.type_ = ALL_TYPES[f"{type_}"]
self.optional = optional
def __str__(self):