aboutsummaryrefslogtreecommitdiff
path: root/neb
diff options
context:
space:
mode:
Diffstat (limited to 'neb')
-rw-r--r--neb/__init__.py11
-rw-r--r--neb/lexer.py8
-rw-r--r--neb/parser.py4
-rw-r--r--neb/std/core.py32
-rw-r--r--neb/std/types.py16
-rw-r--r--neb/structs.py1
-rw-r--r--neb/typeclass.py1
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()}"