Princess-org / Princess

Princess language repository
MIT License
24 stars 2 forks source link

Unify Types and Expressions #31

Open Victorious3 opened 1 year ago

Victorious3 commented 1 year ago

Right now the parsing of types and expressions is entirely separate. It is possible to resolve a type inside of an expression by using the type keyword, this makes it possible to pass types such as references to a generic function accepting a type.

def for_type(type T)

for_type(type &int)
for_type(type *int)

Since the type is resolved during typechecking it knows that the subtree is supposed to be a type anyways. If expressions and types weren't separate you could leave out the superfluous type keyword.

The other problem is that as it stands right now, there is no way to parse an expression inside of a type context. Therefore it is not possible for a (compile time) function or macro to return a type. Doing this would necessitate another keyword (like consteval) in order to embed an expression inside of a type.

The real solution would be to leave the interpretation of a specific subtree up to the typechecker. That means in practice that the prefix operators & type and * type as well as [type], def (type) -> (type) and type | type become proper operators and get parsed as such, instead of resolving to FUNCTION_T, etc right away.

() -> () would clash with (proposed) lambda functions, so those would need a fat arrow => instead. Although it might be possible to infer it from context again.

This should be decided on soon because it will influence the way the language evolves in the future.

Victorious3 commented 1 year ago

This also fixes that case: 10 !uint | 20 Right now the types bind higher than anything else, but with ! having a higher precedence than |, this can be parsed as (10 ! uint) | 20 which is probably what was intended.