Fix: doc comments cannot be used in method defs

This commit is contained in:
Shunsuke Shibayama 2023-01-27 09:46:59 +09:00
parent d6bbb91015
commit 0019147007
7 changed files with 108 additions and 43 deletions

View file

@ -1478,7 +1478,7 @@ impl ASTLowerer {
errs
})?;
}
ast::ClassAttr::Decl(_decl) => {}
ast::ClassAttr::Decl(_) | ast::ClassAttr::Doc(_) => {}
}
}
for attr in methods.attrs.into_iter() {
@ -1499,6 +1499,14 @@ impl ASTLowerer {
self.errs.extend(errs);
}
},
ast::ClassAttr::Doc(doc) => match self.lower_literal(doc) {
Ok(doc) => {
hir_methods.push(hir::Expr::Lit(doc));
}
Err(errs) => {
self.errs.extend(errs);
}
},
}
}
if let Err(errs) = self.module.context.check_decls() {
@ -1597,7 +1605,7 @@ impl ASTLowerer {
errs
})?;
}
ast::ClassAttr::Decl(_decl) => {}
ast::ClassAttr::Decl(_) | ast::ClassAttr::Doc(_) => {}
}
}
for attr in methods.attrs.into_iter() {
@ -1618,6 +1626,14 @@ impl ASTLowerer {
self.errs.extend(errs);
}
},
ast::ClassAttr::Doc(doc) => match self.lower_literal(doc) {
Ok(doc) => {
hir_methods.push(hir::Expr::Lit(doc));
}
Err(errs) => {
self.errs.extend(errs);
}
},
}
}
if let Err(errs) = self.module.context.check_decls() {

View file

@ -748,7 +748,12 @@ impl ValueObj {
pub fn from_str(t: Type, content: Str) -> Option<Self> {
match t {
Type::Int => content.replace('_', "").parse::<i32>().ok().map(Self::Int),
Type::Nat => content.replace('_', "").parse::<u64>().ok().map(Self::Nat),
Type::Nat => content
.trim_start_matches('-') // -0 -> 0
.replace('_', "")
.parse::<u64>()
.ok()
.map(Self::Nat),
Type::Float => content
.replace('_', "")
.parse::<f64>()

View file

@ -727,11 +727,12 @@ impl_locational_for_enum!(Dict; Normal, Comprehension);
pub enum ClassAttr {
Def(Def),
Decl(TypeAscription),
Doc(Literal),
}
impl_nested_display_for_enum!(ClassAttr; Def, Decl);
impl_display_for_enum!(ClassAttr; Def, Decl);
impl_locational_for_enum!(ClassAttr; Def, Decl);
impl_nested_display_for_enum!(ClassAttr; Def, Decl, Doc);
impl_display_for_enum!(ClassAttr; Def, Decl, Doc);
impl_locational_for_enum!(ClassAttr; Def, Decl, Doc);
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct ClassAttrs(Vec<ClassAttr>);

View file

@ -287,6 +287,9 @@ impl Desugarer {
let expr = desugar(*decl.expr);
new_attrs.push(ClassAttr::Decl(expr.type_asc(decl.op, decl.t_spec)));
}
ClassAttr::Doc(doc) => {
new_attrs.push(ClassAttr::Doc(doc));
}
}
}
let new_attrs = ClassAttrs::from(new_attrs);

View file

@ -984,6 +984,7 @@ impl Parser {
let first = match first {
Expr::Def(def) => ClassAttr::Def(def),
Expr::TypeAsc(tasc) => ClassAttr::Decl(tasc),
Expr::Lit(lit) if lit.is_doc_comment() => ClassAttr::Doc(lit),
_ => {
// self.restore();
let err = self.skip_and_throw_syntax_err(caused_by!());

View file

@ -8,7 +8,7 @@ Please think that the parts not mentioned are the same as Python.
## Basic calculation
Erg has a strict type. However, types are automatically casting if subtypes due to the flexibility provided by classes and traits (see [API] for details).
Erg has a strict type. However, types are automatically casting if subtypes due to the flexibility provided by classes and traits (see [API](../API) for details).
In addition, different types can be calculated for each other as long as the type is a numeric type.
@ -20,16 +20,16 @@ d = c * 0 # -0.0: Float
e = f // 2 # 0: Nat
```
If you do not want to allow these implicit type conversions, you can specify the type at declaration time to detect them as errors at compile time.
If you do not want to allow unexpected type widening, you can specify the type at declaration time to detect them as errors at compile time.
```python
a = 1
b: Int = a / 2
# error message
Error[#0047]: File <stdin>, line 1, in <module>
2│ b: Int = int / 2
2│ b: Int = a / 2
^
TypeError: the type of ratio is mismatched:
TypeError: the type of b is mismatched:
expected: Int
but found: Float
```
@ -48,7 +48,7 @@ False == 0.0 # NG
True == "a" # NG
```
## variables, constants
## Variables, constants
Variables are defined with `=`. As with Haskell, variables once defined cannot be changed. However, it can be shadowed in another scope.
@ -61,6 +61,7 @@ assert i == 0
Anything starting with an uppercase letter is a constant. Only things that can be computed at compile time can be constants.
Also, a constant is identical in all scopes since its definition.
This property allows constants to be used in pattern matching.
```python
PI = 3.141592653589793
@ -110,11 +111,13 @@ i.update! x -> x + 1
assert i == 1
```
## procedures
## Procedures
Subroutines with side effects are called procedures and are marked with `!`.
Functions are subroutines that do not have side effects (pure).
You cannot call procedures in functions.
This explicitly isolates side effects.
```python
print! 1 # 1
@ -166,9 +169,9 @@ assert foo.x == 1
foo.y # VisibilityError
```
## pattern matching
## Pattern matching
### variable pattern
### Variable pattern
```python
# basic assignments
@ -197,7 +200,7 @@ fib1 = 1
fibn: Nat = fibn-1 + fibn-2
```
### constant pattern
### Constant pattern
```python
PI = 3.141592653589793
@ -209,7 +212,7 @@ name = match num:
_ -> "unnamed"
```
### discard (wildcard) pattern
### Discard (wildcard) pattern
```python
_ = 1
@ -222,9 +225,9 @@ right(_, r) = r
Used in combination with the tuple/array/record pattern described later.
```python
[i,...j] = [1, 2, 3, 4]
[i, *j] = [1, 2, 3, 4]
assert j == [2, 3, 4]
first|T|(fst: T, ...rest: T) = fst
first|T|(fst: T, *rest: T) = fst
assert first(1, 2, 3) == 1
```
@ -237,17 +240,17 @@ assert first(1, 2, 3) == 1
m, n = 1, 2
```
### array pattern
### Array pattern
```python
length[] = 0
length[_, ...rest] = 1 + lengthrest
length [] = 0
length [_, *rest] = 1 + lengthrest
```
#### record pattern
#### Record pattern
```python
{sin; cos; tan; ...} = import "math"
{sin; cos; tan} = import "math"
{*} = import "math" # import all
person = {name = "John Smith"; age = 20}
@ -270,11 +273,20 @@ Point::{x; y} = p
odds = [i | i <- 1..100; i % 2 == 0]
```
## class
## Class
Erg does not support multiple/multilevel inheritance.
Erg does not support multiple inheritance.
## Traits
Classes are non-inheritable by default, and you must define inheritable classes with the `Inheritable` decorator.
```python
@Inheritable
Point2D = Class {x = Int; y = Int}
Point3D = Inherit Point2D, Base := {x = Int; y = Int; z = Int}
```
## Trait
They are similar to Rust traits, but in a more literal sense, allowing composition and decoupling, and treating attributes and methods as equals.
Also, it does not involve implementation.
@ -291,11 +303,19 @@ Point.
...
```
## patch
## Patch
You can give implementations to classes and traits.
You can retrofit a class or trait with an implementation.
## Refinement type
````python
Invert = Patch Bool
Invert.
invert self = not self
assert False.invert()
````
## Refinement types
A predicate expression can be type-restricted.

View file

@ -12,7 +12,7 @@
ergプログラムは、コンパイル時にすべて厳密に型付けされています。しかし、型はクラスやトレイトによって部分型であると判断できる場合には自動的にキャスティングされます(詳細については[Num](../API/types/traits/Num.md)を参照してください)。
よって、例えば数値型であれば異なる型同士で計算をすることもできます。
よって、例えば数値型であれば異なる型同士で計算をすることもできます。
```python
a = 1 # 1: Nat(Int)
@ -22,16 +22,16 @@ d = c * 0 # -0.0: Float
e = f // 2 # 0: Nat(Int)
```
これら暗黙的な型の変換を許容したくない場合には宣言時に型を指定することでコンパイル時にエラーとして検出できます。
意図しない型の拡大を許容したくない場合には、宣言時に型を指定することでコンパイル時にエラーとして検出できます。
```python
a = 1
b: Int = a / 2
# error message
Error[#0047]: File <stdin>, line 1, in <module>
2│ b: Int = int / 2
2│ b: Int = a / 2
^
TypeError: the type of ratio is mismatched:
TypeError: the type of b is mismatched:
expected: Int
but found: Float
```
@ -40,9 +40,9 @@ but found: Float
True、Falseは真偽値型のシングルトンですが、整数型を汎化型として持ちます。
そのため、整数型や整数の部分型にあたる自然型、それらの汎化型になる有理数型や浮動小数型で比較をすることができます。
そのため、整数型や整数の部分型にあたる自然型、それらの汎化型になる有理数型や浮動小数点数型で比較をすることができます。
ただし、浮動小数型は`Eq`をsupersに持たないため、`==`を使うとコンパイルエラーになります。
ただし、浮動小数点数型は`Eq`を汎化型に持たないため、`==`を使うとコンパイルエラーになります。
```python
True == 1 # OK
@ -65,7 +65,7 @@ assert i == 0
```
大文字で始まるものは定数です。コンパイル時計算できるものだけが定数にできます。
また、定数は定義以降すべてのスコープで同一です。
また、定数は定義以降すべてのスコープで同一です。この性質により、パターンマッチで定数を使うことができます。
```python
random = import "random" # pythonの標準ライブラリをインポートできる
@ -88,7 +88,7 @@ i = 1.0 # NG
## 関数
Haskellなどと同じように定義できます。
概ねHaskellと同じように定義できます。
```python
fib 0 = 0
@ -120,7 +120,9 @@ assert i == 1
## プロシージャ
副作用のあるサブルーチンはプロシージャと呼ばれ、`!`がついています。
副作用のないサブルーチンは関数と呼びます。
プロシージャを関数中で呼び出すことはできません。
これにより、副作用は明示的に分離されます。
```python
print! 1 # 1
@ -145,7 +147,7 @@ assert p.x == 1
## 所有権
Ergは可変オブジェクト(`!`演算子で可変化したオブジェクト)に所有権がついており、複数の場所から書き換えられません。
Ergは可変オブジェクト(`!`演算子で可変化したオブジェクト)に所有権がついており、複数の場所から書き換えられません。
```python
i = !0
@ -228,9 +230,9 @@ right(_, r) = r
後述するタプル/配列/レコードパターンと組み合わせて使う。
```python
[i, ...j] = [1, 2, 3, 4]
[i, *j] = [1, 2, 3, 4]
assert j == [2, 3, 4]
first|T|(fst: T, ...rest: T) = fst
first|T|(fst: T, *rest: T) = fst
assert first(1, 2, 3) == 1
```
@ -247,7 +249,7 @@ m, n = 1, 2
```python
length [] = 0
length [_, ...rest] = 1 + length rest
length [_, *rest] = 1 + length rest
```
#### レコードパターン
@ -278,7 +280,16 @@ odds = [i | i <- 1..100; i % 2 == 0]
## クラス
Ergでは多重・多段継承をサポートしていません。
Ergでは多重継承をサポートしていません。
クラスはデフォルトで継承不可能であり、継承可能クラスを定義する際は`Inheritable`デコレータをつけます。
```python
@Inheritable
Point2D = Class {x = Int; y = Int}
Point3D = Inherit Point2D, Base := {x = Int; y = Int; z = Int}
```
## トレイト
@ -299,7 +310,15 @@ Point.
## パッチ
クラスやトレイトに実装を与えたりできます。
クラスやトレイトに後付けで実装を与えたりできます。
```python
Invert = Patch Bool
Invert.
invert self = not self
assert False.invert()
```
## 篩型