-
Notifications
You must be signed in to change notification settings - Fork 0
/
todo.txt
89 lines (66 loc) · 3.42 KB
/
todo.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
# Ideas
## String type
Prerequisites for built-in string type:
* alloc(), or C malloc()
* pointer arithmetic? *a = 0
## Programmable lifetime
Let the programmer tell the compiler explicitly where a specific type of
object lives and dies in the code.
- How would the lifetime annotation look like?
## 'match' syntax in function(method) declaration
Similar to how functional languages like Haskell allow function declaration
to be spread over specific instances of argument patterns, allow methods to
be declared with different 'self' pattern matches, so that "virtual" method
calls are defined clearly in syntax. The performance characteristics of such
method calls now become clear because they use the same codegen as matches.
## Specify lifetime between struct parameters?
E.g. Source, Parser, Lexer all in a single Driver struct, but their
construction/destruction order is guaranteed.
## Compiler UI that reports if a function (or an arbitrary snippet of
code) allocates on the heap or not.
E.g. give it a variable name or a file:line:col, and it should tell you where
that variable resides on the memory.
- For code that just calls into another code, it might need deep call chain
analysis.
- This can be solved if we annotate all functions with the allocation
analysis result to begin with.
- Is this a job for a debugger though?
## Out-of-module extensible structs
E.g. enums should be allowed to have user defined methods.
Q. What's the advantage of separating type table from decl table?
- How to handle built-in types?
Push them to the decl_table at the global scope? But then, after the global
scope is deleted, their type objects may become unaccessible.
Does this matter? What if we maintain the decl_table to be alive for the
whole lifetime of the compiler?
Or, we can make some dangling AST nodes with names of 'int', 'bool' and such
and hold the pointers to the Types in those. But this seems messy.
- Simple CLI for displaying symantic informations about a decl on a specific
file:line location, e.g.
./qc -sema 'test_sema.txt:17:a'
- What do I index the symbol table with?
Name? How do we name types?
Maybe only store canonical types, and make new Type objects for each
ref/array types?
- But then we would waste heap memory unless we store the whole Type object
in AST nodes. Small sizeof(Type) would become a requirement.
- We do declaration/name binding and type checking in one pass. These should
be separated into different passes.
(??) Declaration and name binding should be in the same pass, because
otherwise we can't catch use-before-declaration errors in the same scope.
For example:
{
a = 3; // 'a' undeclared
...
var a: int;
}
Maybe we can only check the decl table for each variable use, and name bind
them later in a separate pass. But I'm not sure that's got any advantage.
- What about use of declarations that are declared in other files/modules? We
need multiple passes for this one. In this case, *every* identifier can
potentially be a use of a external declaration, and we cannot emit any
use-before-declaration error in the first pass.
A: This can be prevented by mandating explicit syntax for use of external
declarations, e.g. 'module.variable', similar to what Go does. Simple 'a'
can only refer to either (1) local variables/function args, or (2) file-local
constants.