nac3-spec/README.md

135 lines
4.6 KiB
Markdown
Raw Normal View History

2020-12-15 11:27:47 +08:00
# NAC3 Specification
2020-12-15 13:09:32 +08:00
Specification and discussions about language design.
2020-12-22 16:56:40 +08:00
A toy implementation is in [`toy-impl`](./toy-impl), requires python 3.9.
2020-12-17 14:52:51 +08:00
## Referencing Host Variables from Kernel
Host variable to be accessed must be declared as `global` in the kernel
function. This is to simplify and speed-up implementation, and also warn the
user about the variable being global. (prevent calling the interpreter many
times during compilation if there are many references to host variables)
2020-12-15 13:09:32 +08:00
Kernel cannot modify host variables, this would be checked by the compiler.
Value that can be observed by the kernel would be frozen once the kernel has
been compiled, subsequence modification within the host would not affect the
kernel.
2021-01-19 15:35:11 +08:00
Only types supported in the kernel can be referenced.
2020-12-15 13:09:32 +08:00
2020-12-15 17:33:31 +08:00
## Class and Functions
* Instance variables must be annotated: (Issue #1)
```python
2020-12-15 17:33:31 +08:00
class Foo:
a: int
b: int
def __init__(self, a: int, b: int):
self.a = a
self.b = b
```
* Three types of instance variables: (Issue #5)
* Host only variables: Do not add type annotation for it in the class.
* Kernel Invariants: Immutable in the kernel and in the host while the kernel
is executing. Type: `KernelInvariant(T)`. The types must be immutable.
(use tuple instead of list in the host, but the type annotation should still
be list?)
* Normal Variables: The host can only assign to them in the `__init__`
function. Not accessible afterwards.
2020-12-15 17:33:31 +08:00
* Functions require full type signature, including type annotation to every
parameter and return type.
```python
2020-12-15 17:33:31 +08:00
def add(a: int, b: int) -> int:
return a + b
```
* RPCs: optional parameter type signature, require return type signature.
* Function default parameters must be immutable.
* Function pointers are supported, and lambda expression is not supported
currently. (maybe support lambda after implementing type inference?)
2020-12-15 17:33:31 +08:00
2020-12-17 10:22:46 +08:00
## Built-in Types
* Primitive types include:
* `bool`
2020-12-17 14:52:24 +08:00
* `byte`
2020-12-17 10:22:46 +08:00
* `int32`
* `int64`
2020-12-17 10:27:11 +08:00
* `uint32`
* `uint64`
2020-12-17 10:22:46 +08:00
* `float`
* `str`
* `bytes`
2020-12-17 10:22:46 +08:00
* Collections include:
* `list`: homogeneous (elements must be of the same type) fixed-size (no
append) list.
* `tuple`: inhomogeneous immutable list, only pattern
matching (e.g. `a, b, c = (1, True, 1.2)`) and constant indexing is
supported:
2020-12-17 10:22:46 +08:00
```
t = (1, True)
# OK
a, b = t
# OK
a = t[0]
# Not OK
i = 0
a = t[i]
```
* `range` (over numerical types)
2020-12-17 10:22:46 +08:00
2020-12-17 14:52:24 +08:00
### Numerical Types
* All binary operations expect the values to have the same type.
2020-12-17 14:52:24 +08:00
* Casting can be done by `T(v)` where `T` is the target type, and `v` is the
original value. Examples: `int64(123)`
* Integers are treated as `int32` by default. Floating point numbers are double
by default.
* No implicit coercion, require implicit cast.
For integers that don't fit in int32, users should cast them to `int64`
explicitly, i.e. `int64(2147483648)`. If the compiler found that the integer
does not fit into int32, it would raise an error. (Issue #2)
2020-12-17 14:52:24 +08:00
* Only `uint32`, `int32` (and range of them) can be used as index.
2020-12-15 17:33:31 +08:00
## Generics
We use [type variable](https://docs.python.org/3/library/typing.html#typing.TypeVar) for denoting generics.
2020-12-15 13:09:32 +08:00
2020-12-15 17:33:31 +08:00
Example:
```python
2020-12-15 17:33:31 +08:00
from typing import TypeVar
T = TypeVar('T')
2020-12-15 13:09:32 +08:00
class Foo(EnvExperiment):
@kernel
2020-12-15 17:33:31 +08:00
# type of a is the same as type of b
def run(self, a: T, b: T) -> bool:
return a == b
2020-12-15 13:09:32 +08:00
```
2021-01-19 15:35:11 +08:00
* Type variable can be limited to a fixed set of types.
2020-12-15 17:33:31 +08:00
* Type variables are invariant, same as the default in Python. We disallow
covariant or contravariant. The compiler should mark as error if it encounters
a type variable used in kernel that is declared covariant or contravariant.
* Code region protected by a type check, such as `if type(x) == int:`, would
treat `x` as `int`, similar to how [typescript type guard](https://www.typescripttutorial.net/typescript-tutorial/typescript-type-guards/) works.
```python
2020-12-15 17:33:31 +08:00
def add1(x: Union[int, bool]) -> int:
if type(x) == int:
# x is int
return x + 1
else:
# x must be bool
return 2 if x else 1
```
* Generics are instantiated at compile time, all the type checks like
`type(x) == int` would be evaluated as constants. Type checks are not allowed
in area outside generics.
2021-01-19 15:35:11 +08:00
* Type variable cannot occur alone in the result type, i.e. must be bound to the
input parameters.
2020-12-15 17:33:31 +08:00
Questions:
* Should we support things like optional type? (like the one in rust)
* Would it be better to assert on the type variable directly instead of
`type(x)` for type guards?
## Lifetime
Probably need more discussions...
2020-12-15 11:27:47 +08:00