diff options
| author | mryouse | 2022-06-22 04:03:13 +0000 |
|---|---|---|
| committer | mryouse | 2022-06-22 04:03:13 +0000 |
| commit | 810d01108110901a290aa4d4a9cdf96187430d0d (patch) | |
| tree | 4d8b1142e70b0c08426644ac35319febacb88228 | |
| parent | 7e69cf2d253ba12055b827c584380438e2e0a70f (diff) | |
initial commit of user defined types!
| -rw-r--r-- | neb/__init__.py | 11 | ||||
| -rw-r--r-- | neb/lexer.py | 8 | ||||
| -rw-r--r-- | neb/parser.py | 4 | ||||
| -rw-r--r-- | neb/std/core.py | 32 | ||||
| -rw-r--r-- | neb/std/types.py | 16 | ||||
| -rw-r--r-- | neb/structs.py | 1 | ||||
| -rw-r--r-- | neb/typeclass.py | 1 |
7 files changed, 54 insertions, 19 deletions
diff --git a/neb/__init__.py b/neb/__init__.py index c505a04..16d5e44 100644 --- a/neb/__init__.py +++ b/neb/__init__.py @@ -143,11 +143,10 @@ class UserFunction(Function): args.append(Arg(param.name, TypeEnum.ANY)) prev_type = False elif isinstance(param, Type) and not prev_type and not first: - typ = TypeEnum.__getattr__(param.name[1:].upper()) if many is None: - args[-1].type_ = typ + args[-1].type_ = param.name else: - many.type_ = typ + many.type_ = param.name prev_type = True else: raise NebPanic("invalid :func signature", param) @@ -164,7 +163,6 @@ class UserFunction(Function): # if we got "many", wrap the rest in a list if self.many: this_env.register(self.many.name, List(evaluated_args[len(self.params):])) - return interpret(self.body, env=this_env, ns=ns) @@ -176,7 +174,10 @@ class TypeWrap: self.is_func = is_func def validate_type(self, target, env, ns): - valid = self.is_func(None, [target], env, ns) + # if it's an any type, it's valid + if self.parent is None: + return Bool(True) + valid = self.is_func.call(List([None, target]), env, ns) if valid.value == True: return valid parent_type = env.get(f"{target.type_}") diff --git a/neb/lexer.py b/neb/lexer.py index b522460..22a9710 100644 --- a/neb/lexer.py +++ b/neb/lexer.py @@ -162,7 +162,9 @@ def get_type(data, line): counter += 1 if counter >= len(data): break - if value not in types: - raise LexError(f"unrecognized type {value}", line) - return Token(types[value], value, None, line), counter - 1 + if value in types: + typ = types[value] + else: + typ = TokenType.USER_TYPE + return Token(typ, value, None, line), counter - 1 diff --git a/neb/parser.py b/neb/parser.py index 8129fc9..5352ee5 100644 --- a/neb/parser.py +++ b/neb/parser.py @@ -13,7 +13,7 @@ def parseExpression(token, prev, tokens): elif token.type_ in (TokenType.STRING, TokenType.TRUE, TokenType.FALSE, TokenType.INT, TokenType.FLOAT): expr, inc = parseLiteral(token, prev, tokens[idx+1:]) args.append(expr) - elif token.type_ in (TokenType.INT_TYPE, TokenType.FLOAT_TYPE, TokenType.STRING_TYPE, TokenType.ANY_TYPE, TokenType.LIST_TYPE, TokenType.NUMBER_TYPE, TokenType.BOOL_TYPE, TokenType.LITERAL_TYPE): + elif token.type_ in (TokenType.INT_TYPE, TokenType.FLOAT_TYPE, TokenType.STRING_TYPE, TokenType.ANY_TYPE, TokenType.LIST_TYPE, TokenType.NUMBER_TYPE, TokenType.BOOL_TYPE, TokenType.LITERAL_TYPE, TokenType.USER_TYPE): expr, inc = parseType(token, prev, tokens[idx+1:]) args.append(expr) else: @@ -55,7 +55,7 @@ def parse(tokens): elif token.type_ in (TokenType.FALSE, TokenType.TRUE, TokenType.STRING, TokenType.INT, TokenType.FLOAT): lit, counter = parseLiteral(token, prev, tokens[idx+1:]) exprs.append(lit) - elif token.type_ in (TokenType.INT_TYPE, TokenType.FLOAT_TYPE, TokenType.STRING_TYPE, TokenType.ANY_TYPE, TokenType.LIST_TYPE, TokenType.NUMBER_TYPE, TokenType.BOOL_TYPE, TokenType.LITERAL_TYPE): + elif token.type_ in (TokenType.INT_TYPE, TokenType.FLOAT_TYPE, TokenType.STRING_TYPE, TokenType.ANY_TYPE, TokenType.LIST_TYPE, TokenType.NUMBER_TYPE, TokenType.BOOL_TYPE, TokenType.LITERAL_TYPE, TokenType.USER_TYPE): typ, counter = parseType(token, prev, tokens[idx+1:]) exprs.append(typ) else: diff --git a/neb/std/core.py b/neb/std/core.py index 8881468..83b164c 100644 --- a/neb/std/core.py +++ b/neb/std/core.py @@ -1,4 +1,4 @@ -from .. import TypeEnum, Environment, Arg, Builtin, UserFunction, evaluate, interpret, parse, lex, InterpretPanic +from .. import TypeEnum, Environment, Arg, Builtin, UserFunction, evaluate, interpret, parse, lex, InterpretPanic, TypeWrap, Function, UserType from ..structs import * from pathlib import Path @@ -182,3 +182,33 @@ def interpretEval(symbol, args, env, ns): eval_arg = Arg("arg", TypeEnum.ANY) CORE.register("eval", Builtin("eval", interpretEval, [eval_arg])) + +def interpretType(symbol, args, env, ns): + # (type typename parent func) + if not isinstance(args[0], Type): + raise InterpretPanic(symbol, "types must begin with a colon") + name = args[0].name # NOTE: we are not evaluating the name!! + + # TODO we may need to do namespace things here + # also, we probably shouldn't be able to rename types + + if not isinstance(args[1], TypeWrap): + raise InterpretPanic(symbol, "parent must be a valid type", args[1]) + elif not env.contains(args[1].name): + raise InterpretPanic(symbol, f"no such type {args[1]}") + parent = env.get(args[1].name) + + func = args[2] + if not isinstance(func, Function): + raise InterpretPanic(symbol, "validation must be a :func", func) + + new_type = UserType(name, parent, func) + env.register(name, new_type) + return List([]) + +type_name_arg = Arg("name", TypeEnum.ANY, lazy=True) +type_parent_arg = Arg("name", TypeEnum.ANY) +type_func_arg = Arg("func", TypeEnum.ANY) +CORE.register("type", Builtin("type", interpretType, [type_name_arg, type_parent_arg, type_func_arg])) + + diff --git a/neb/std/types.py b/neb/std/types.py index b5fb993..855a1d9 100644 --- a/neb/std/types.py +++ b/neb/std/types.py @@ -70,14 +70,14 @@ def interpretIsLiteral(symbol, args, env, ns): TYPES.register("literal?", Builtin("literal?", interpretIsLiteral, [Arg("arg", TypeEnum.ANY)])) # add types to env -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) -bool_type = NebType(":bool", literal_type, interpretIsBool) -number_type = NebType(":number", literal_type, interpretIsNumber) -int_type = NebType(":int", number_type, interpretIsInt) -float_type = NebType(":float", number_type, interpretIsFloat) +any_type = NebType(":any", None, Builtin("any?", interpretIsAny, [Arg("arg", TypeEnum.ANY)])) +literal_type = NebType(":literal", any_type, Builtin("literal?", interpretIsLiteral, [Arg("arg", TypeEnum.ANY)])) +string_type = NebType(":string", literal_type, Builtin("string?", interpretIsString, [Arg("arg", TypeEnum.ANY)])) +list_type = NebType(":list", any_type, Builtin("list?", interpretIsList, [Arg("arg", TypeEnum.ANY)])) +bool_type = NebType(":bool", literal_type, Builtin("bool?", interpretIsBool, [Arg("arg", TypeEnum.ANY)])) +number_type = NebType(":number", literal_type, Builtin("number?", interpretIsNumber, [Arg("arg", TypeEnum.ANY)])) +int_type = NebType(":int", number_type, Builtin("int?", interpretIsInt, [Arg("arg", TypeEnum.ANY)])) +float_type = NebType(":float", number_type, Builtin("float?", interpretIsFloat, [Arg("arg", TypeEnum.ANY)])) TYPES.register(":any", any_type) TYPES.register(":literal", literal_type) diff --git a/neb/structs.py b/neb/structs.py index f3bdb36..1cb2adc 100644 --- a/neb/structs.py +++ b/neb/structs.py @@ -40,6 +40,7 @@ class TokenType(Enum): LIST_TYPE = auto() LITERAL_TYPE = auto() BOOL_TYPE = auto() + USER_TYPE = auto() MANY = auto() diff --git a/neb/typeclass.py b/neb/typeclass.py index eae412c..9e37a2d 100644 --- a/neb/typeclass.py +++ b/neb/typeclass.py @@ -9,6 +9,7 @@ class TypeEnum(Enum): LIST = auto() LITERAL = auto() BOOL = auto() + USER = auto() def __str__(self): return f":{self.name.lower()}" |
