This checklist containts only major changes and updates, for minor changes and updates, please refer to the commit history.
-
13/03/2024:
- Finding common types for multiple datatypes
typeinference.ts:findCompatibleTypes
- Casting generic types to specific types, such as getting an interface from a reference or an interface from a join types, using
DataType.is(InterfaceType)
, andDataType.to(InterfaceType)
, these functions are implemented internally to return and perform the appropriate casting. - Basic implementation of cloning for declared functions, etc.
- Finding common types for multiple datatypes
-
13/03/2024:
- Infer functions for some expressions
- MetaTypes (also known as RawTypes in the old compiler), which holds enums, classes, interfaces, variants and variant consturctors
- New method
allowNullable
, which indicates that a datatype is allowed to be wrapped within aNullable
class. For example Classes, interfaces, struct, variants can be nullables. - New method
Expression.checkHint
used to compare the hint with the inferred type of the expression, since the check is very repetitive.
-
14/03/2024:
- Removed auto returning
inferredType
when set, from within expression, when we re-infer function return expression, the hint is not set and type checks are not performed since it auto-returns first thing during inference. One solution is to not infer return statements expressions, gotta investigate!
- Removed auto returning
-
17/03/2024:
Context.addSymbol
now sets theparentContext
of the symbol added, if a symbol is imported,Context.addExternalSymbol
is used instead, which does not set theparentContext
of the symbol added.ReferenceType
now requires attributeusageContext
, which points the context in which the reference is used, and Not where the reference is declared!- Since generic class methods do not support overloading, the method
ClassType.getGenericMethodByName(name: string)
has been introduced and used inFunctionCallExpression
to get the generic method to be called.
-
18/03/2024:
- Variant constructors are matched based not only on name and argument but at their position within the parent.
-
20/03/2024:
- Added
getGenericParameters(ctx: Context, originalType: DataType, declaredGenerics: {[key: string]: GenericType}): {[key: string]: DataType}
which returns the list of generic types with a compound type, this is used withinClassType.getMethodBySignature
to create concrete method from generic method and a given signature. It makes sure that redudant generic usages are consistent and throws error on failure
- Added
-
28/03/2024:
- Removed processes concept from the language.
- Added
locks
andpromises
as builtin types. - Class checking is now based on location, until a better solution comes up
getMethodBySignature
now also takes type arguments, so it can infer generics when not present, or just clone the methods when they are present.
-
04/03/2024:
- Context has
uuid
and it assigns auid
to all symbols it owns. ClassMethod
,LambdaExpression
andDeclaredFunction
now have an attributecodeGenProps: FunctionCodegenProps
, which contains all symbols (locals, arguments and upvalues) of that function to be used for code gen. This field is filled when theElement
(terminal expression) is being resolved throughlookupScope
, and this new classFunctionCodegenProps
is used to report unused arguments in the function.- Added a field
wasInferred
toDeclaredFunction
instances to avoid inferring non-generic function declaration multiple times.
- Context has
-
04/04/2024:
- During
FunctionCallExpression
inference, if the LHS is an element, the arguments are inferred asnull
hint and the fieldinferredArgumentsTypes: DataType[] | undefined = undefined
is set for the element. If the element is a generic function call, and has no type arguments, generics are extracted from theinferredArgumentsTypes
field (similar to class methods). - ~~ (old) Fix cloning of variable declarations and function declarations, also cloning scopes doesn't copy the symbols anymore. It only copies variables and functions since these are static and already set by the parser.~~
inferredArgumentsTypes
is only set inFunctionCallExpression
only when lhs is an element and has no generic parameters. Next is to only set it if the LHS is generic and has no type arguments.- Now we infer the arguments of generics only if the function being called is generic and has no type arguments, otherwise we use the type arguments provided.
- Lambda expressions now have a symbol attached to them to be registered in global context
- During
-
13/04/2024:
- Originally, variables and functions are added to their parent context during parsing. This behavior has been changed, they are now added to the context when their respective declaration statement is being resolved. This makes context cloning simpler, since we init the cloned context with empty symbols, the symbols will be added when the declaration is resolved when resolving the parenting cloned statement/expr.
-
29/07/2024:
- Added Tuple data type.
-
5/08/2024:
- Added destructuring assignment for tuples, structs and arrays.
-
6/08/2024:
- Added
external
attribute to symbols, to mark if a symbol is external or not. Was a bug that resulted in external symbols added to the global context and having their IR generated twice (one from original and one from context that imported it). - Added
getAllMethods
andbuildAllMethods
toClassType
to build all methods for a class, including the implemenation of all generic methods static and not.
- Added
-
8/08/2024:
- Added
DoExpression
- Added
-
10/08/2024:
- Refactored bytecode for structs, a global id for every field is generated, covering all combinations, this global id is used to access the field in the struct, using an additional offset byte.
- Refactored bytecode for classes and interfaces. VM now only supports classes. Class methods are processed the same way as structs now, each method has a global id.
- class to interface now is direct, interface to interface is now done through new
i_has_m
bytecode instruction, which checks if the class has the method.
-
12/08/2024:
- Isolated static methods, so static methods are stored in the base class type, not classes that are concrete implementations of that class.
- Static methods now support generics.
-
13/08/2024:
- This is a reminder for me to differentiate between anonymous types and named types! this needs to be modeled properly, to generate proper errors and start working on types layouts in the bytecode.
-
17/08/2024:
- This expression now added recusively upwards, as an upvalue (obviously not added to the method itself, but any function/lambda within the class method)
- Any anonymous function now is treated as a closure, and is generated as a closure.
- Closures are finally here!
-
22/08/2024:
- Implemented coroutine functions, to declare coroutine functions that be instatiated into coroutine objects. Coroutine functions are same as regular functions, but are not called directly, because they must yield values back to the caller. They are declared with
fn
orcfn
keyword, but from a compiler perspective they are of typecfn
. - Coroutine Callable Functions now ends with
throw_rt
instruction, which is used to throw an error when coroutine reaches end of execution and has not yielded any value.
- Implemented coroutine functions, to declare coroutine functions that be instatiated into coroutine objects. Coroutine functions are same as regular functions, but are not called directly, because they must yield values back to the caller. They are declared with
-
8/11/2024:
- Updated class, struct and array instructions to include bitmask for which fields are pointers.
-
10/11/2024:
- Fixed a flaw with pointer bitmaps. Pointer fields in structs and classes are now specified when registering the field.
- Changed instructions again, we do not create pointer bitmask on creating object but on every *_reg_field. Array still unchanged (ptr flag given in a_alloc).
-
16/11/2024:
- Fixed const/mut analysis
- Added
mutate
expression, which is used to mutate a variable.
-
23/11/2024:
- Added namespaces, local symbols and namespace imports
- Namespaces variables are pushed in the base package, and generated in the bytecode same as global variables.
-
24/11/2024:
- Added
impl
datatype, for reusability and more modular behavior of classes.
- Added
-
25/11/2024:
- Fixed issues with static variables/methods and blocks
- Static variables are stored and read as global variables, also pushed in the base package global context.
- Static block are now properly generated just like global block. They are also pushed in the base package global context.
- Small fixes for class methods and attributes in the bytecode generator when nested under namespaces and invalid access of non-static method through the class name (instead of through an instance).
- Added special assignment for
ThisExpression
in the form ofThisDistributedAssignExpression
, which allows for distributed assignment to the attributes ofthis
, such asthis += {x, y, z}
orthis += {a: x, b: y, c: z}
. Only works withthis
. Does not translate to creating a new struct, it extract field names and values from the RHS and translates it to a series of assignments. - Added special index_rset which sets the value of an index of an array-like object, but in reverse order of index_get, such as
x[-3]
, Evaluates to__index_rset__(x, 3, value)
. This is important because value is not evaluated as a negative number, the negative sign within an index[]
translates to a reverse index access. - Added
override
keyword to class methods, to indicate that the method is overriding an external method with the same signature.
-
04/12/2024:
- Eytzinger layout for structs and variants and class methods
- Variants now have a $tag field which is always UID 0 and variant field UIDs share same pool as struct fields.
-
07/12/2024:
- Reverted back to binary search, after some benchmarking
-
13/12/2024:
- Added
foreach
statement, which iterates over an array or a struct. - Added
Context.InferenceMode
which refers to the mode of the compiler, whether it is in inference mode or code generation mode. Incodegen
mode, some errors are skipped because the codegen will refactor the AST and might endup revisiting some var decls etc.
- Added
-
Allow class attributes (both static and not static) to be immutable, and can only be set from within the constructor.
-
Address the issue of non-inferred expressions suchas expressions as arguments to method call.
dt.callMe({"user", 20})
In such case, the compiler will not infer the unnamed struct construction
{"user", 20}
with the method argument, due to method overload resolution.
- Pad constants segment
- Pad global segment for faster access
- Add Short-circuiting logical operators and nullish coalescing operator (codegen)
- Implement Nullish coalescing operator as a binary operator, will require additional parameter to
expresion.infer
so when we encounter nullable member access we can accept it knowing that there is a fallback value:a?.b ?? 0
. -
Add language level support for threads -
Add support Shadow Classes (requires VM integration too) - Infer generic method call without exilicitly specifying the generic types (from within
FunctionCallExpression
) - Bytecode generation
- Pad structs in the VM, for faster CPU access
bytecode generation for pattern matching uses primitive types such as array slicing in case
[x, y, ...rest]
Inorder to allow matching over custom types, we need to add custom overloads for pattern matching, for instance for array matching we need the index access override and a custom slice implementation.
Maybe even a built-in range class? like python x[0:3] -> x[Range(0, 3)] by overloading the index access operator.
Lots of potential work here, but also low priority.
if we can create "templates" for types, we can then use local index instead of global offset for structs, interfaces and classes. Hence we can avoid searching for index within the globalIndex table.
For each defined type, we add it to the template segment, each object will then be created based on that template (it has predefined index for its fields), and we can then use that index. Each struct/class/interface/variant will need to have an ID referencing the template ID used to create it.
When generating bytecode, we will need instruction to fetch data from local index instead of global index.