Replies: 1 comment 1 reply
-
Standalone type declarations are creating
typedLamda and typedSelectorLamda does not act differently than ordinary lambda in terms of argument application. So we can say there is a typeOf function on type (identity), value, typedLambda, and typedSelectorLambda. Ordinary lambdas should return error on typeOf. And type namespace for type declarations is just a temporary residence for forward declarations. Keywords: typeOf, typedLambda, typedSelectorLamda. Now steps to full typed module declaration becomes only 2 steps
To think for the future. There is a difference in constructors and functions to be selectors. Both in stdLib internal implementation and in the syntax (when we introduce modules to users) there has to be a difference. For example, we should prefix normal functions with constructor/function keyword and leave the selectors as the default. Like:
Of course with the constructor keyword the first thing that comes to my mind is that there might be other normal functions in a module that should not be selectors. Just some utility functions. So what is the right way of expressing them?
|
Beta Was this translation helpful? Give feedback.
-
Error locations
If you were writing a C compiler then you would simply wrap blocks of generated machine code with an exception handler that adds error location.
We will do the same. We will wrap function calls with a location updater.
doSth->onError( err->addLocation(aLocation) )
Only function calls need to have locations.
What about type errors on arguments? Now, that's a different story
Types
Let's say add: float=>float=>float
if we are calling
add(1., "a")
then we can apply argument types with location the type calculus at the moment is((float=>float=>float) float string)
We just need to add locations to the apply operator
apply( apply((float=>float=>float)) float locations) string location2)
Which reduces to
apply( (float=>float) string location2)
Which reduces to
"float expected at location 2"
It is really trivial to generate a type checking pass once everything has a strong type. Once library functions has all strong types, user functions will have strong types also because of simple type calculus.
Easy but this does not fit the current implementation
add@location1 1@location2, "2"@location3
which has to produce 3@location1 instead of just 3. This motivates me to keep error locations coarse and have a type checking pass in the future.Therefore
Type checking pass
Type checking pass is becoming the core of the module implementation.
Let's say we have rescript calling ability from Squigle and type declarations. Let's define add:
add(a: float, a: float): float = rescriptFFI{ a + b }
Here you have defined add as a function selector and a add_float_float function.
The typechecker replaces add with add_float_float based on the argument types during the type checking pass.
For now, until there is a type checking pass, I will insert this call to function calls (to be removed when there is a type checking pass).
So that function selectors will be replaced by actual function on call for now.
Here I relied on 2 features
I observe that without the type checking pass, the code is becoming redundant and heavy.
** More on error locations **
Most of the time errors are not happening in current source code executing. Therefore I propose to have a new evaluate interface
evaluate2(<project>, <sourceId>)
Using sourceId@project instead of source code text.
This guarantees that everything imported or continued has an unmistakable location.
You might naively think that evaluate(, sourceCode) would be a smart workaround but I see many disadvantages. It's open to weird errors. And project has other advantages
Project
A project contains s indexed with . It is a simple stupid collection. But in addition we can hang more things to the project to optimize code more.
To enable easy wiping out we can define some simple functions
Once we have the project, we don't have to use an evaluate with bindings. It's there in the project. In fact, I can switch to use a continuation instead of converting bindings from typescript which are converted from rescript all the time. Bindings need to be converted only one way for viewing. Furthermore, there wont be the issue of merging standard library multiple times. When type modules are implemented, to-from-converting them will be massive. And as bindings are for viewing with the project, we don't have to export standard library at all inside them. In fact, we can add export filters to decrease further heavy traffic.
Anyway, this is a roadmap. But for the immediate future:
evaluate2(<project>, <sourceId>)
and spice it with function call error location.The project will be an nice agreement point on file imports/includes also. Import a file? Hang it to the project and don't worry about execution.
Beta Was this translation helpful? Give feedback.
All reactions