diff options
| -rw-r--r-- | neb/__init__.py | 49 | ||||
| -rw-r--r-- | neb/parser.py | 11 | ||||
| -rw-r--r-- | neb/std/core.py | 4 | ||||
| -rw-r--r-- | neb/std/types.py | 29 | ||||
| -rw-r--r-- | neb/structs.py | 34 |
5 files changed, 97 insertions, 30 deletions
diff --git a/neb/__init__.py b/neb/__init__.py index 7296c58..0542d0d 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}") @@ -46,7 +59,8 @@ class Function: 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): @@ -82,8 +96,7 @@ class Function: ret.append(param) continue 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_}" @@ -146,9 +159,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) @@ -171,7 +186,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 @@ -179,15 +194,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 @@ -199,4 +215,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 1c3c4b4..d846498 100644 --- a/neb/std/core.py +++ b/neb/std/core.py @@ -201,9 +201,9 @@ def interpretType(symbol, args, env, ns): if not isinstance(args[1], TypeWrap): raise InterpretPanic(symbol, "parent must be a valid type", args[1]) - elif not env.contains(args[1].name): + elif not env.contains(args[1].name.name): raise InterpretPanic(symbol, f"no such type {args[1]}") - parent = env.get(args[1].name) + parent = env.get(args[1].name.name) func = args[2] if not isinstance(func, Function): diff --git a/neb/std/types.py b/neb/std/types.py index 872f29a..9cd8e6d 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"))) @@ -78,7 +97,8 @@ TYPES.register("handle?", Builtin("handle?", interpretIsHandle, [Arg("arg", Type 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) @@ -88,7 +108,8 @@ handle_type = NebType(":handle", any_type, interpretIsHandle) 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 8598344..1c5248c 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]}"' @@ -98,10 +99,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 :[]" +ALL_TYPES = {x: Type(x) for x in _native_types.split(" ")} class Symbol: def __init__(self, name, line): @@ -121,7 +132,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) + ")" @@ -130,7 +141,10 @@ class Arg: def __init__(self, name, type_, *, optional=False, lazy=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 self.lazy = lazy |
