mirror of
https://github.com/erg-lang/erg.git
synced 2025-10-02 13:41:10 +00:00
commit
04d754b329
75 changed files with 1402 additions and 1357 deletions
|
@ -42,10 +42,10 @@
|
||||||
l2[10] # IndexError: `l2` has 7 elements but was accessed the 11th element
|
l2[10] # IndexError: `l2` has 7 elements but was accessed the 11th element
|
||||||
|
|
||||||
2.times! do!:
|
2.times! do!:
|
||||||
print! "hello, ", end: ""
|
print! "hello, ", end := ""
|
||||||
# => hello, hello,
|
# => hello, hello,
|
||||||
-2.times! do!:
|
-2.times! do!:
|
||||||
print! "hello, ", end: ""
|
print! "hello, ", end := ""
|
||||||
# TypeError: `.times!` is a method of `Nat` (0 or more Int), not `Int`
|
# TypeError: `.times!` is a method of `Nat` (0 or more Int), not `Int`
|
||||||
|
|
||||||
{Meter; Sec; meter; yard; sec; ...} = import "unit"
|
{Meter; Sec; meter; yard; sec; ...} = import "unit"
|
||||||
|
|
|
@ -46,10 +46,10 @@
|
||||||
l2[10] # IndexError: `l2`は7つの要素を持っていますが、11番目の要素のアクセスしようとしています
|
l2[10] # IndexError: `l2`は7つの要素を持っていますが、11番目の要素のアクセスしようとしています
|
||||||
|
|
||||||
2.times! do!:
|
2.times! do!:
|
||||||
print! "hello, ", end: ""
|
print! "hello, ", end := ""
|
||||||
# => hello, hello,
|
# => hello, hello,
|
||||||
-2.times! do!:
|
-2.times! do!:
|
||||||
print! "hello,", end: ""
|
print! "hello,", end := ""
|
||||||
# TypeError: `.times!`は`Nat`(0以上のInt)のメソッドです、`Int`ではありません
|
# TypeError: `.times!`は`Nat`(0以上のInt)のメソッドです、`Int`ではありません
|
||||||
|
|
||||||
{Meter; Sec; meter; yard; sec; ...} = import "unit"
|
{Meter; Sec; meter; yard; sec; ...} = import "unit"
|
||||||
|
|
|
@ -45,10 +45,10 @@
|
||||||
l2[10] # 下标错误:`l2`只有7个元素,但却被访问了第11个元素
|
l2[10] # 下标错误:`l2`只有7个元素,但却被访问了第11个元素
|
||||||
|
|
||||||
2.times! do!:
|
2.times! do!:
|
||||||
print! "hello, ", end: ""
|
print! "hello, ", end := ""
|
||||||
# => hello, hello,
|
# => hello, hello,
|
||||||
-2.times! do!:
|
-2.times! do!:
|
||||||
print! "hello, ", end: ""
|
print! "hello, ", end := ""
|
||||||
# 类型错误:`.times!`是`Nat`(0或更大整数)的方法,不是`Int`的
|
# 类型错误:`.times!`是`Nat`(0或更大整数)的方法,不是`Int`的
|
||||||
|
|
||||||
{Meter; Sec; meter; yard; sec; ...} = import "unit"
|
{Meter; Sec; meter; yard; sec; ...} = import "unit"
|
||||||
|
|
|
@ -45,10 +45,10 @@
|
||||||
l2[10] # 下標錯誤:`l2`只有7個元素,但卻被訪問了第11個元素
|
l2[10] # 下標錯誤:`l2`只有7個元素,但卻被訪問了第11個元素
|
||||||
|
|
||||||
2.times! do!:
|
2.times! do!:
|
||||||
print! "hello, ", end: ""
|
print! "hello, ", end := ""
|
||||||
# => hello, hello,
|
# => hello, hello,
|
||||||
-2.times! do!:
|
-2.times! do!:
|
||||||
print! "hello, ", end: ""
|
print! "hello, ", end := ""
|
||||||
# 類型錯誤:`.times!`是`Nat`(0或更大整數)的方法,不是`Int`的
|
# 類型錯誤:`.times!`是`Nat`(0或更大整數)的方法,不是`Int`的
|
||||||
|
|
||||||
{Meter; Sec; meter; yard; sec; ...} = import "unit"
|
{Meter; Sec; meter; yard; sec; ...} = import "unit"
|
||||||
|
|
|
@ -212,7 +212,7 @@ macro_rules! impl_stream_for_wrapper {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl erg_common::traits::Stream<$Inner> for $Strc {
|
impl $crate::traits::Stream<$Inner> for $Strc {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn payload(self) -> Vec<$Inner> {
|
fn payload(self) -> Vec<$Inner> {
|
||||||
self.0
|
self.0
|
||||||
|
@ -232,7 +232,7 @@ macro_rules! impl_stream_for_wrapper {
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! impl_stream {
|
macro_rules! impl_stream {
|
||||||
($Strc: ident, $Inner: ident, $field: ident) => {
|
($Strc: ident, $Inner: ident, $field: ident) => {
|
||||||
impl erg_common::traits::Stream<$Inner> for $Strc {
|
impl $crate::traits::Stream<$Inner> for $Strc {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn payload(self) -> Vec<$Inner> {
|
fn payload(self) -> Vec<$Inner> {
|
||||||
self.$field
|
self.$field
|
||||||
|
|
|
@ -701,6 +701,9 @@ impl CodeGenerator {
|
||||||
self.emit_store_instr(sig.ident, Name);
|
self.emit_store_instr(sig.ident, Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NOTE: use `TypeVar`, `Generic` in `typing` module
|
||||||
|
// fn emit_poly_type_def(&mut self, sig: SubrSignature, body: DefBody) {}
|
||||||
|
|
||||||
fn emit_var_def(&mut self, sig: VarSignature, mut body: DefBody) {
|
fn emit_var_def(&mut self, sig: VarSignature, mut body: DefBody) {
|
||||||
if body.is_type() {
|
if body.is_type() {
|
||||||
return self.emit_mono_type_def(sig, body);
|
return self.emit_mono_type_def(sig, body);
|
||||||
|
|
24
compiler/erg_compiler/context/hint.rs
Normal file
24
compiler/erg_compiler/context/hint.rs
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
use erg_common::Str;
|
||||||
|
|
||||||
|
use erg_type::Type;
|
||||||
|
|
||||||
|
use crate::context::Context;
|
||||||
|
|
||||||
|
impl Context {
|
||||||
|
pub(crate) fn get_type_mismatch_hint(&self, expected: &Type, found: &Type) -> Option<Str> {
|
||||||
|
let expected = if let Type::FreeVar(fv) = expected {
|
||||||
|
if fv.is_linked() {
|
||||||
|
fv.crack().clone()
|
||||||
|
} else {
|
||||||
|
let (_sub, sup) = fv.crack_bound_types().unwrap();
|
||||||
|
sup
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
expected.clone()
|
||||||
|
};
|
||||||
|
match (&expected.name()[..], &found.name()[..]) {
|
||||||
|
("Eq", "Float") => Some(Str::ever("Float has no equivalence relation defined. you should use `l - r <= Float.EPSILON` instead of `l == r`.")),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -51,6 +51,7 @@ impl Context {
|
||||||
ident.inspect(),
|
ident.inspect(),
|
||||||
&spec_t,
|
&spec_t,
|
||||||
body_t,
|
body_t,
|
||||||
|
self.get_type_mismatch_hint(&spec_t, body_t),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -120,6 +121,7 @@ impl Context {
|
||||||
"match",
|
"match",
|
||||||
&class("LambdaFunc"),
|
&class("LambdaFunc"),
|
||||||
t,
|
t,
|
||||||
|
self.get_type_mismatch_hint(&class("LambdaFunc"), t),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -616,6 +618,7 @@ impl Context {
|
||||||
&name[..],
|
&name[..],
|
||||||
param_t,
|
param_t,
|
||||||
arg_t,
|
arg_t,
|
||||||
|
self.get_type_mismatch_hint(param_t, arg_t),
|
||||||
)
|
)
|
||||||
})?;
|
})?;
|
||||||
if let Some(name) = param.name() {
|
if let Some(name) = param.name() {
|
||||||
|
@ -656,6 +659,7 @@ impl Context {
|
||||||
&name[..],
|
&name[..],
|
||||||
param_t,
|
param_t,
|
||||||
arg_t,
|
arg_t,
|
||||||
|
self.get_type_mismatch_hint(param_t, arg_t),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -698,6 +702,7 @@ impl Context {
|
||||||
&name[..],
|
&name[..],
|
||||||
pt.typ(),
|
pt.typ(),
|
||||||
arg_t,
|
arg_t,
|
||||||
|
self.get_type_mismatch_hint(pt.typ(), arg_t),
|
||||||
)
|
)
|
||||||
})?;
|
})?;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
//! `Context` is used for type inference and type checking.
|
//! `Context` is used for type inference and type checking.
|
||||||
pub mod cache;
|
pub mod cache;
|
||||||
pub mod compare;
|
pub mod compare;
|
||||||
|
pub mod hint;
|
||||||
pub mod initialize;
|
pub mod initialize;
|
||||||
pub mod inquire;
|
pub mod inquire;
|
||||||
pub mod instantiate;
|
pub mod instantiate;
|
||||||
|
|
|
@ -393,6 +393,7 @@ impl Context {
|
||||||
"import::name",
|
"import::name",
|
||||||
&Str,
|
&Str,
|
||||||
mod_name.ref_t(),
|
mod_name.ref_t(),
|
||||||
|
self.get_type_mismatch_hint(&Str, mod_name.ref_t()),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1017,6 +1017,7 @@ impl Context {
|
||||||
param_name.unwrap_or(&Str::ever("_")),
|
param_name.unwrap_or(&Str::ever("_")),
|
||||||
maybe_sup,
|
maybe_sup,
|
||||||
maybe_sub,
|
maybe_sub,
|
||||||
|
self.get_type_mismatch_hint(maybe_sup, maybe_sub),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
match (maybe_sub, maybe_sup) {
|
match (maybe_sub, maybe_sup) {
|
||||||
|
|
|
@ -513,6 +513,7 @@ impl TyCheckError {
|
||||||
name: &str,
|
name: &str,
|
||||||
expect: &Type,
|
expect: &Type,
|
||||||
found: &Type,
|
found: &Type,
|
||||||
|
hint: Option<Str>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self::new(
|
Self::new(
|
||||||
ErrorCore::new(
|
ErrorCore::new(
|
||||||
|
@ -525,7 +526,7 @@ impl TyCheckError {
|
||||||
"traditional_chinese" => format!("{name}的類型不匹配:\n預期:{GREEN}{expect}{RESET}\n但找到:{RED}{found}{RESET}"),
|
"traditional_chinese" => format!("{name}的類型不匹配:\n預期:{GREEN}{expect}{RESET}\n但找到:{RED}{found}{RESET}"),
|
||||||
"english" => format!("the type of {name} is mismatched:\nexpected: {GREEN}{expect}{RESET}\nbut found: {RED}{found}{RESET}"),
|
"english" => format!("the type of {name} is mismatched:\nexpected: {GREEN}{expect}{RESET}\nbut found: {RED}{found}{RESET}"),
|
||||||
),
|
),
|
||||||
None,
|
hint,
|
||||||
),
|
),
|
||||||
caused_by,
|
caused_by,
|
||||||
)
|
)
|
||||||
|
|
|
@ -264,7 +264,7 @@ impl Evaluator {
|
||||||
Some(ValueObj::Array(RcArray::from(elems)))
|
Some(ValueObj::Array(RcArray::from(elems)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eval_const_record(&self, record: &Record, ctx: &Context) -> Option<ValueObj> {
|
fn eval_const_record(&self, record: &NormalRecord, ctx: &Context) -> Option<ValueObj> {
|
||||||
let mut attrs = vec![];
|
let mut attrs = vec![];
|
||||||
for attr in record.attrs.iter() {
|
for attr in record.attrs.iter() {
|
||||||
if let Some(elem) = self.eval_const_block(&attr.body.block, ctx) {
|
if let Some(elem) = self.eval_const_block(&attr.body.block, ctx) {
|
||||||
|
|
|
@ -97,7 +97,7 @@ pub struct KwArg {
|
||||||
|
|
||||||
impl NestedDisplay for KwArg {
|
impl NestedDisplay for KwArg {
|
||||||
fn fmt_nest(&self, f: &mut std::fmt::Formatter<'_>, level: usize) -> std::fmt::Result {
|
fn fmt_nest(&self, f: &mut std::fmt::Formatter<'_>, level: usize) -> std::fmt::Result {
|
||||||
writeln!(f, "{}:", self.keyword)?;
|
writeln!(f, "{} := ", self.keyword)?;
|
||||||
self.expr.fmt_nest(f, level + 1)
|
self.expr.fmt_nest(f, level + 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,6 +55,7 @@ impl ASTLowerer {
|
||||||
name,
|
name,
|
||||||
expect,
|
expect,
|
||||||
found,
|
found,
|
||||||
|
self.ctx.get_type_mismatch_hint(expect, found),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -216,7 +217,7 @@ impl ASTLowerer {
|
||||||
Ok(hir::NormalTuple::new(hir::Args::from(new_tuple)))
|
Ok(hir::NormalTuple::new(hir::Args::from(new_tuple)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lower_record(&mut self, record: ast::Record) -> LowerResult<hir::Record> {
|
fn lower_record(&mut self, record: ast::NormalRecord) -> LowerResult<hir::Record> {
|
||||||
log!(info "entered {}({record})", fn_name!());
|
log!(info "entered {}({record})", fn_name!());
|
||||||
let mut hir_record =
|
let mut hir_record =
|
||||||
hir::Record::new(record.l_brace, record.r_brace, hir::RecordAttrs::new());
|
hir::Record::new(record.l_brace, record.r_brace, hir::RecordAttrs::new());
|
||||||
|
@ -336,8 +337,6 @@ impl ASTLowerer {
|
||||||
&hir_args.kw_args,
|
&hir_args.kw_args,
|
||||||
&self.ctx.name,
|
&self.ctx.name,
|
||||||
)?;
|
)?;
|
||||||
log!(err "{}", obj);
|
|
||||||
log!(err "{:?}", call.method_name);
|
|
||||||
Ok(hir::Call::new(obj, call.method_name, hir_args, t))
|
Ok(hir::Call::new(obj, call.method_name, hir_args, t))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -95,12 +95,18 @@ impl PosArg {
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
pub struct KwArg {
|
pub struct KwArg {
|
||||||
pub keyword: Token,
|
pub keyword: Token,
|
||||||
|
pub t_spec: Option<TypeSpec>,
|
||||||
pub expr: Expr,
|
pub expr: Expr,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NestedDisplay for KwArg {
|
impl NestedDisplay for KwArg {
|
||||||
fn fmt_nest(&self, f: &mut std::fmt::Formatter<'_>, level: usize) -> std::fmt::Result {
|
fn fmt_nest(&self, f: &mut std::fmt::Formatter<'_>, level: usize) -> std::fmt::Result {
|
||||||
writeln!(f, "{}: ", self.keyword.content)?;
|
writeln!(
|
||||||
|
f,
|
||||||
|
"{}{} := ",
|
||||||
|
self.keyword.content,
|
||||||
|
fmt_option!(pre ": ", self.t_spec)
|
||||||
|
)?;
|
||||||
self.expr.fmt_nest(f, level + 1)
|
self.expr.fmt_nest(f, level + 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -109,8 +115,12 @@ impl_display_from_nested!(KwArg);
|
||||||
impl_locational!(KwArg, keyword, expr);
|
impl_locational!(KwArg, keyword, expr);
|
||||||
|
|
||||||
impl KwArg {
|
impl KwArg {
|
||||||
pub const fn new(keyword: Token, expr: Expr) -> Self {
|
pub const fn new(keyword: Token, t_spec: Option<TypeSpec>, expr: Expr) -> Self {
|
||||||
Self { keyword, expr }
|
Self {
|
||||||
|
keyword,
|
||||||
|
t_spec,
|
||||||
|
expr,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -169,6 +179,10 @@ impl Args {
|
||||||
self.pos_args.is_empty() && self.kw_args.is_empty()
|
self.pos_args.is_empty() && self.kw_args.is_empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn len(&self) -> usize {
|
||||||
|
self.pos_args.len() + self.kw_args.len()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn kw_is_empty(&self) -> bool {
|
pub fn kw_is_empty(&self) -> bool {
|
||||||
self.kw_args.is_empty()
|
self.kw_args.is_empty()
|
||||||
}
|
}
|
||||||
|
@ -296,12 +310,13 @@ impl Public {
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
pub struct Attribute {
|
pub struct Attribute {
|
||||||
pub obj: Box<Expr>,
|
pub obj: Box<Expr>,
|
||||||
|
pub vis: Token,
|
||||||
pub name: Local,
|
pub name: Local,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NestedDisplay for Attribute {
|
impl NestedDisplay for Attribute {
|
||||||
fn fmt_nest(&self, f: &mut std::fmt::Formatter<'_>, _level: usize) -> std::fmt::Result {
|
fn fmt_nest(&self, f: &mut std::fmt::Formatter<'_>, _level: usize) -> std::fmt::Result {
|
||||||
write!(f, "({}).{}", self.obj, self.name)
|
write!(f, "({}){}{}", self.obj, self.vis.inspect(), self.name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -309,9 +324,10 @@ impl_display_from_nested!(Attribute);
|
||||||
impl_locational!(Attribute, obj, name);
|
impl_locational!(Attribute, obj, name);
|
||||||
|
|
||||||
impl Attribute {
|
impl Attribute {
|
||||||
pub fn new(obj: Expr, name: Local) -> Self {
|
pub fn new(obj: Expr, vis: Token, name: Local) -> Self {
|
||||||
Self {
|
Self {
|
||||||
obj: Box::new(obj),
|
obj: Box::new(obj),
|
||||||
|
vis,
|
||||||
name,
|
name,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -388,8 +404,8 @@ impl Accessor {
|
||||||
Self::Public(Public::new(dot, symbol))
|
Self::Public(Public::new(dot, symbol))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn attr(obj: Expr, name: Local) -> Self {
|
pub fn attr(obj: Expr, vis: Token, name: Local) -> Self {
|
||||||
Self::Attr(Attribute::new(obj, name))
|
Self::Attr(Attribute::new(obj, vis, name))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn tuple_attr(obj: Expr, index: Literal) -> Self {
|
pub fn tuple_attr(obj: Expr, index: Literal) -> Self {
|
||||||
|
@ -646,6 +662,12 @@ impl NestedDisplay for RecordAttrs {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Locational for RecordAttrs {
|
||||||
|
fn loc(&self) -> Location {
|
||||||
|
Location::concat(self.0.first().unwrap(), self.0.last().unwrap())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl From<Vec<Def>> for RecordAttrs {
|
impl From<Vec<Def>> for RecordAttrs {
|
||||||
fn from(attrs: Vec<Def>) -> Self {
|
fn from(attrs: Vec<Def>) -> Self {
|
||||||
Self(attrs)
|
Self(attrs)
|
||||||
|
@ -663,13 +685,13 @@ impl RecordAttrs {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
pub struct Record {
|
pub struct NormalRecord {
|
||||||
pub l_brace: Token,
|
pub l_brace: Token,
|
||||||
pub r_brace: Token,
|
pub r_brace: Token,
|
||||||
pub attrs: RecordAttrs,
|
pub attrs: RecordAttrs,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NestedDisplay for Record {
|
impl NestedDisplay for NormalRecord {
|
||||||
fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, level: usize) -> fmt::Result {
|
fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, level: usize) -> fmt::Result {
|
||||||
writeln!(f, "{{")?;
|
writeln!(f, "{{")?;
|
||||||
self.attrs.fmt_nest(f, level + 1)?;
|
self.attrs.fmt_nest(f, level + 1)?;
|
||||||
|
@ -677,10 +699,10 @@ impl NestedDisplay for Record {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_display_from_nested!(Record);
|
impl_display_from_nested!(NormalRecord);
|
||||||
impl_locational!(Record, l_brace, r_brace);
|
impl_locational!(NormalRecord, l_brace, r_brace);
|
||||||
|
|
||||||
impl Record {
|
impl NormalRecord {
|
||||||
pub fn new(l_brace: Token, r_brace: Token, attrs: RecordAttrs) -> Self {
|
pub fn new(l_brace: Token, r_brace: Token, attrs: RecordAttrs) -> Self {
|
||||||
Self {
|
Self {
|
||||||
l_brace,
|
l_brace,
|
||||||
|
@ -690,6 +712,14 @@ impl Record {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// e.g. {x; y; z} (syntax sugar of {x = x; y = y; z = z})
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub struct SimpleRecord {
|
||||||
|
pub l_brace: Token,
|
||||||
|
pub r_brace: Token,
|
||||||
|
idents: Vec<Identifier>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
pub struct NormalSet {
|
pub struct NormalSet {
|
||||||
l_brace: Token,
|
l_brace: Token,
|
||||||
|
@ -1168,7 +1198,7 @@ pub struct ConstKwArg {
|
||||||
|
|
||||||
impl NestedDisplay for ConstKwArg {
|
impl NestedDisplay for ConstKwArg {
|
||||||
fn fmt_nest(&self, f: &mut std::fmt::Formatter<'_>, _level: usize) -> std::fmt::Result {
|
fn fmt_nest(&self, f: &mut std::fmt::Formatter<'_>, _level: usize) -> std::fmt::Result {
|
||||||
write!(f, "{}: {}", self.keyword.content, self.expr)
|
write!(f, "{} := {}", self.keyword.content, self.expr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1403,7 +1433,7 @@ impl SubrKindSpec {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
pub struct SubrTySpec {
|
pub struct SubrTypeSpec {
|
||||||
pub kind: SubrKindSpec,
|
pub kind: SubrKindSpec,
|
||||||
pub lparen: Option<Token>,
|
pub lparen: Option<Token>,
|
||||||
pub non_defaults: Vec<ParamTySpec>,
|
pub non_defaults: Vec<ParamTySpec>,
|
||||||
|
@ -1412,11 +1442,11 @@ pub struct SubrTySpec {
|
||||||
pub return_t: Box<TypeSpec>,
|
pub return_t: Box<TypeSpec>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for SubrTySpec {
|
impl fmt::Display for SubrTypeSpec {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
"({}, {}, |= {}) {} {}",
|
"({}, {}, := {}) {} {}",
|
||||||
fmt_vec(&self.non_defaults),
|
fmt_vec(&self.non_defaults),
|
||||||
fmt_option!(pre "...", &self.var_args),
|
fmt_option!(pre "...", &self.var_args),
|
||||||
fmt_vec(&self.defaults),
|
fmt_vec(&self.defaults),
|
||||||
|
@ -1426,7 +1456,7 @@ impl fmt::Display for SubrTySpec {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Locational for SubrTySpec {
|
impl Locational for SubrTypeSpec {
|
||||||
fn loc(&self) -> Location {
|
fn loc(&self) -> Location {
|
||||||
if let Some(lparen) = &self.lparen {
|
if let Some(lparen) = &self.lparen {
|
||||||
Location::concat(lparen, self.return_t.as_ref())
|
Location::concat(lparen, self.return_t.as_ref())
|
||||||
|
@ -1437,7 +1467,7 @@ impl Locational for SubrTySpec {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SubrTySpec {
|
impl SubrTypeSpec {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
kind: SubrKindSpec,
|
kind: SubrKindSpec,
|
||||||
lparen: Option<Token>,
|
lparen: Option<Token>,
|
||||||
|
@ -1457,24 +1487,34 @@ impl SubrTySpec {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
|
pub struct ArrayTypeSpec {
|
||||||
|
pub ty: Box<TypeSpec>,
|
||||||
|
pub len: ConstExpr,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for ArrayTypeSpec {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f, "[{}; {}]", self.ty, self.len)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_locational!(ArrayTypeSpec, ty, len);
|
||||||
|
|
||||||
/// * Array: `[Int; 3]`, `[Int, Ratio, Complex]`, etc.
|
/// * Array: `[Int; 3]`, `[Int, Ratio, Complex]`, etc.
|
||||||
/// * Dict: `[Str: Str]`, etc.
|
/// * Dict: `[Str: Str]`, etc.
|
||||||
/// * Option: `Int?`, etc.
|
|
||||||
/// * And (Intersection type): Add and Sub and Mul (== Num), etc.
|
/// * And (Intersection type): Add and Sub and Mul (== Num), etc.
|
||||||
/// * Not (Diff type): Pos == Nat not {0}, etc.
|
/// * Not (Diff type): Pos == Nat not {0}, etc.
|
||||||
/// * Or (Union type): Int or None (== Option Int), etc.
|
/// * Or (Union type): Int or None (== Option Int), etc.
|
||||||
/// * Enum: `{0, 1}` (== Binary), etc.
|
/// * Enum: `{0, 1}` (== Binary), etc.
|
||||||
/// * Range: 1..12, 0.0<..1.0, etc.
|
/// * Range: 1..12, 0.0<..1.0, etc.
|
||||||
/// * Record: {.into_s: Self.() -> Str }, etc.
|
/// * Record: {.into_s: Self.() -> Str }, etc.
|
||||||
/// * Func: Int -> Int, etc.
|
/// * Subr: Int -> Int, Int => None, T.(X) -> Int, etc.
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
pub enum TypeSpec {
|
pub enum TypeSpec {
|
||||||
PreDeclTy(PreDeclTypeSpec),
|
PreDeclTy(PreDeclTypeSpec),
|
||||||
/* Composite types */
|
/* Composite types */
|
||||||
Array {
|
Array(ArrayTypeSpec),
|
||||||
t: PreDeclTypeSpec,
|
|
||||||
len: ConstExpr,
|
|
||||||
},
|
|
||||||
Tuple(Vec<TypeSpec>),
|
Tuple(Vec<TypeSpec>),
|
||||||
// Dict(),
|
// Dict(),
|
||||||
// Option(),
|
// Option(),
|
||||||
|
@ -1488,7 +1528,7 @@ pub enum TypeSpec {
|
||||||
rhs: ConstExpr,
|
rhs: ConstExpr,
|
||||||
},
|
},
|
||||||
// Record(),
|
// Record(),
|
||||||
Subr(SubrTySpec),
|
Subr(SubrTypeSpec),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for TypeSpec {
|
impl fmt::Display for TypeSpec {
|
||||||
|
@ -1498,7 +1538,7 @@ impl fmt::Display for TypeSpec {
|
||||||
Self::And(lhs, rhs) => write!(f, "{lhs} and {rhs}"),
|
Self::And(lhs, rhs) => write!(f, "{lhs} and {rhs}"),
|
||||||
Self::Not(lhs, rhs) => write!(f, "{lhs} not {rhs}"),
|
Self::Not(lhs, rhs) => write!(f, "{lhs} not {rhs}"),
|
||||||
Self::Or(lhs, rhs) => write!(f, "{lhs} or {rhs}"),
|
Self::Or(lhs, rhs) => write!(f, "{lhs} or {rhs}"),
|
||||||
Self::Array { t, len } => write!(f, "[{t}; {len}]"),
|
Self::Array(arr) => write!(f, "{arr}"),
|
||||||
Self::Tuple(tys) => write!(f, "({})", fmt_vec(tys)),
|
Self::Tuple(tys) => write!(f, "({})", fmt_vec(tys)),
|
||||||
Self::Enum(elems) => write!(f, "{{{elems}}}"),
|
Self::Enum(elems) => write!(f, "{{{elems}}}"),
|
||||||
Self::Interval { op, lhs, rhs } => write!(f, "{lhs}{}{rhs}", op.inspect()),
|
Self::Interval { op, lhs, rhs } => write!(f, "{lhs}{}{rhs}", op.inspect()),
|
||||||
|
@ -1514,7 +1554,7 @@ impl Locational for TypeSpec {
|
||||||
Self::And(lhs, rhs) | Self::Not(lhs, rhs) | Self::Or(lhs, rhs) => {
|
Self::And(lhs, rhs) | Self::Not(lhs, rhs) | Self::Or(lhs, rhs) => {
|
||||||
Location::concat(lhs.as_ref(), rhs.as_ref())
|
Location::concat(lhs.as_ref(), rhs.as_ref())
|
||||||
}
|
}
|
||||||
Self::Array { t, len } => Location::concat(t, len),
|
Self::Array(arr) => arr.loc(),
|
||||||
// TODO: ユニット
|
// TODO: ユニット
|
||||||
Self::Tuple(tys) => Location::concat(tys.first().unwrap(), tys.last().unwrap()),
|
Self::Tuple(tys) => Location::concat(tys.first().unwrap(), tys.last().unwrap()),
|
||||||
Self::Enum(set) => set.loc(),
|
Self::Enum(set) => set.loc(),
|
||||||
|
@ -1548,7 +1588,7 @@ impl TypeSpec {
|
||||||
defaults: Vec<ParamTySpec>,
|
defaults: Vec<ParamTySpec>,
|
||||||
return_t: TypeSpec,
|
return_t: TypeSpec,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self::Subr(SubrTySpec::new(
|
Self::Subr(SubrTypeSpec::new(
|
||||||
SubrKindSpec::Func,
|
SubrKindSpec::Func,
|
||||||
lparen,
|
lparen,
|
||||||
non_defaults,
|
non_defaults,
|
||||||
|
@ -1565,7 +1605,7 @@ impl TypeSpec {
|
||||||
defaults: Vec<ParamTySpec>,
|
defaults: Vec<ParamTySpec>,
|
||||||
return_t: TypeSpec,
|
return_t: TypeSpec,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self::Subr(SubrTySpec::new(
|
Self::Subr(SubrTypeSpec::new(
|
||||||
SubrKindSpec::Proc,
|
SubrKindSpec::Proc,
|
||||||
lparen,
|
lparen,
|
||||||
non_defaults,
|
non_defaults,
|
||||||
|
@ -1623,6 +1663,14 @@ impl Decorator {
|
||||||
pub const fn new(expr: Expr) -> Self {
|
pub const fn new(expr: Expr) -> Self {
|
||||||
Self(expr)
|
Self(expr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn expr(&self) -> &Expr {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn into_expr(self) -> Expr {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// symbol as a left value
|
/// symbol as a left value
|
||||||
|
@ -2063,6 +2111,20 @@ impl ParamArrayPattern {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub struct ParamTuplePattern {
|
||||||
|
pub elems: Params,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NestedDisplay for ParamTuplePattern {
|
||||||
|
fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, _level: usize) -> fmt::Result {
|
||||||
|
write!(f, "({})", self.elems)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_display_from_nested!(ParamTuplePattern);
|
||||||
|
impl_locational!(ParamTuplePattern, elems);
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
pub struct ParamRecordPattern {
|
pub struct ParamRecordPattern {
|
||||||
l_brace: Token,
|
l_brace: Token,
|
||||||
|
@ -2100,11 +2162,15 @@ pub enum ParamPattern {
|
||||||
VarArgsName(VarName),
|
VarArgsName(VarName),
|
||||||
Lit(Literal),
|
Lit(Literal),
|
||||||
Array(ParamArrayPattern),
|
Array(ParamArrayPattern),
|
||||||
|
Tuple(ParamTuplePattern),
|
||||||
Record(ParamRecordPattern),
|
Record(ParamRecordPattern),
|
||||||
|
Ref(VarName),
|
||||||
|
RefMut(VarName),
|
||||||
|
VarArgs(VarName),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_display_for_enum!(ParamPattern; Discard, VarName, VarArgsName, Lit, Array, Record);
|
impl_display_for_enum!(ParamPattern; Discard, VarName, VarArgsName, Lit, Array, Tuple, Record, Ref, RefMut, VarArgs);
|
||||||
impl_locational_for_enum!(ParamPattern; Discard, VarName, VarArgsName, Lit, Array, Record);
|
impl_locational_for_enum!(ParamPattern; Discard, VarName, VarArgsName, Lit, Array, Tuple, Record, Ref, RefMut, VarArgs);
|
||||||
|
|
||||||
impl ParamPattern {
|
impl ParamPattern {
|
||||||
pub const fn inspect(&self) -> Option<&Str> {
|
pub const fn inspect(&self) -> Option<&Str> {
|
||||||
|
@ -2148,7 +2214,7 @@ impl NestedDisplay for ParamSignature {
|
||||||
if let Some(default_val) = &self.opt_default_val {
|
if let Some(default_val) = &self.opt_default_val {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
"{}{} |= {}",
|
"{}{} := {}",
|
||||||
self.pat,
|
self.pat,
|
||||||
fmt_option!(pre ": ", self.t_spec),
|
fmt_option!(pre ": ", self.t_spec),
|
||||||
default_val
|
default_val
|
||||||
|
@ -2163,7 +2229,9 @@ impl_display_from_nested!(ParamSignature);
|
||||||
|
|
||||||
impl Locational for ParamSignature {
|
impl Locational for ParamSignature {
|
||||||
fn loc(&self) -> Location {
|
fn loc(&self) -> Location {
|
||||||
if let Some(t_spec) = &self.t_spec {
|
if let Some(default) = &self.opt_default_val {
|
||||||
|
Location::concat(&self.pat, default)
|
||||||
|
} else if let Some(t_spec) = &self.t_spec {
|
||||||
Location::concat(&self.pat, t_spec)
|
Location::concat(&self.pat, t_spec)
|
||||||
} else {
|
} else {
|
||||||
self.pat.loc()
|
self.pat.loc()
|
||||||
|
@ -2220,6 +2288,8 @@ impl Locational for Params {
|
||||||
Location::concat(l, r)
|
Location::concat(l, r)
|
||||||
} else if !self.non_defaults.is_empty() {
|
} else if !self.non_defaults.is_empty() {
|
||||||
Location::concat(&self.non_defaults[0], self.non_defaults.last().unwrap())
|
Location::concat(&self.non_defaults[0], self.non_defaults.last().unwrap())
|
||||||
|
} else if let Some(var_args) = &self.var_args {
|
||||||
|
Location::concat(var_args.as_ref(), self.defaults.last().unwrap())
|
||||||
} else if !self.defaults.is_empty() {
|
} else if !self.defaults.is_empty() {
|
||||||
Location::concat(&self.defaults[0], self.defaults.last().unwrap())
|
Location::concat(&self.defaults[0], self.defaults.last().unwrap())
|
||||||
} else {
|
} else {
|
||||||
|
@ -2340,9 +2410,9 @@ impl SubrSignature {
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
pub struct LambdaSignature {
|
pub struct LambdaSignature {
|
||||||
|
pub bounds: TypeBoundSpecs,
|
||||||
pub params: Params,
|
pub params: Params,
|
||||||
pub return_t_spec: Option<TypeSpec>,
|
pub return_t_spec: Option<TypeSpec>,
|
||||||
pub bounds: TypeBoundSpecs,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for LambdaSignature {
|
impl fmt::Display for LambdaSignature {
|
||||||
|
@ -2492,7 +2562,30 @@ impl Signature {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type Decl = Signature;
|
/// type_ascription ::= expr ':' type
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub struct TypeAscription {
|
||||||
|
pub expr: Box<Expr>,
|
||||||
|
pub t_spec: TypeSpec,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NestedDisplay for TypeAscription {
|
||||||
|
fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, _level: usize) -> fmt::Result {
|
||||||
|
writeln!(f, "{}: {}", self.expr, self.t_spec)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_display_from_nested!(TypeAscription);
|
||||||
|
impl_locational!(TypeAscription, expr, t_spec);
|
||||||
|
|
||||||
|
impl TypeAscription {
|
||||||
|
pub fn new(expr: Expr, t_spec: TypeSpec) -> Self {
|
||||||
|
Self {
|
||||||
|
expr: Box::new(expr),
|
||||||
|
t_spec,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
pub struct DefBody {
|
pub struct DefBody {
|
||||||
|
@ -2539,6 +2632,36 @@ impl Def {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// e.g.
|
||||||
|
/// ```erg
|
||||||
|
/// T = Class ...
|
||||||
|
/// T.
|
||||||
|
/// x = 1
|
||||||
|
/// f(a) = ...
|
||||||
|
/// ```
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
|
pub struct MethodDefs {
|
||||||
|
pub class: TypeSpec,
|
||||||
|
pub vis: Token, // `.` or `::`
|
||||||
|
pub defs: RecordAttrs, // TODO: allow declaration
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NestedDisplay for MethodDefs {
|
||||||
|
fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, level: usize) -> fmt::Result {
|
||||||
|
writeln!(f, "{}{}", self.class, self.vis)?;
|
||||||
|
self.defs.fmt_nest(f, level + 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_display_from_nested!(MethodDefs);
|
||||||
|
impl_locational!(MethodDefs, class, defs);
|
||||||
|
|
||||||
|
impl MethodDefs {
|
||||||
|
pub const fn new(class: TypeSpec, vis: Token, defs: RecordAttrs) -> Self {
|
||||||
|
Self { class, vis, defs }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Expression(式)
|
/// Expression(式)
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
pub enum Expr {
|
pub enum Expr {
|
||||||
|
@ -2548,18 +2671,19 @@ pub enum Expr {
|
||||||
Tuple(Tuple),
|
Tuple(Tuple),
|
||||||
Dict(Dict),
|
Dict(Dict),
|
||||||
Set(Set),
|
Set(Set),
|
||||||
Record(Record),
|
Record(NormalRecord),
|
||||||
BinOp(BinOp),
|
BinOp(BinOp),
|
||||||
UnaryOp(UnaryOp),
|
UnaryOp(UnaryOp),
|
||||||
Call(Call),
|
Call(Call),
|
||||||
Lambda(Lambda),
|
Lambda(Lambda),
|
||||||
Decl(Decl),
|
TypeAsc(TypeAscription),
|
||||||
Def(Def),
|
Def(Def),
|
||||||
|
MethodDefs(MethodDefs),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_nested_display_for_chunk_enum!(Expr; Lit, Accessor, Array, Tuple, Dict, Set, Record, BinOp, UnaryOp, Call, Lambda, Decl, Def);
|
impl_nested_display_for_chunk_enum!(Expr; Lit, Accessor, Array, Tuple, Dict, Set, Record, BinOp, UnaryOp, Call, Lambda, TypeAsc, Def, MethodDefs);
|
||||||
impl_display_from_nested!(Expr);
|
impl_display_from_nested!(Expr);
|
||||||
impl_locational_for_enum!(Expr; Lit, Accessor, Array, Tuple, Dict, Set, Record, BinOp, UnaryOp, Call, Lambda, Decl, Def);
|
impl_locational_for_enum!(Expr; Lit, Accessor, Array, Tuple, Dict, Set, Record, BinOp, UnaryOp, Call, Lambda, TypeAsc, Def, MethodDefs);
|
||||||
|
|
||||||
impl Expr {
|
impl Expr {
|
||||||
pub fn is_match_call(&self) -> bool {
|
pub fn is_match_call(&self) -> bool {
|
||||||
|
|
|
@ -244,7 +244,12 @@ impl Desugarer {
|
||||||
Accessor::subscr(obj, Expr::Lit(Literal::nat(n, sig.ln_begin().unwrap())))
|
Accessor::subscr(obj, Expr::Lit(Literal::nat(n, sig.ln_begin().unwrap())))
|
||||||
}
|
}
|
||||||
BufIndex::Record(attr) => {
|
BufIndex::Record(attr) => {
|
||||||
Accessor::attr(obj, Local::dummy_with_line(attr, sig.ln_begin().unwrap()))
|
// TODO: visibility
|
||||||
|
Accessor::attr(
|
||||||
|
obj,
|
||||||
|
Token::from_str(TokenKind::Dot, "."),
|
||||||
|
Local::dummy_with_line(attr, sig.ln_begin().unwrap()),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let id = DefId(get_hash(&(&acc, buf_name)));
|
let id = DefId(get_hash(&(&acc, buf_name)));
|
||||||
|
|
|
@ -664,7 +664,11 @@ impl Iterator for Lexer /*<'a>*/ {
|
||||||
_ => self.accept(Closed, ".."),
|
_ => self.accept(Closed, ".."),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some(c) if c.is_ascii_digit() => Some(self.lex_ratio(".".into())),
|
// prev_token is Symbol => TupleAttribute
|
||||||
|
// else: RatioLit (e.g. .0)
|
||||||
|
Some(c) if c.is_ascii_digit() && !self.prev_token.is(Symbol) => {
|
||||||
|
Some(self.lex_ratio(".".into()))
|
||||||
|
}
|
||||||
_ => self.accept(Dot, "."),
|
_ => self.accept(Dot, "."),
|
||||||
},
|
},
|
||||||
Some(',') => self.accept(Comma, ","),
|
Some(',') => self.accept(Comma, ","),
|
||||||
|
@ -673,6 +677,10 @@ impl Iterator for Lexer /*<'a>*/ {
|
||||||
self.consume();
|
self.consume();
|
||||||
self.accept(DblColon, "::")
|
self.accept(DblColon, "::")
|
||||||
}
|
}
|
||||||
|
Some('=') => {
|
||||||
|
self.consume();
|
||||||
|
self.accept(Walrus, ":=")
|
||||||
|
}
|
||||||
Some('>') => {
|
Some('>') => {
|
||||||
self.consume();
|
self.consume();
|
||||||
self.accept(SupertypeOf, ":>")
|
self.accept(SupertypeOf, ":>")
|
||||||
|
@ -694,10 +702,6 @@ impl Iterator for Lexer /*<'a>*/ {
|
||||||
self.consume();
|
self.consume();
|
||||||
self.accept(BitOr, "||")
|
self.accept(BitOr, "||")
|
||||||
}
|
}
|
||||||
Some('=') => {
|
|
||||||
self.consume();
|
|
||||||
self.accept(OrEqual, "|=")
|
|
||||||
}
|
|
||||||
_ => self.accept(VBar, "|"),
|
_ => self.accept(VBar, "|"),
|
||||||
},
|
},
|
||||||
Some('^') => {
|
Some('^') => {
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -105,8 +105,8 @@ pub enum TokenKind {
|
||||||
CrossOp,
|
CrossOp,
|
||||||
/// =
|
/// =
|
||||||
Equal,
|
Equal,
|
||||||
/// |=
|
/// :=
|
||||||
OrEqual,
|
Walrus,
|
||||||
/// ->
|
/// ->
|
||||||
FuncArrow,
|
FuncArrow,
|
||||||
/// =>
|
/// =>
|
||||||
|
@ -175,7 +175,7 @@ pub enum TokenCategory {
|
||||||
LEnclosure,
|
LEnclosure,
|
||||||
/// ) } } Dedent
|
/// ) } } Dedent
|
||||||
REnclosure,
|
REnclosure,
|
||||||
/// , : :: :> <: . |> |=
|
/// , : :: :> <: . |> :=
|
||||||
SpecialBinOp,
|
SpecialBinOp,
|
||||||
/// =
|
/// =
|
||||||
DefOp,
|
DefOp,
|
||||||
|
@ -212,7 +212,7 @@ impl TokenKind {
|
||||||
| InfLit => TokenCategory::Literal,
|
| InfLit => TokenCategory::Literal,
|
||||||
PrePlus | PreMinus | PreBitNot | Mutate => TokenCategory::UnaryOp,
|
PrePlus | PreMinus | PreBitNot | Mutate => TokenCategory::UnaryOp,
|
||||||
Try => TokenCategory::PostfixOp,
|
Try => TokenCategory::PostfixOp,
|
||||||
Comma | Colon | DblColon | SupertypeOf | SubtypeOf | Dot | Pipe | OrEqual => {
|
Comma | Colon | DblColon | SupertypeOf | SubtypeOf | Dot | Pipe | Walrus => {
|
||||||
TokenCategory::SpecialBinOp
|
TokenCategory::SpecialBinOp
|
||||||
}
|
}
|
||||||
Equal => TokenCategory::DefOp,
|
Equal => TokenCategory::DefOp,
|
||||||
|
@ -250,7 +250,7 @@ impl TokenKind {
|
||||||
FuncArrow | ProcArrow => 60, // -> =>
|
FuncArrow | ProcArrow => 60, // -> =>
|
||||||
Colon | SupertypeOf | SubtypeOf => 50, // : :> <:
|
Colon | SupertypeOf | SubtypeOf => 50, // : :> <:
|
||||||
Comma => 40, // ,
|
Comma => 40, // ,
|
||||||
Equal | OrEqual => 20, // = |=
|
Equal | Walrus => 20, // = :=
|
||||||
Newline | Semi => 10, // \n ;
|
Newline | Semi => 10, // \n ;
|
||||||
LParen | LBrace | LSqBr | Indent => 0, // ( { [ Indent
|
LParen | LBrace | LSqBr | Indent => 0, // ( { [ Indent
|
||||||
_ => return None,
|
_ => return None,
|
||||||
|
|
|
@ -704,7 +704,7 @@ impl LimitedDisplay for SubrType {
|
||||||
var_params.typ().limited_fmt(f, limit - 1)?;
|
var_params.typ().limited_fmt(f, limit - 1)?;
|
||||||
}
|
}
|
||||||
for pt in self.default_params.iter() {
|
for pt in self.default_params.iter() {
|
||||||
write!(f, ", {} |= ", pt.name().unwrap())?;
|
write!(f, ", {} := ", pt.name().unwrap())?;
|
||||||
pt.typ().limited_fmt(f, limit - 1)?;
|
pt.typ().limited_fmt(f, limit - 1)?;
|
||||||
}
|
}
|
||||||
write!(f, ") {} ", self.kind.arrow())?;
|
write!(f, ") {} ", self.kind.arrow())?;
|
||||||
|
@ -1075,7 +1075,7 @@ impl fmt::Display for ArgsOwnership {
|
||||||
write!(f, ", ...{o:?}")?;
|
write!(f, ", ...{o:?}")?;
|
||||||
}
|
}
|
||||||
for (name, o) in self.defaults.iter() {
|
for (name, o) in self.defaults.iter() {
|
||||||
write!(f, ", {name} |= {o:?}")?;
|
write!(f, ", {name} := {o:?}")?;
|
||||||
}
|
}
|
||||||
write!(f, ")")?;
|
write!(f, ")")?;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
[
|
[
|
||||||
](https://gezf7g7pd5.execute-api.ap-northeast-1.amazonaws.com/default/source_up_to_date?owner=erg-lang&repos=erg&ref=main&path=doc/EN/syntax/00_basic.md&commit_hash=21e8145e83fb54ed77e7631deeee8a7e39b028a3)
|
](https://gezf7g7pd5.execute-api.ap-northeast-1.amazonaws.com/default/source_up_to_date?owner=erg-lang&repos=erg&ref=main&path=doc/EN/syntax/00_basic.md&commit_hash=21e8145e83fb54ed77e7631deeee8a7e39b028a3)
|
||||||
|
|
||||||
> __Info__: This document is incomplete. It has not been proofread (style, correct links, mistranslation, etc.). Also, Erg's syntax may be change destructively during version 0.*, and the documentation may not have been updated accordingly. Please be aware of this beforehand.
|
> __Warning__: This document is incomplete. It has not been proofread (style, correct links, mistranslation, etc.). Also, Erg's syntax may be change destructively during version 0.*, and the documentation may not have been updated accordingly. Please be aware of this beforehand.
|
||||||
> If you find any errors in this document, please report then to [here form](https://forms.gle/HtLYRfYzWCAaeTGb6) or [GitHub repo](https://github.com/mtshiba/TheErgBook/issues/new). We would appreciate your suggestions.
|
> If you find any errors in this document, please report then to [here form](https://forms.gle/HtLYRfYzWCAaeTGb6) or [GitHub repo](https://github.com/mtshiba/TheErgBook/issues/new). We would appreciate your suggestions.
|
||||||
>
|
>
|
||||||
> [The Erg book original version (Japanese)](http://mtshiba.me/TheErgBook/)
|
> [The Erg book original version (Japanese)](http://mtshiba.me/TheErgBook/)
|
||||||
|
|
|
@ -41,7 +41,7 @@ T = Trait {
|
||||||
.f = (x: Int, y: Int): Int
|
.f = (x: Int, y: Int): Int
|
||||||
}
|
}
|
||||||
|
|
||||||
C = Class(U, Impl: T)
|
C = Class(U, Impl := T)
|
||||||
C.f(a: Int, b: Int): Int = ... # TypeError: `.f` must be type of `(x: Int, y: Int) -> Int`, not `(a: Int, b: Int) -> Int`
|
C.f(a: Int, b: Int): Int = ... # TypeError: `.f` must be type of `(x: Int, y: Int) -> Int`, not `(a: Int, b: Int) -> Int`
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -85,10 +85,10 @@ f x:
|
||||||
|
|
||||||
Default parameters are used when some parameters are mostly fixed and you want to be able to omit them.
|
Default parameters are used when some parameters are mostly fixed and you want to be able to omit them.
|
||||||
|
|
||||||
Default parameters are specified by `|=`(or-assign operator). If `base` is not specified, assign `math.E` to `base`.
|
Default parameters are specified by `:=`(walrus operator). If `base` is not specified, assign `math.E` to `base`.
|
||||||
|
|
||||||
```erg
|
```erg
|
||||||
math_log x: Ratio, base |= math.E = ...
|
math_log x: Ratio, base := math.E = ...
|
||||||
|
|
||||||
assert math_log(100, 10) == 2
|
assert math_log(100, 10) == 2
|
||||||
assert math_log(100) == math_log(100, math.E)
|
assert math_log(100) == math_log(100, math.E)
|
||||||
|
@ -97,7 +97,7 @@ assert math_log(100) == math_log(100, math.E)
|
||||||
Note that there is a distinction between specifying no argument and assigning `None`.
|
Note that there is a distinction between specifying no argument and assigning `None`.
|
||||||
|
|
||||||
```erg
|
```erg
|
||||||
p! x |= 0 = print!
|
p! x := 0 = print!
|
||||||
p!(2) # 2
|
p!(2) # 2
|
||||||
p!() # 0
|
p!() # 0
|
||||||
p!(None) # None
|
p!(None) # None
|
||||||
|
@ -106,20 +106,20 @@ p!(None) # None
|
||||||
Can also be used with type specification and patterns.
|
Can also be used with type specification and patterns.
|
||||||
|
|
||||||
```erg
|
```erg
|
||||||
math_log x, base: Ratio |= math.E = ...
|
math_log x, base: Ratio := math.E = ...
|
||||||
f [x, y] |= [1, 2] = ...
|
f [x, y] := [1, 2] = ...
|
||||||
```
|
```
|
||||||
|
|
||||||
However, within the default arguments, it is not possible to call the procedures (described later) or assign mutable objects.
|
However, within the default arguments, it is not possible to call the procedures (described later) or assign mutable objects.
|
||||||
|
|
||||||
```erg
|
```erg
|
||||||
f x |= p! 1 = ... # NG
|
f x := p! 1 = ... # NG
|
||||||
```
|
```
|
||||||
|
|
||||||
Also, the argument just defined cannot be used as the value passed to the default argument.
|
Also, the argument just defined cannot be used as the value passed to the default argument.
|
||||||
|
|
||||||
```erg
|
```erg
|
||||||
f x |= 1, y |= x = ... # NG
|
f x := 1, y := x = ... # NG
|
||||||
```
|
```
|
||||||
|
|
||||||
## Variable-length arguments
|
## Variable-length arguments
|
||||||
|
|
|
@ -134,20 +134,20 @@ f {x: Int; y: Int} = ...
|
||||||
|
|
||||||
```erg
|
```erg
|
||||||
Point = Inherit {x = Int; y = Int}
|
Point = Inherit {x = Int; y = Int}
|
||||||
p = Point.{x = 1; y = 2}
|
p = Point::{x = 1; y = 2}
|
||||||
Point.{x; y} = p
|
Point::{x; y} = p
|
||||||
|
|
||||||
Nil T = Class Impl: Phantom T
|
Nil T = Class Impl := Phantom T
|
||||||
Cons T = Inherit {head = T; rest = List T}
|
Cons T = Inherit {head = T; rest = List T}
|
||||||
List T = Enum Nil(T), Cons(T)
|
List T = Enum Nil(T), Cons(T)
|
||||||
List T.
|
List T.
|
||||||
first self =
|
first self =
|
||||||
match self:
|
match self:
|
||||||
Cons.{head; ...} -> x
|
Cons::{head; ...} -> x
|
||||||
_ -> ...
|
_ -> ...
|
||||||
second self =
|
second self =
|
||||||
match self:
|
match self:
|
||||||
Cons.{rest=Cons.{head; ...} ; ...} -> head
|
Cons::{rest=Cons::{head; ...} ; ...} -> head
|
||||||
_ -> ...
|
_ -> ...
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,21 @@ X = ...
|
||||||
X = deco(X)
|
X = deco(X)
|
||||||
```
|
```
|
||||||
|
|
||||||
Since Erg does not allow reassignment, the above code will not pass, and a decorator is required.
|
Erg does not allow reassignment of variables, so the above code will not pass.
|
||||||
|
For a simple variable, `X = deco(...)` is the same, but for instant blocks and subroutines, you can't do that, so you need decorators.
|
||||||
|
|
||||||
|
```erg
|
||||||
|
@deco
|
||||||
|
f x = ...
|
||||||
|
y = ...
|
||||||
|
x + y
|
||||||
|
|
||||||
|
# Can also prevent code from going horizontal.
|
||||||
|
@LongNameDeco1
|
||||||
|
@LongNameDeco2
|
||||||
|
C = Class ...
|
||||||
|
```
|
||||||
|
|
||||||
Here are some frequently used built-in decorators.
|
Here are some frequently used built-in decorators.
|
||||||
|
|
||||||
## Inheritable
|
## Inheritable
|
||||||
|
@ -37,7 +51,7 @@ Use to override an attribute, which by default Erg will fail if you try to defin
|
||||||
|
|
||||||
## Impl
|
## Impl
|
||||||
|
|
||||||
Indicates implementation of the argument trace.
|
Indicates implementation of traits.
|
||||||
|
|
||||||
```erg
|
```erg
|
||||||
ClosedAdd = Trait {
|
ClosedAdd = Trait {
|
||||||
|
@ -47,11 +61,11 @@ ClosedSub = Trait {
|
||||||
. `_-_` = Self.(Self) -> Self
|
. `_-_` = Self.(Self) -> Self
|
||||||
}
|
}
|
||||||
|
|
||||||
C = Class({i = Int}, Impl: ClosedAdd and ClosedSub)
|
C = Class {i = Int}
|
||||||
C.
|
C.
|
||||||
@Impl Add.
|
@Impl ClosedAdd
|
||||||
`_+_` self, other = C.new {i = self::i + other::i}
|
`_+_` self, other = C.new {i = self::i + other::i}
|
||||||
@Impl Sub
|
@Impl ClosedSub
|
||||||
`_-_` self, other = C.new {i = self::i - other::}
|
`_-_` self, other = C.new {i = self::i - other::}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -70,9 +84,9 @@ Add R = Trait {
|
||||||
@Attach AddForInt, AddForOdd
|
@Attach AddForInt, AddForOdd
|
||||||
ClosedAdd = Subsume Add(Self)
|
ClosedAdd = Subsume Add(Self)
|
||||||
|
|
||||||
AddForInt = Patch(Int, Impl: ClosedAdd)
|
AddForInt = Patch(Int, Impl := ClosedAdd)
|
||||||
AddForInt.AddO = Int
|
AddForInt.AddO = Int
|
||||||
AddForOdd = Patch(Odd, Impl: ClosedAdd)
|
AddForOdd = Patch(Odd, Impl := ClosedAdd)
|
||||||
AddForOdd.AddO = Even
|
AddForOdd.AddO = Even
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -86,7 +100,7 @@ assert Int.AddO == Int
|
||||||
assert Odd.AddO == Even
|
assert Odd.AddO == Even
|
||||||
```
|
```
|
||||||
|
|
||||||
Internally, they are only connected together using the trait's `.attach` method. If there is a conflict, it can be removed using the trace's `.detach` method.
|
Internally, they are only connected together using the trait's `.attach` method. If there is a conflict, it can be removed using the trait's `.detach` method.
|
||||||
|
|
||||||
```erg
|
```erg
|
||||||
@Attach X
|
@Attach X
|
||||||
|
|
|
@ -17,7 +17,7 @@ It looks like just an increase in `|>`, but since the bond strength is low, the
|
||||||
``` erg
|
``` erg
|
||||||
rand = -1.0..1.0 |>.sample!()
|
rand = -1.0..1.0 |>.sample!()
|
||||||
log rand # 0.2597...
|
log rand # 0.2597...
|
||||||
1+1*2 |>.times do log("a", end: "") # aaa
|
1+1*2 |>.times do log("a", end := "") # aaa
|
||||||
# without `|>`, the following will be `evens = (1..100).iter().filter(i -> i % 2 == 0).collect(Array)`
|
# without `|>`, the following will be `evens = (1..100).iter().filter(i -> i % 2 == 0).collect(Array)`
|
||||||
evens = 1..100 |>.iter |>.filter i -> i % 2 == 0 |>.collect Array
|
evens = 1..100 |>.iter |>.filter i -> i % 2 == 0 |>.collect Array
|
||||||
# or
|
# or
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
# The Grammar of Erg (ver 0.1.0, provisional)
|
# The Grammar of Erg (ver 0.1.0, provisional)
|
||||||
special_op ::= '=' | '->' | '=>' | '.' | ',' | ':' | '|>' | '&'
|
special_op ::= '=' | '->' | '=>' | '.' | ',' | ':' | '::' | '|>' | '&'
|
||||||
separator ::= ';' | '\n'
|
separator ::= ';' | '\n'
|
||||||
escape ::= '\'
|
escape ::= '\'
|
||||||
comment_marker ::= '#'
|
comment_marker ::= '#'
|
||||||
comment ::= '#' .* '\n'
|
|
||||||
reserved_symbol ::= special_op | separator | comment_marker
|
reserved_symbol ::= special_op | separator | comment_marker
|
||||||
number ::= [0-9]
|
number ::= [0-9]
|
||||||
first_last_dight ::= number
|
first_last_dight ::= number
|
||||||
|
@ -28,7 +27,8 @@ parenthesis ::= '(' | ')'
|
||||||
bracket ::= '{' | '}'
|
bracket ::= '{' | '}'
|
||||||
square_bracket ::= '[' | ']'
|
square_bracket ::= '[' | ']'
|
||||||
enclosure ::= parenthesis | bracket | square_bracket
|
enclosure ::= parenthesis | bracket | square_bracket
|
||||||
infix_op ::= '+' | '-' | '*' | '/' | '//' | '**' | '%' | '&&' | '||' | '^^' | '<' | '<=' | '>' | '>='
|
infix_op ::= '+' | '-' | '*' | '/' | '//' | '**'
|
||||||
|
| '%' | '&&' | '||' | '^^' | '<' | '<=' | '>' | '>='
|
||||||
| 'and' | 'or' | 'is' | 'as' | 'isnot' | 'in' | 'notin' | 'dot' | 'cross'
|
| 'and' | 'or' | 'is' | 'as' | 'isnot' | 'in' | 'notin' | 'dot' | 'cross'
|
||||||
prefix_op ::= '+' | '-' | '*' | '**' | '..' | '..<' | '~' | '&' | '!'
|
prefix_op ::= '+' | '-' | '*' | '**' | '..' | '..<' | '~' | '&' | '!'
|
||||||
postfix_op ::= '?' | '..' | '<..'
|
postfix_op ::= '?' | '..' | '<..'
|
||||||
|
@ -68,10 +68,21 @@ decorator ::= call
|
||||||
lambda_func ::= params_opt_t '->' body
|
lambda_func ::= params_opt_t '->' body
|
||||||
lambda_proc ::= params_opt_t '=>' body
|
lambda_proc ::= params_opt_t '=>' body
|
||||||
lambda ::= lambda_func | lambda_proc
|
lambda ::= lambda_func | lambda_proc
|
||||||
array ::= '[' enc_args ']'
|
normal_array ::= '[' enc_args ']'
|
||||||
array_comprehension ::= '[' expr | (generator)+ ']'
|
array_comprehension ::= '[' expr | (generator)+ ']'
|
||||||
anonymous_type ::= '{' enc_args '}'
|
array ::= normal_array | array_comprehension
|
||||||
|
record ::= '{' '=' '}'
|
||||||
|
| '{' def (';' def)* ';'? '}'
|
||||||
|
set ::= '{' '}'
|
||||||
|
| '{' expr (',' expr)* ','? '}'
|
||||||
|
dict ::= '{' ':' '}'
|
||||||
|
| '{' symbol ':' expr (',' symbol ':' expr)* ','? '}'
|
||||||
|
tuple ::= '(' ')'
|
||||||
|
| '(' expr (',' expr)* ','? ')'
|
||||||
indent ::= /* ... */
|
indent ::= /* ... */
|
||||||
expr ::= accessor | literal | prefix | infix | postfix | call | def | lambda
|
expr ::= accessor | literal
|
||||||
|
| prefix | infix | postfix
|
||||||
|
| array | record | set | dict | tuple
|
||||||
|
| call | def | lambda
|
||||||
line ::= expr separator+
|
line ::= expr separator+
|
||||||
program ::= expr? | (line | comment)*
|
program ::= expr? | (line | comment)*
|
||||||
|
|
|
@ -70,7 +70,7 @@ You can also use a subtype specification when defining a class to statically che
|
||||||
|
|
||||||
```erg
|
```erg
|
||||||
# Class C is a subtype of Show
|
# Class C is a subtype of Show
|
||||||
C = Class Object, Impl: Show
|
C = Class Object, Impl := Show
|
||||||
C.show self = ... # Show's required attributes.
|
C.show self = ... # Show's required attributes.
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@ Point2D <: Norm # TypeError: Point2D is not a subtype of Norm
|
||||||
Point2D = Class {.x = Int; .y = Int}
|
Point2D = Class {.x = Int; .y = Int}
|
||||||
```
|
```
|
||||||
|
|
||||||
Traits, like structural types, can apply operations such as composition, substitution, and elimination (e.g. `T and U`). The resulting trace is called an instant trace.
|
Traits, like structural types, can apply operations such as composition, substitution, and elimination (e.g. `T and U`). The resulting trait is called an instant trait.
|
||||||
|
|
||||||
```erg
|
```erg
|
||||||
T = Trait {.x = Int}
|
T = Trait {.x = Int}
|
||||||
|
@ -49,7 +49,7 @@ assert points.iter().map(x -> x.norm()).collect(Array) == [5, 25].
|
||||||
|
|
||||||
## Trait inclusion
|
## Trait inclusion
|
||||||
|
|
||||||
The expansion operator `...` allows you to define a trace that contains a certain trace as a supertype. This is called the __subsumption__ of a trace.
|
The expansion operator `...` allows you to define a trait that contains a certain trait as a supertype. This is called the __subsumption__ of a trait.
|
||||||
In the example below, `BinAddSub` subsumes `BinAdd` and `BinSub`.
|
In the example below, `BinAddSub` subsumes `BinAdd` and `BinSub`.
|
||||||
This corresponds to Inheritance in a class, but unlike Inheritance, multiple base types can be combined using `and`. Traits that are partially excluded by `not` are also allowed.
|
This corresponds to Inheritance in a class, but unlike Inheritance, multiple base types can be combined using `and`. Traits that are partially excluded by `not` are also allowed.
|
||||||
|
|
||||||
|
@ -87,7 +87,7 @@ assert add(C.new(1), C.new(2)) == C.new(3)
|
||||||
```
|
```
|
||||||
|
|
||||||
Nominal traits cannot be used simply by implementing a request method, but must be explicitly declared to have been implemented.
|
Nominal traits cannot be used simply by implementing a request method, but must be explicitly declared to have been implemented.
|
||||||
In the following example, `add` cannot be used with an argument of type `C` because there is no explicit declaration of implementation. It must be `C = Class {i = Int}, Impl: Add`.
|
In the following example, `add` cannot be used with an argument of type `C` because there is no explicit declaration of implementation. It must be `C = Class {i = Int}, Impl := Add`.
|
||||||
|
|
||||||
```erg
|
```erg
|
||||||
Add = Trait {
|
Add = Trait {
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
[](https://gezf7g7pd5.execute-api.ap-northeast-1.amazonaws.com/default/source_up_to_date?owner=erg-lang&repos=erg&ref=main&path=doc/EN/syntax/type/05_inheritance.md&commit_hash=8586bf6f02bd04fd5c823b3a476238881ef037de)
|
[](https://gezf7g7pd5.execute-api.ap-northeast-1.amazonaws.com/default/source_up_to_date?owner=erg-lang&repos=erg&ref=main&path=doc/EN/syntax/type/05_inheritance.md&commit_hash=8586bf6f02bd04fd5c823b3a476238881ef037de)
|
||||||
|
|
||||||
Inheritance allows you to define a new class that adds functionality or specialization to an existing class.
|
Inheritance allows you to define a new class that adds functionality or specialization to an existing class.
|
||||||
Inheritance is similar to inclusion in a trace. The inherited class becomes a subtype of the original class.
|
Inheritance is similar to inclusion in a trait. The inherited class becomes a subtype of the original class.
|
||||||
|
|
||||||
```erg
|
```erg
|
||||||
NewInt = Inherit Int
|
NewInt = Inherit Int
|
||||||
|
@ -126,7 +126,7 @@ Although it is not possible to replace traits at inheritance time, there are exa
|
||||||
For example, `Int`, a subtype of `Real` (which implements `Add()`), appears to reimplement `Add()`.
|
For example, `Int`, a subtype of `Real` (which implements `Add()`), appears to reimplement `Add()`.
|
||||||
|
|
||||||
```erg
|
```erg
|
||||||
Int = Class ... , Impl: Add() and ...
|
Int = Class ... , Impl := Add() and ...
|
||||||
```
|
```
|
||||||
|
|
||||||
But in fact `Add()` in `Real` stands for `Add(Real, Real)`, and in `Int` it is just overwritten by `Add(Int, Int)`.
|
But in fact `Add()` in `Real` stands for `Add(Real, Real)`, and in `Int` it is just overwritten by `Add(Int, Int)`.
|
||||||
|
|
|
@ -113,7 +113,7 @@ Reverse = Trait {
|
||||||
.reverse = Self.() -> Self
|
.reverse = Self.() -> Self
|
||||||
}
|
}
|
||||||
|
|
||||||
StrReverse = Patch Str, Impl: Reverse
|
StrReverse = Patch Str, Impl := Reverse
|
||||||
StrReverse.
|
StrReverse.
|
||||||
reverse self =
|
reverse self =
|
||||||
self.iter().rev().collect(Str)
|
self.iter().rev().collect(Str)
|
||||||
|
@ -128,7 +128,7 @@ NumericStr = Inherit Str
|
||||||
NumericStr.
|
NumericStr.
|
||||||
...
|
...
|
||||||
|
|
||||||
NumStrRev = Patch NumericStr, Impl: Reverse
|
NumStrRev = Patch NumericStr, Impl := Reverse
|
||||||
NumStrRev.
|
NumStrRev.
|
||||||
...
|
...
|
||||||
# DuplicatePatchError: NumericStr is already associated with `Reverse`
|
# DuplicatePatchError: NumericStr is already associated with `Reverse`
|
||||||
|
@ -160,7 +160,7 @@ Reverse = Trait {
|
||||||
.reverse = Self.() -> Self
|
.reverse = Self.() -> Self
|
||||||
}
|
}
|
||||||
|
|
||||||
StrReverse = Patch(Str, Impl: Reverse)
|
StrReverse = Patch(Str, Impl := Reverse)
|
||||||
StrReverse.
|
StrReverse.
|
||||||
reverse self =
|
reverse self =
|
||||||
self.iter().rev().collect(Str)
|
self.iter().rev().collect(Str)
|
||||||
|
|
|
@ -34,7 +34,7 @@ f x =
|
||||||
print! f::x, module::x
|
print! f::x, module::x
|
||||||
|
|
||||||
# Phantom types have an attribute called Phantom that has the same value as the type argument
|
# Phantom types have an attribute called Phantom that has the same value as the type argument
|
||||||
T X: Int = Class Impl: Phantom X
|
T X: Int = Class Impl := Phantom X
|
||||||
T(X).
|
T(X).
|
||||||
x self = self::Phantom
|
x self = self::Phantom
|
||||||
|
|
||||||
|
@ -46,7 +46,7 @@ Transitions are specified with `~>`.
|
||||||
|
|
||||||
```erg
|
```erg
|
||||||
# Note that `Id` is an immutable type and cannot be transitioned.
|
# Note that `Id` is an immutable type and cannot be transitioned.
|
||||||
VM!(State: {"stopped", "running"}! |= _, Id: Nat |= _) = Class(... State).
|
VM!(State: {"stopped", "running"}! := _, Id: Nat := _) = Class(... State).
|
||||||
VM!().
|
VM!().
|
||||||
# Variables that do not change can be omitted by passing `_`.
|
# Variables that do not change can be omitted by passing `_`.
|
||||||
start! ref! self("stopped" ~> "running") =
|
start! ref! self("stopped" ~> "running") =
|
||||||
|
|
|
@ -53,7 +53,7 @@ assert not c in D
|
||||||
## Subtyping of subroutines
|
## Subtyping of subroutines
|
||||||
|
|
||||||
Arguments and return values of subroutines take only a single class.
|
Arguments and return values of subroutines take only a single class.
|
||||||
In other words, you cannot directly specify a structural type or a trace as the type of a function.
|
In other words, you cannot directly specify a structural type or a trait as the type of a function.
|
||||||
It must be specified as "a single class that is a subtype of that type" using the partial type specification.
|
It must be specified as "a single class that is a subtype of that type" using the partial type specification.
|
||||||
|
|
||||||
```erg
|
```erg
|
||||||
|
@ -66,7 +66,7 @@ f2 x, y: Add = x + y
|
||||||
f3<A <: Add> x, y: A = x + y
|
f3<A <: Add> x, y: A = x + y
|
||||||
```
|
```
|
||||||
|
|
||||||
Type inference in subroutines also follows this rule. When a variable in a subroutine has an unspecified type, the compiler first checks to see if it is an instance of one of the classes, and if not, looks for a match in the scope of the trace. If it still cannot find one, a compile error occurs. This error can be resolved by using a structural type, but since inferring an anonymous type may have unintended consequences for the programmer, it is designed to be explicitly specified by the programmer with `Structural`.
|
Type inference in subroutines also follows this rule. When a variable in a subroutine has an unspecified type, the compiler first checks to see if it is an instance of one of the classes, and if not, looks for a match in the scope of the trait. If it still cannot find one, a compile error occurs. This error can be resolved by using a structural type, but since inferring an anonymous type may have unintended consequences for the programmer, it is designed to be explicitly specified by the programmer with `Structural`.
|
||||||
|
|
||||||
## Class upcasting
|
## Class upcasting
|
||||||
|
|
||||||
|
|
|
@ -5,8 +5,8 @@
|
||||||
Erg can create Generalized Algebraic Data Types (GADTs) by classifying Or (Union) types.
|
Erg can create Generalized Algebraic Data Types (GADTs) by classifying Or (Union) types.
|
||||||
|
|
||||||
```erg
|
```erg
|
||||||
Nil T = Class(Impl: Phantom T)
|
Nil T = Class(Impl := Phantom T)
|
||||||
Cons T = Class {head = T; rest = List T}, Impl: Unpack
|
Cons T = Class {head = T; rest = List T}, Impl := Unpack
|
||||||
List T: Type = Class(Nil T or Cons T)
|
List T: Type = Class(Nil T or Cons T)
|
||||||
List.
|
List.
|
||||||
nil|T|() = Self(T).new Nil(T).new()
|
nil|T|() = Self(T).new Nil(T).new()
|
||||||
|
@ -32,8 +32,8 @@ For example, the `.head` method above will give a runtime error if the contents
|
||||||
|
|
||||||
```erg
|
```erg
|
||||||
List: (Type, {"Empty", "Nonempty"}) -> Type
|
List: (Type, {"Empty", "Nonempty"}) -> Type
|
||||||
List T, "Empty" = Class(Impl: Phantom T)
|
List T, "Empty" = Class(Impl := Phantom T)
|
||||||
List T, "Nonempty" = Class {head = T; rest = List(T, _)}, Impl: Unpack
|
List T, "Nonempty" = Class {head = T; rest = List(T, _)}, Impl := Unpack
|
||||||
List.
|
List.
|
||||||
nil|T|() = Self(T, "Empty").new Nil(T).new()
|
nil|T|() = Self(T, "Empty").new Nil(T).new()
|
||||||
cons head, rest | T = Self(T, "Nonempty").new {head; rest}
|
cons head, rest | T = Self(T, "Nonempty").new {head; rest}
|
||||||
|
@ -50,8 +50,8 @@ Erg allows for further refinement, defining a list with length.
|
||||||
|
|
||||||
```erg
|
```erg
|
||||||
List: (Type, Nat) -> Type
|
List: (Type, Nat) -> Type
|
||||||
List T, 0 = Class(Impl: Phantom T)
|
List T, 0 = Class(Impl := Phantom T)
|
||||||
List T, N = Class {head = T; rest = List(T, N-1)}, Impl: Unpack
|
List T, N = Class {head = T; rest = List(T, N-1)}, Impl := Unpack
|
||||||
List.
|
List.
|
||||||
nil|T|() = Self(T, 0).new Nil(T).new()
|
nil|T|() = Self(T, 0).new Nil(T).new()
|
||||||
cons head, rest | T, N = Self(T, N).new {head; rest}
|
cons head, rest | T, N = Self(T, N).new {head; rest}
|
||||||
|
|
|
@ -5,25 +5,25 @@
|
||||||
First, let's look at an example of the use of default parameters.
|
First, let's look at an example of the use of default parameters.
|
||||||
|
|
||||||
```erg
|
```erg
|
||||||
f: (Int, Int, z |= Int) -> Int
|
f: (Int, Int, z := Int) -> Int
|
||||||
f(x, y, z |= 0) = x + y + z
|
f(x, y, z := 0) = x + y + z
|
||||||
|
|
||||||
g: (Int, Int, z |= Int, w |= Int) -> Int
|
g: (Int, Int, z := Int, w := Int) -> Int
|
||||||
g(x, y, z |= 0, w |= 1) = x + y + z + w
|
g(x, y, z := 0, w := 1) = x + y + z + w
|
||||||
|
|
||||||
fold: ((Int, Int) -> Int, [Int], acc |= Int) -> Int
|
fold: ((Int, Int) -> Int, [Int], acc := Int) -> Int
|
||||||
fold(f, [], acc) = acc
|
fold(f, [], acc) = acc
|
||||||
fold(f, arr, acc |= 0) = fold(f, arr[1...]) , f(acc, arr[0]))
|
fold(f, arr, acc := 0) = fold(f, arr[1...]) , f(acc, arr[0]))
|
||||||
assert fold(f, [1, 2, 3]) == 6
|
assert fold(f, [1, 2, 3]) == 6
|
||||||
assert fold(g, [1, 2, 3]) == 8
|
assert fold(g, [1, 2, 3]) == 8
|
||||||
```
|
```
|
||||||
|
|
||||||
The parameters after `|=` are default parameters.
|
The parameters after `:=` are default parameters.
|
||||||
The subtyping rules are as follows.
|
The subtyping rules are as follows.
|
||||||
|
|
||||||
```erg
|
```erg
|
||||||
((X, y |= Y) -> Z) <: (X -> Z)
|
((X, y := Y) -> Z) <: (X -> Z)
|
||||||
((X, y |= Y, ...) -> Z) -> Z) <: ((X, ...) -> Z)
|
((X, y := Y, ...) -> Z) -> Z) <: ((X, ...) -> Z)
|
||||||
```
|
```
|
||||||
|
|
||||||
The first means that a function with a default parameter is identical to a function without it.
|
The first means that a function with a default parameter is identical to a function without it.
|
||||||
|
|
|
@ -6,7 +6,7 @@ A marker trait is a trait with no required attributes. That is, it can be Impl w
|
||||||
It may seem meaningless without the required attribute, but it registers the information that it belongs to that trait, so that patch methods can be used and the compiler can give it special treatment.
|
It may seem meaningless without the required attribute, but it registers the information that it belongs to that trait, so that patch methods can be used and the compiler can give it special treatment.
|
||||||
|
|
||||||
All marker traits are encompassed by the `Marker` trait.
|
All marker traits are encompassed by the `Marker` trait.
|
||||||
The `Light` provided in the standard is a kind of `marker` trace.
|
The `Light` provided in the standard is a kind of marker trait.
|
||||||
|
|
||||||
```erg
|
```erg
|
||||||
Light = Subsume Marker
|
Light = Subsume Marker
|
||||||
|
@ -19,7 +19,7 @@ Person = Class {.name = Str; .age = Nat} and Light
|
||||||
```erg
|
```erg
|
||||||
M = Subsume Marker
|
M = Subsume Marker
|
||||||
|
|
||||||
MarkedInt = Inherit Int, Impl: M
|
MarkedInt = Inherit Int, Impl := M
|
||||||
|
|
||||||
i = MarkedInt.new(2)
|
i = MarkedInt.new(2)
|
||||||
assert i + 1 == 2
|
assert i + 1 == 2
|
||||||
|
@ -29,5 +29,5 @@ assert i in M
|
||||||
The marker class can also be removed with the `Excluding` argument.
|
The marker class can also be removed with the `Excluding` argument.
|
||||||
|
|
||||||
```erg
|
```erg
|
||||||
NInt = Inherit MarkedInt, Impl: N, Excluding: M
|
NInt = Inherit MarkedInt, Impl := N, Excluding: M
|
||||||
```
|
```
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
The ``T!`` type is described as a box type that can be replaced by any ``T`` type object.
|
The ``T!`` type is described as a box type that can be replaced by any ``T`` type object.
|
||||||
|
|
||||||
```erg
|
```erg
|
||||||
Particle!State: {"base", "excited"}! = Class(... Impl: Phantom State)
|
Particle!State: {"base", "excited"}! = Class(... Impl := Phantom State)
|
||||||
Particle!
|
Particle!
|
||||||
# This method moves the State from "base" to "excited".
|
# This method moves the State from "base" to "excited".
|
||||||
apply_electric_field!(ref! self("base" ~> "excited"), field: Vector) = ...
|
apply_electric_field!(ref! self("base" ~> "excited"), field: Vector) = ...
|
||||||
|
@ -33,7 +33,7 @@ Incidentally, the `[T; !N]` type is the sugar-coated syntax of the `ArrayWithLen
|
||||||
Mutable structure types can of course be user-defined. Note, however, that there are some differences from invariant structure types in terms of the construction method.
|
Mutable structure types can of course be user-defined. Note, however, that there are some differences from invariant structure types in terms of the construction method.
|
||||||
|
|
||||||
```erg
|
```erg
|
||||||
Nil T = Class(Impl: Phantom T)
|
Nil T = Class(Impl := Phantom T)
|
||||||
List T, !0 = Inherit Nil T
|
List T, !0 = Inherit Nil T
|
||||||
List T, N: Nat! = Class {head = T; rest = List(T, !N-1)}
|
List T, N: Nat! = Class {head = T; rest = List(T, !N-1)}
|
||||||
List(T, !N).
|
List(T, !N).
|
||||||
|
|
|
@ -2,17 +2,17 @@
|
||||||
|
|
||||||
[](https://gezf7g7pd5.execute-api.ap-northeast-1.amazonaws.com/default/source_up_to_date?owner=erg-lang&repos=erg&ref=main&path=doc/EN/syntax/type/advanced/overloading.md&commit_hash=317b5973c354984891523d14a5e6e8f1cc3923ec)
|
[](https://gezf7g7pd5.execute-api.ap-northeast-1.amazonaws.com/default/source_up_to_date?owner=erg-lang&repos=erg&ref=main&path=doc/EN/syntax/type/advanced/overloading.md&commit_hash=317b5973c354984891523d14a5e6e8f1cc3923ec)
|
||||||
|
|
||||||
Erg does not support __ad hoc polymorphism__. That is, multiple definitions of functions and Kinds (overloading) are not possible. However, you can reproduce the overloading behavior by using a combination of a trace class and a patch.
|
Erg does not support __ad hoc polymorphism__. That is, multiple definitions of functions and Kinds (overloading) are not possible. However, you can reproduce the overloading behavior by using a combination of a trait and a patch.
|
||||||
You can use traits instead of trait classes, but then all types that implement `.add1` will be covered.
|
You can use traits instead of trait classes, but then all types that implement `.add1` will be covered.
|
||||||
|
|
||||||
```erg
|
```erg
|
||||||
Add1 = Trait {
|
Add1 = Trait {
|
||||||
.add1: Self.() -> Self
|
.add1: Self.() -> Self
|
||||||
}
|
}
|
||||||
IntAdd1 = Patch Int, Impl: Add1
|
IntAdd1 = Patch Int, Impl := Add1
|
||||||
IntAdd1.
|
IntAdd1.
|
||||||
add1 self = self + 1
|
add1 self = self + 1
|
||||||
RatioAdd1 = Patch Ratio, Impl: Add1
|
RatioAdd1 = Patch Ratio, Impl := Add1
|
||||||
RatioAdd1.
|
RatioAdd1.
|
||||||
add1 self = self + 1.0
|
add1 self = self + 1.0
|
||||||
|
|
||||||
|
@ -37,7 +37,7 @@ Also, overloading of types with different numbers of arguments can be reproduced
|
||||||
```erg
|
```erg
|
||||||
C = Class {.x = Int; .y = Int}
|
C = Class {.x = Int; .y = Int}
|
||||||
C.
|
C.
|
||||||
new(x, y |= 0) = Self::__new__ {.x; .y}
|
new(x, y := 0) = Self::__new__ {.x; .y}
|
||||||
|
|
||||||
assert C.new(0, 0) == C.new(0)
|
assert C.new(0, 0) == C.new(0)
|
||||||
```
|
```
|
||||||
|
@ -64,7 +64,7 @@ Second, it is incompatible with default arguments. When a function with default
|
||||||
|
|
||||||
```erg
|
```erg
|
||||||
f x: Int = ...
|
f x: Int = ...
|
||||||
f(x: Int, y |= 0) = ...
|
f(x: Int, y := 0) = ...
|
||||||
|
|
||||||
f(1) # which is chosen?
|
f(1) # which is chosen?
|
||||||
```
|
```
|
||||||
|
|
|
@ -34,7 +34,7 @@ This code passes compilation. But it's a little tricky to understand the intent,
|
||||||
In such a case, a phantom type is just what you need. A phantom type is a generalized type of size 0.
|
In such a case, a phantom type is just what you need. A phantom type is a generalized type of size 0.
|
||||||
|
|
||||||
```erg
|
```erg
|
||||||
Nil T = Class(Impl: Phantom T)
|
Nil T = Class(Impl := Phantom T)
|
||||||
List T, 0 = Inherit Nil T
|
List T, 0 = Inherit Nil T
|
||||||
List T, N: Nat = Class {head = T; rest = List(T, N-1)}
|
List T, N: Nat = Class {head = T; rest = List(T, N-1)}
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ Add R = Trait {
|
||||||
.AddO = Type
|
.AddO = Type
|
||||||
}
|
}
|
||||||
|
|
||||||
AddForInt = Patch(Int, Impl: Add Int)
|
AddForInt = Patch(Int, Impl := Add Int)
|
||||||
AddForInt.
|
AddForInt.
|
||||||
AddO = Int
|
AddO = Int
|
||||||
```
|
```
|
||||||
|
|
|
@ -42,7 +42,7 @@ Add R = Trait {
|
||||||
}
|
}
|
||||||
ClosedAdd = Subsume Add(Self)
|
ClosedAdd = Subsume Add(Self)
|
||||||
|
|
||||||
ClosedAddForInt = Patch(Int, Impl: ClosedAdd)
|
ClosedAddForInt = Patch(Int, Impl := ClosedAdd)
|
||||||
ClosedAddForInt.
|
ClosedAddForInt.
|
||||||
AddO = Int
|
AddO = Int
|
||||||
|
|
||||||
|
|
|
@ -47,15 +47,15 @@ If you implement `Singleton`, classes and instances are identical.
|
||||||
Also, if you use `Enum`, the type of choice is automatically defined as a redirect attribute.
|
Also, if you use `Enum`, the type of choice is automatically defined as a redirect attribute.
|
||||||
|
|
||||||
```erg
|
```erg
|
||||||
Ok = Class Impl: Singleton
|
Ok = Class Impl := Singleton
|
||||||
Err = Class Impl: Singleton
|
Err = Class Impl := Singleton
|
||||||
ErrWithInfo = Inherit {info = Str}
|
ErrWithInfo = Inherit {info = Str}
|
||||||
Status = Enum Ok, Err, ErrWithInfo
|
Status = Enum Ok, Err, ErrWithInfo
|
||||||
stat: Status = Status.cons(ErrWithInfo) {info = "error caused by ..."}
|
stat: Status = Status.cons(ErrWithInfo) {info = "error caused by ..."}
|
||||||
match! stat:
|
match! stat:
|
||||||
Status.Ok -> ...
|
Status.Ok -> ...
|
||||||
Status.Err -> ...
|
Status.Err -> ...
|
||||||
Status.ErrWithInfo.{info;} -> ...
|
Status.ErrWithInfo::{info} -> ...
|
||||||
```
|
```
|
||||||
|
|
||||||
```erg
|
```erg
|
||||||
|
|
|
@ -114,15 +114,15 @@ ClassはInt, Bool, Strなど
|
||||||
|
|
||||||
Complex以外の例として、Vector, Matrix, TensorはNum(Matrix, Tensorの*はそれぞれdot, productと同じ)
|
Complex以外の例として、Vector, Matrix, TensorはNum(Matrix, Tensorの*はそれぞれdot, productと同じ)
|
||||||
|
|
||||||
### Complex (= Inherit(Object, Impl: Num))
|
### Complex (= Inherit(Object, Impl := Num))
|
||||||
|
|
||||||
* `imag: Ratio`: 虚部を返す
|
* `imag: Ratio`: 虚部を返す
|
||||||
* `real: Ratio`: 実部を返す
|
* `real: Ratio`: 実部を返す
|
||||||
* `conjugate self -> Complex`: 共役複素数を返す
|
* `conjugate self -> Complex`: 共役複素数を返す
|
||||||
|
|
||||||
### Float (= Inherit(FloatComplex, Impl: Num))
|
### Float (= Inherit(FloatComplex, Impl := Num))
|
||||||
|
|
||||||
### Ratio (= Inherit(Complex, Impl: Num))
|
### Ratio (= Inherit(Complex, Impl := Num))
|
||||||
|
|
||||||
* `numerator: Int`: 分子を返す
|
* `numerator: Int`: 分子を返す
|
||||||
* `denominator: Int`: 分母を返す
|
* `denominator: Int`: 分母を返す
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# Interval begin, end: WellOrder
|
# Interval begin, end := WellOrder
|
||||||
|
|
||||||
整列集合型(WellOrder)の部分型を表す型です。Interval型にはPreOpen(x<..y)などの派生型が存在します。
|
整列集合型(WellOrder)の部分型を表す型です。Interval型にはPreOpen(x<..y)などの派生型が存在します。
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# 型推論アルゴリズム
|
# 型推論アルゴリズム
|
||||||
|
|
||||||
> __Info__: この項は編集中であり、一部に間違いを含む可能性があります。
|
> __Warning__: この項は編集中であり、一部に間違いを含む可能性があります。
|
||||||
|
|
||||||
以下で用いる表記方法を示します。
|
以下で用いる表記方法を示します。
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# 基本事項
|
# 基本事項
|
||||||
|
|
||||||
> __Info__: 本ドキュメントは未完成です。校正(文体、正しいリンクが張られているか、など)がなされていません。また、Ergの文法はバージョン0.*の間に破壊的変更が加えられる可能性があり、それに伴うドキュメントの更新が追いついていない可能性があります。予めご了承ください。
|
> __Warning__: 本ドキュメントは未完成です。校正(文体、正しいリンクが張られているか、など)がなされていません。また、Ergの文法はバージョン0.*の間に破壊的変更が加えられる可能性があり、それに伴うドキュメントの更新が追いついていない可能性があります。予めご了承ください。
|
||||||
> また、本ドキュメントの誤りを見つけた場合は、[こちらのフォーム](https://forms.gle/HtLYRfYzWCAaeTGb6)または[GitHubリポジトリ](https://github.com/mtshiba/TheErgBook/issues/new)から修正の提案をしていただけると幸いです。
|
> また、本ドキュメントの誤りを見つけた場合は、[こちらのフォーム](https://forms.gle/HtLYRfYzWCAaeTGb6)または[GitHubリポジトリ](https://github.com/mtshiba/TheErgBook/issues/new)から修正の提案をしていただけると幸いです。
|
||||||
|
|
||||||
本ドキュメントは、Ergの基本文法について解説するものです。[標準API](../API/index.md)や[Ergコントリビューター向けの内部資料](../dev_guide/index.md)は別のディレクトリに置かれています。
|
本ドキュメントは、Ergの基本文法について解説するものです。[標準API](../API/index.md)や[Ergコントリビューター向けの内部資料](../dev_guide/index.md)は別のディレクトリに置かれています。
|
||||||
|
|
|
@ -39,7 +39,7 @@ T = Trait {
|
||||||
.f = (x: Int, y: Int): Int
|
.f = (x: Int, y: Int): Int
|
||||||
}
|
}
|
||||||
|
|
||||||
C = Class(U, Impl: T)
|
C = Class(U, Impl := T)
|
||||||
C.f(a: Int, b: Int): Int = ... # TypeError: `.f` must be type of `(x: Int, y: Int) -> Int`, not `(a: Int, b: Int) -> Int`
|
C.f(a: Int, b: Int): Int = ... # TypeError: `.f` must be type of `(x: Int, y: Int) -> Int`, not `(a: Int, b: Int) -> Int`
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -84,10 +84,10 @@ f x:
|
||||||
|
|
||||||
ある引数が大抵の場合決まりきっており省略できるようにしたい場合、デフォルト引数を使うと良いでしょう。
|
ある引数が大抵の場合決まりきっており省略できるようにしたい場合、デフォルト引数を使うと良いでしょう。
|
||||||
|
|
||||||
デフォルト引数は`|=`(or-assign operator)で指定します。`base`が指定されなかったら`math.E`を`base`に代入します。
|
デフォルト引数は`:=`(or-assign operator)で指定します。`base`が指定されなかったら`math.E`を`base`に代入します。
|
||||||
|
|
||||||
```erg
|
```erg
|
||||||
math_log x: Ratio, base |= math.E = ...
|
math_log x: Ratio, base := math.E = ...
|
||||||
|
|
||||||
assert math_log(100, 10) == 2
|
assert math_log(100, 10) == 2
|
||||||
assert math_log(100) == math_log(100, math.E)
|
assert math_log(100) == math_log(100, math.E)
|
||||||
|
@ -96,7 +96,7 @@ assert math_log(100) == math_log(100, math.E)
|
||||||
引数を指定しないことと`None`を代入することは区別されるので注意してください。
|
引数を指定しないことと`None`を代入することは区別されるので注意してください。
|
||||||
|
|
||||||
```erg
|
```erg
|
||||||
p! x |= 0 = print! x
|
p! x := 0 = print! x
|
||||||
p!(2) # 2
|
p!(2) # 2
|
||||||
p!() # 0
|
p!() # 0
|
||||||
p!(None) # None
|
p!(None) # None
|
||||||
|
@ -105,20 +105,20 @@ p!(None) # None
|
||||||
型指定、パターンと併用することもできます。
|
型指定、パターンと併用することもできます。
|
||||||
|
|
||||||
```erg
|
```erg
|
||||||
math_log x, base: Ratio |= math.E = ...
|
math_log x, base: Ratio := math.E = ...
|
||||||
f [x, y] |= [1, 2] = ...
|
f [x, y] := [1, 2] = ...
|
||||||
```
|
```
|
||||||
|
|
||||||
しかしデフォルト引数内では、後述するプロシージャを呼び出したり、可変オブジェクトを代入したりすることができません。
|
しかしデフォルト引数内では、後述するプロシージャを呼び出したり、可変オブジェクトを代入したりすることができません。
|
||||||
|
|
||||||
```erg
|
```erg
|
||||||
f x |= p! 1 = ... # NG
|
f x := p! 1 = ... # NG
|
||||||
```
|
```
|
||||||
|
|
||||||
また、定義したばかりの引数はデフォルト引数に渡す値として使えません。
|
また、定義したばかりの引数はデフォルト引数に渡す値として使えません。
|
||||||
|
|
||||||
```erg
|
```erg
|
||||||
f x |= 1, y |= x = ... # NG
|
f x := 1, y := x = ... # NG
|
||||||
```
|
```
|
||||||
|
|
||||||
## 可変長引数
|
## 可変長引数
|
||||||
|
|
|
@ -141,7 +141,7 @@ foo.public() # AttributeError: 'Foo' has no attribute 'public' ('public' is defi
|
||||||
{Foo; ...} = import "foo"
|
{Foo; ...} = import "foo"
|
||||||
|
|
||||||
FooImpl = Patch Foo
|
FooImpl = Patch Foo
|
||||||
FooImpl::
|
FooImpl :=:
|
||||||
private self = pass
|
private self = pass
|
||||||
FooImpl.
|
FooImpl.
|
||||||
public self = self::private()
|
public self = self::private()
|
||||||
|
|
|
@ -135,20 +135,20 @@ f {x: Int; y: Int} = ...
|
||||||
|
|
||||||
```erg
|
```erg
|
||||||
Point = Inherit {x = Int; y = Int}
|
Point = Inherit {x = Int; y = Int}
|
||||||
p = Point.{x = 1; y = 2}
|
p = Point::{x = 1; y = 2}
|
||||||
Point.{x; y} = p
|
Point::{x; y} = p
|
||||||
|
|
||||||
Nil T = Class Impl: Phantom T
|
Nil T = Class Impl := Phantom T
|
||||||
Cons T = Inherit {head = T; rest = List T}
|
Cons T = Inherit {head = T; rest = List T}
|
||||||
List T = Enum Nil(T), Cons(T)
|
List T = Enum Nil(T), Cons(T)
|
||||||
List T.
|
List T.
|
||||||
first self =
|
first self =
|
||||||
match self:
|
match self:
|
||||||
Cons.{head; ...} -> x
|
Cons::{head; ...} -> x
|
||||||
_ -> ...
|
_ -> ...
|
||||||
second self =
|
second self =
|
||||||
match self:
|
match self:
|
||||||
Cons.{rest=Cons.{head; ...}; ...} -> head
|
Cons::{rest=Cons::{head; ...}; ...} -> head
|
||||||
_ -> ...
|
_ -> ...
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,21 @@ X = ...
|
||||||
X = deco(X)
|
X = deco(X)
|
||||||
```
|
```
|
||||||
|
|
||||||
Ergでは変数の再代入が出来ないので、上のようなコードは通らず、デコレータが必要なのです。
|
Ergでは変数の再代入が出来ないので、上のようなコードは通りません。
|
||||||
|
単なる変数の場合は`X = deco(...)`と同じなのですが、インスタントブロックやサブルーチンの場合はそうすることができないので、デコレータが必要になってきます。
|
||||||
|
|
||||||
|
```erg
|
||||||
|
@deco
|
||||||
|
f x =
|
||||||
|
y = ...
|
||||||
|
x + y
|
||||||
|
|
||||||
|
# コードが横長になるのを防ぐこともできる
|
||||||
|
@LongNameDeco1
|
||||||
|
@LongNameDeco2
|
||||||
|
C = Class ...
|
||||||
|
```
|
||||||
|
|
||||||
以下に、頻出の組み込みデコレータを紹介します。
|
以下に、頻出の組み込みデコレータを紹介します。
|
||||||
|
|
||||||
## Inheritable
|
## Inheritable
|
||||||
|
@ -44,7 +58,7 @@ Sub = Trait {
|
||||||
.`_-_` = Self.(Self) -> Self
|
.`_-_` = Self.(Self) -> Self
|
||||||
}
|
}
|
||||||
|
|
||||||
C = Class({i = Int}, Impl: Add and Sub)
|
C = Class({i = Int}, Impl := Add and Sub)
|
||||||
C.
|
C.
|
||||||
@Impl Add
|
@Impl Add
|
||||||
`_+_` self, other = C.new {i = self::i + other::i}
|
`_+_` self, other = C.new {i = self::i + other::i}
|
||||||
|
@ -66,9 +80,9 @@ Add R = Trait {
|
||||||
@Attach AddForInt, AddForOdd
|
@Attach AddForInt, AddForOdd
|
||||||
ClosedAdd = Subsume Add(Self)
|
ClosedAdd = Subsume Add(Self)
|
||||||
|
|
||||||
AddForInt = Patch(Int, Impl: ClosedAdd)
|
AddForInt = Patch(Int, Impl := ClosedAdd)
|
||||||
AddForInt.AddO = Int
|
AddForInt.AddO = Int
|
||||||
AddForOdd = Patch(Odd, Impl: ClosedAdd)
|
AddForOdd = Patch(Odd, Impl := ClosedAdd)
|
||||||
AddForOdd.AddO = Even
|
AddForOdd.AddO = Even
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@ assert f(g(x, y)) == ((x, y) |> g |> f)
|
||||||
rand = -1.0..1.0 |>.sample!()
|
rand = -1.0..1.0 |>.sample!()
|
||||||
log rand # 0.2597...
|
log rand # 0.2597...
|
||||||
|
|
||||||
1+1*2 |>.times do log("a", end: "") # aaa
|
1+1*2 |>.times do log("a", end := "") # aaa
|
||||||
|
|
||||||
evens = 1..100 |>.iter |>.filter i -> i % 2 == 0 |>.collect Array
|
evens = 1..100 |>.iter |>.filter i -> i % 2 == 0 |>.collect Array
|
||||||
# パイプライン演算子を使わずに実装する場合、
|
# パイプライン演算子を使わずに実装する場合、
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
# The Grammar of Erg (ver 0.1.0, provisional)
|
# The Grammar of Erg (ver 0.1.0, provisional)
|
||||||
special_op ::= '=' | '->' | '=>' | '.' | ',' | ':' | '|>' | '&'
|
special_op ::= '=' | '->' | '=>' | '.' | ',' | ':' | '::' | '|>' | '&'
|
||||||
separator ::= ';' | '\n'
|
separator ::= ';' | '\n'
|
||||||
escape ::= '\'
|
escape ::= '\'
|
||||||
comment_marker ::= '#'
|
comment_marker ::= '#'
|
||||||
comment ::= '#' .* '\n'
|
|
||||||
reserved_symbol ::= special_op | separator | comment_marker
|
reserved_symbol ::= special_op | separator | comment_marker
|
||||||
number ::= [0-9]
|
number ::= [0-9]
|
||||||
first_last_dight ::= number
|
first_last_dight ::= number
|
||||||
|
@ -28,7 +27,8 @@ parenthesis ::= '(' | ')'
|
||||||
bracket ::= '{' | '}'
|
bracket ::= '{' | '}'
|
||||||
square_bracket ::= '[' | ']'
|
square_bracket ::= '[' | ']'
|
||||||
enclosure ::= parenthesis | bracket | square_bracket
|
enclosure ::= parenthesis | bracket | square_bracket
|
||||||
infix_op ::= '+' | '-' | '*' | '/' | '//' | '**' | '%' | '&&' | '||' | '^^' | '<' | '<=' | '>' | '>='
|
infix_op ::= '+' | '-' | '*' | '/' | '//' | '**'
|
||||||
|
| '%' | '&&' | '||' | '^^' | '<' | '<=' | '>' | '>='
|
||||||
| 'and' | 'or' | 'is' | 'as' | 'isnot' | 'in' | 'notin' | 'dot' | 'cross'
|
| 'and' | 'or' | 'is' | 'as' | 'isnot' | 'in' | 'notin' | 'dot' | 'cross'
|
||||||
prefix_op ::= '+' | '-' | '*' | '**' | '..' | '..<' | '~' | '&' | '!'
|
prefix_op ::= '+' | '-' | '*' | '**' | '..' | '..<' | '~' | '&' | '!'
|
||||||
postfix_op ::= '?' | '..' | '<..'
|
postfix_op ::= '?' | '..' | '<..'
|
||||||
|
@ -68,10 +68,21 @@ decorator ::= call
|
||||||
lambda_func ::= params_opt_t '->' body
|
lambda_func ::= params_opt_t '->' body
|
||||||
lambda_proc ::= params_opt_t '=>' body
|
lambda_proc ::= params_opt_t '=>' body
|
||||||
lambda ::= lambda_func | lambda_proc
|
lambda ::= lambda_func | lambda_proc
|
||||||
array ::= '[' enc_args ']'
|
normal_array ::= '[' enc_args ']'
|
||||||
array_comprehension ::= '[' expr | (generator)+ ']'
|
array_comprehension ::= '[' expr | (generator)+ ']'
|
||||||
anonymous_type ::= '{' enc_args '}'
|
array ::= normal_array | array_comprehension
|
||||||
|
record ::= '{' '=' '}'
|
||||||
|
| '{' def (';' def)* ';'? '}'
|
||||||
|
set ::= '{' '}'
|
||||||
|
| '{' expr (',' expr)* ','? '}'
|
||||||
|
dict ::= '{' ':' '}'
|
||||||
|
| '{' expr ':' expr (',' expr ':' expr)* ','? '}'
|
||||||
|
tuple ::= '(' ')'
|
||||||
|
| '(' expr (',' expr)* ','? ')'
|
||||||
indent ::= /* ... */
|
indent ::= /* ... */
|
||||||
expr ::= accessor | literal | prefix | infix | postfix | call | def | lambda
|
expr ::= accessor | literal
|
||||||
|
| prefix | infix | postfix
|
||||||
|
| array | record | set | dict | tuple
|
||||||
|
| call | def | lambda
|
||||||
line ::= expr separator+
|
line ::= expr separator+
|
||||||
program ::= expr? | (line | comment)*
|
program ::= expr? | (line | comment)*
|
||||||
|
|
|
@ -215,8 +215,8 @@ age = match person:
|
||||||
|
|
||||||
```erg
|
```erg
|
||||||
Point = Inherit {x = Int; y = Int}
|
Point = Inherit {x = Int; y = Int}
|
||||||
p = Point.{x = 1; y = 2}
|
p = Point::{x = 1; y = 2}
|
||||||
Point.{x; y} = p
|
Point::{x; y} = p
|
||||||
```
|
```
|
||||||
|
|
||||||
## 内包表記
|
## 内包表記
|
||||||
|
|
|
@ -85,7 +85,7 @@ assert add(C.new(1), C.new(2)) == C.new(3)
|
||||||
```
|
```
|
||||||
|
|
||||||
記名的トレイトは単に要求メソッドを実装しただけでは使えず、実装したことを明示的に宣言する必要があります。
|
記名的トレイトは単に要求メソッドを実装しただけでは使えず、実装したことを明示的に宣言する必要があります。
|
||||||
以下の例では明示的な実装の宣言がないため、`add`が`C`型の引数で使えません。`C = Class {i = Int}, Impl: Add`としなくてはならないのです。
|
以下の例では明示的な実装の宣言がないため、`add`が`C`型の引数で使えません。`C = Class {i = Int}, Impl := Add`としなくてはならないのです。
|
||||||
|
|
||||||
```erg
|
```erg
|
||||||
Add = Trait {
|
Add = Trait {
|
||||||
|
|
|
@ -125,7 +125,7 @@ Inherited!.
|
||||||
例えば`Real`(`Add()`を実装する)のサブタイプである`Int`では`Add()`を再実装しているようにみえます。
|
例えば`Real`(`Add()`を実装する)のサブタイプである`Int`では`Add()`を再実装しているようにみえます。
|
||||||
|
|
||||||
```erg
|
```erg
|
||||||
Int = Class ..., Impl: Add() and ...
|
Int = Class ..., Impl := Add() and ...
|
||||||
```
|
```
|
||||||
|
|
||||||
しかし実際は`Real`の`Add()`は`Add(Real, Real)`の略で、`Int`では`Add(Int, Int)`で上書きしているだけです。
|
しかし実際は`Real`の`Add()`は`Add(Real, Real)`の略で、`Int`では`Add(Int, Int)`で上書きしているだけです。
|
||||||
|
|
|
@ -110,7 +110,7 @@ Reverse = Trait {
|
||||||
.reverse = Self.() -> Self
|
.reverse = Self.() -> Self
|
||||||
}
|
}
|
||||||
|
|
||||||
StrReverse = Patch Str, Impl: Reverse
|
StrReverse = Patch Str, Impl := Reverse
|
||||||
StrReverse.
|
StrReverse.
|
||||||
reverse self =
|
reverse self =
|
||||||
self.iter().rev().collect(Str)
|
self.iter().rev().collect(Str)
|
||||||
|
@ -125,7 +125,7 @@ NumericStr = Inherit Str
|
||||||
NumericStr.
|
NumericStr.
|
||||||
...
|
...
|
||||||
|
|
||||||
NumStrRev = Patch NumericStr, Impl: Reverse
|
NumStrRev = Patch NumericStr, Impl := Reverse
|
||||||
NumStrRev.
|
NumStrRev.
|
||||||
...
|
...
|
||||||
# DuplicatePatchError: NumericStr is already associated with `Reverse`
|
# DuplicatePatchError: NumericStr is already associated with `Reverse`
|
||||||
|
@ -157,7 +157,7 @@ Reverse = Trait {
|
||||||
.reverse = Self.() -> Self
|
.reverse = Self.() -> Self
|
||||||
}
|
}
|
||||||
|
|
||||||
StrReverse = Patch(Str, Impl: Reverse)
|
StrReverse = Patch(Str, Impl := Reverse)
|
||||||
StrReverse.
|
StrReverse.
|
||||||
reverse self =
|
reverse self =
|
||||||
self.iter().rev().collect(Str)
|
self.iter().rev().collect(Str)
|
||||||
|
|
|
@ -5,4 +5,4 @@
|
||||||
|
|
||||||
## レコード型の合成
|
## レコード型の合成
|
||||||
|
|
||||||
合成されたレコード型は平坦化できます。例えば、`{...{.name = Str; .age = Nat}; ...{.name = Str; .id = Nat}}`は`{.name = Str; .age = Nat; .id = Nat}`となります。
|
合成されたレコード型は平坦化できます。例えば、`{..::{.name = Str; .age = Nat}; ..::{.name = Str; .id = Nat}}`は`{.name = Str; .age = Nat; .id = Nat}`となります。
|
||||||
|
|
|
@ -32,7 +32,7 @@ f x =
|
||||||
print! f::x, module::x
|
print! f::x, module::x
|
||||||
|
|
||||||
# Phantom型は型引数と同じ値になるPhantomという属性を持っている
|
# Phantom型は型引数と同じ値になるPhantomという属性を持っている
|
||||||
T X: Int = Class Impl: Phantom X
|
T X: Int = Class Impl := Phantom X
|
||||||
T(X).
|
T(X).
|
||||||
x self = self::Phantom
|
x self = self::Phantom
|
||||||
|
|
||||||
|
@ -44,7 +44,7 @@ T(1).x() # 1
|
||||||
|
|
||||||
```erg
|
```erg
|
||||||
# `Id`は不変型なので遷移させることはできないことに注意
|
# `Id`は不変型なので遷移させることはできないことに注意
|
||||||
VM!(State: {"stopped", "running"}! |= _, Id: Nat |= _) = Class(..., Impl: Phantom! State)
|
VM!(State: {"stopped", "running"}! := _, Id: Nat := _) = Class(..., Impl := Phantom! State)
|
||||||
VM!().
|
VM!().
|
||||||
# 変わらない変数は`_`を渡せば省略可能, デフォルト引数にしておけば書く必要すらない
|
# 変わらない変数は`_`を渡せば省略可能, デフォルト引数にしておけば書く必要すらない
|
||||||
start! ref! self("stopped" ~> "running") =
|
start! ref! self("stopped" ~> "running") =
|
||||||
|
|
|
@ -3,8 +3,8 @@
|
||||||
ErgはOr型をクラス化することで一般化代数的データ型(GADTs)を作成出来ます。
|
ErgはOr型をクラス化することで一般化代数的データ型(GADTs)を作成出来ます。
|
||||||
|
|
||||||
```erg
|
```erg
|
||||||
Nil T = Class(Impl: Phantom T)
|
Nil T = Class(Impl := Phantom T)
|
||||||
Cons T = Class {head = T; rest = List T}, Impl: Unpack
|
Cons T = Class {head = T; rest = List T}, Impl := Unpack
|
||||||
List T: Type = Class(Nil T or Cons T)
|
List T: Type = Class(Nil T or Cons T)
|
||||||
List.
|
List.
|
||||||
nil|T|() = Self(T).new Nil(T).new()
|
nil|T|() = Self(T).new Nil(T).new()
|
||||||
|
@ -30,8 +30,8 @@ _: List Int = cons 1, i
|
||||||
|
|
||||||
```erg
|
```erg
|
||||||
List: (Type, {"Empty", "Nonempty"}) -> Type
|
List: (Type, {"Empty", "Nonempty"}) -> Type
|
||||||
List T, "Empty" = Class(Impl: Phantom T)
|
List T, "Empty" = Class(Impl := Phantom T)
|
||||||
List T, "Nonempty" = Class {head = T; rest = List(T, _)}, Impl: Unpack
|
List T, "Nonempty" = Class {head = T; rest = List(T, _)}, Impl := Unpack
|
||||||
List.
|
List.
|
||||||
nil|T|() = Self(T, "Empty").new Nil(T).new()
|
nil|T|() = Self(T, "Empty").new Nil(T).new()
|
||||||
cons head, rest | T = Self(T, "Nonempty").new {head; rest}
|
cons head, rest | T = Self(T, "Nonempty").new {head; rest}
|
||||||
|
@ -48,8 +48,8 @@ Ergではさらに精密化して、長さを持つリストを定義できま
|
||||||
|
|
||||||
```erg
|
```erg
|
||||||
List: (Type, Nat) -> Type
|
List: (Type, Nat) -> Type
|
||||||
List T, 0 = Class(Impl: Phantom T)
|
List T, 0 = Class(Impl := Phantom T)
|
||||||
List T, N = Class {head = T; rest = List(T, N-1)}, Impl: Unpack
|
List T, N = Class {head = T; rest = List(T, N-1)}, Impl := Unpack
|
||||||
List.
|
List.
|
||||||
nil|T|() = Self(T, 0).new Nil(T).new()
|
nil|T|() = Self(T, 0).new Nil(T).new()
|
||||||
cons head, rest | T, N = Self(T, N).new {head; rest}
|
cons head, rest | T, N = Self(T, N).new {head; rest}
|
||||||
|
|
|
@ -3,25 +3,25 @@
|
||||||
まず、デフォルト引数の使用例を見る。
|
まず、デフォルト引数の使用例を見る。
|
||||||
|
|
||||||
```erg
|
```erg
|
||||||
f: (Int, Int, z |= Int) -> Int
|
f: (Int, Int, z := Int) -> Int
|
||||||
f(x, y, z |= 0) = x + y + z
|
f(x, y, z := 0) = x + y + z
|
||||||
|
|
||||||
g: (Int, Int, z |= Int, w |= Int) -> Int
|
g: (Int, Int, z := Int, w := Int) -> Int
|
||||||
g(x, y, z |= 0, w |= 1) = x + y + z + w
|
g(x, y, z := 0, w := 1) = x + y + z + w
|
||||||
|
|
||||||
fold: ((Int, Int) -> Int, [Int], acc |= Int) -> Int
|
fold: ((Int, Int) -> Int, [Int], acc := Int) -> Int
|
||||||
fold(f, [], acc) = acc
|
fold(f, [], acc) = acc
|
||||||
fold(f, arr, acc |= 0) = fold(f, arr[1..], f(acc, arr[0]))
|
fold(f, arr, acc := 0) = fold(f, arr[1..], f(acc, arr[0]))
|
||||||
assert fold(f, [1, 2, 3]) == 6
|
assert fold(f, [1, 2, 3]) == 6
|
||||||
assert fold(g, [1, 2, 3]) == 8
|
assert fold(g, [1, 2, 3]) == 8
|
||||||
```
|
```
|
||||||
|
|
||||||
`|=`以降の引数はデフォルト引数である。
|
`:=`以降の引数はデフォルト引数である。
|
||||||
部分型付け規則は以下の通り。
|
部分型付け規則は以下の通り。
|
||||||
|
|
||||||
```erg
|
```erg
|
||||||
((X, y |= Y) -> Z) <: (X -> Z)
|
((X, y := Y) -> Z) <: (X -> Z)
|
||||||
((X, y |= Y, ...) -> Z) <: ((X, ...) -> Z)
|
((X, y := Y, ...) -> Z) <: ((X, ...) -> Z)
|
||||||
```
|
```
|
||||||
|
|
||||||
1番目は、デフォルト引数のある関数は、ない関数と同一視できる、という意味である。
|
1番目は、デフォルト引数のある関数は、ない関数と同一視できる、という意味である。
|
||||||
|
|
|
@ -17,7 +17,7 @@ Person = Class {.name = Str; .age = Nat} and Light
|
||||||
```erg
|
```erg
|
||||||
M = Subsume Marker
|
M = Subsume Marker
|
||||||
|
|
||||||
MarkedInt = Inherit Int, Impl: M
|
MarkedInt = Inherit Int, Impl := M
|
||||||
|
|
||||||
i = MarkedInt.new(2)
|
i = MarkedInt.new(2)
|
||||||
assert i + 1 == 2
|
assert i + 1 == 2
|
||||||
|
@ -27,5 +27,5 @@ assert i in M
|
||||||
マーカークラスは`Excluding`引数で外すことも可能である。
|
マーカークラスは`Excluding`引数で外すことも可能である。
|
||||||
|
|
||||||
```erg
|
```erg
|
||||||
NInt = Inherit MarkedInt, Impl: N, Excluding: M
|
NInt = Inherit MarkedInt, Impl := N, Excluding: M
|
||||||
```
|
```
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
`T!`型は任意の`T`型オブジェクトを入れられて差し替え可能なボックス型であると説明した。
|
`T!`型は任意の`T`型オブジェクトを入れられて差し替え可能なボックス型であると説明した。
|
||||||
|
|
||||||
```erg
|
```erg
|
||||||
Particle! State: {"base", "excited"}! = Class(..., Impl: Phantom State)
|
Particle! State: {"base", "excited"}! = Class(..., Impl := Phantom State)
|
||||||
Particle!.
|
Particle!.
|
||||||
# このメソッドはStateを"base"から"excited"に遷移させる
|
# このメソッドはStateを"base"から"excited"に遷移させる
|
||||||
apply_electric_field!(ref! self("base" ~> "excited"), field: Vector) = ...
|
apply_electric_field!(ref! self("base" ~> "excited"), field: Vector) = ...
|
||||||
|
@ -31,7 +31,7 @@ v: [Str; !1]
|
||||||
可変構造型はもちろんユーザー定義も可能である。ただし、不変構造型とは構成法に関していくつか違いがあるので注意が必要である。
|
可変構造型はもちろんユーザー定義も可能である。ただし、不変構造型とは構成法に関していくつか違いがあるので注意が必要である。
|
||||||
|
|
||||||
```erg
|
```erg
|
||||||
Nil T = Class(Impl: Phantom T)
|
Nil T = Class(Impl := Phantom T)
|
||||||
List T, !0 = Inherit Nil T
|
List T, !0 = Inherit Nil T
|
||||||
List T, N: Nat! = Class {head = T; rest = List(T, !N-1)}
|
List T, N: Nat! = Class {head = T; rest = List(T, !N-1)}
|
||||||
List(T, !N).
|
List(T, !N).
|
||||||
|
|
|
@ -7,10 +7,10 @@ Ergでは __アドホック多相__ をサポートしない。すなわち、
|
||||||
Add1 = Trait {
|
Add1 = Trait {
|
||||||
.add1: Self.() -> Self
|
.add1: Self.() -> Self
|
||||||
}
|
}
|
||||||
IntAdd1 = Patch Int, Impl: Add1
|
IntAdd1 = Patch Int, Impl := Add1
|
||||||
IntAdd1.
|
IntAdd1.
|
||||||
add1 self = self + 1
|
add1 self = self + 1
|
||||||
RatioAdd1 = Patch Ratio, Impl: Add1
|
RatioAdd1 = Patch Ratio, Impl := Add1
|
||||||
RatioAdd1.
|
RatioAdd1.
|
||||||
add1 self = self + 1.0
|
add1 self = self + 1.0
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@ assert add1(1.0) == 2.0
|
||||||
```erg
|
```erg
|
||||||
C = Class {.x = Int; .y = Int}
|
C = Class {.x = Int; .y = Int}
|
||||||
C.
|
C.
|
||||||
new(x, y |= 0) = Self::__new__ {.x; .y}
|
new(x, y := 0) = Self::__new__ {.x; .y}
|
||||||
|
|
||||||
assert C.new(0, 0) == C.new(0)
|
assert C.new(0, 0) == C.new(0)
|
||||||
```
|
```
|
||||||
|
@ -62,7 +62,7 @@ id "str" # TypeError: id is not implemented for Str
|
||||||
|
|
||||||
```erg
|
```erg
|
||||||
f x: Int = ...
|
f x: Int = ...
|
||||||
f(x: Int, y |= 0) = ...
|
f(x: Int, y := 0) = ...
|
||||||
|
|
||||||
f(1) # which is chosen?
|
f(1) # which is chosen?
|
||||||
```
|
```
|
||||||
|
|
|
@ -32,7 +32,7 @@ List T, N: Nat = Class {head = T; rest = List(T, N-1)}
|
||||||
このようなときにちょうどよいのが幽霊型である。幽霊型はサイズ0の型を一般化した型である。
|
このようなときにちょうどよいのが幽霊型である。幽霊型はサイズ0の型を一般化した型である。
|
||||||
|
|
||||||
```erg
|
```erg
|
||||||
Nil T = Class(Impl: Phantom T)
|
Nil T = Class(Impl := Phantom T)
|
||||||
List T, 0 = Inherit Nil T
|
List T, 0 = Inherit Nil T
|
||||||
List T, N: Nat = Class {head = T; rest = List(T, N-1)}
|
List T, N: Nat = Class {head = T; rest = List(T, N-1)}
|
||||||
|
|
||||||
|
@ -46,7 +46,7 @@ assert nil.__size__ == 0
|
||||||
この場合も、`state`はオブジェクトの実体に現れないハリボテの型変数である。
|
この場合も、`state`はオブジェクトの実体に現れないハリボテの型変数である。
|
||||||
|
|
||||||
```erg
|
```erg
|
||||||
VM! State: {"stopped", "running"}! = Class(..., Impl: Phantom! State)
|
VM! State: {"stopped", "running"}! = Class(..., Impl := Phantom! State)
|
||||||
VM!("stopped").
|
VM!("stopped").
|
||||||
start ref! self("stopped" ~> "running") =
|
start ref! self("stopped" ~> "running") =
|
||||||
self.do_something!()
|
self.do_something!()
|
||||||
|
|
|
@ -8,7 +8,7 @@ Add R = Trait {
|
||||||
.AddO = Type
|
.AddO = Type
|
||||||
}
|
}
|
||||||
|
|
||||||
AddForInt = Patch(Int, Impl: Add Int)
|
AddForInt = Patch(Int, Impl := Add Int)
|
||||||
AddForInt.
|
AddForInt.
|
||||||
AddO = Int
|
AddO = Int
|
||||||
```
|
```
|
||||||
|
|
|
@ -40,7 +40,7 @@ Add R = Trait {
|
||||||
}
|
}
|
||||||
ClosedAdd = Subsume Add(Self)
|
ClosedAdd = Subsume Add(Self)
|
||||||
|
|
||||||
ClosedAddForInt = Patch(Int, Impl: ClosedAdd)
|
ClosedAddForInt = Patch(Int, Impl := ClosedAdd)
|
||||||
ClosedAddForInt.
|
ClosedAddForInt.
|
||||||
AddO = Int
|
AddO = Int
|
||||||
|
|
||||||
|
|
|
@ -133,11 +133,11 @@ K T = Class(...)
|
||||||
assert not K(Str) <= K(Object)
|
assert not K(Str) <= K(Object)
|
||||||
assert not K(Str) >= K(Object)
|
assert not K(Str) >= K(Object)
|
||||||
|
|
||||||
InputStream T = Class ..., Impl: Inputs(T)
|
InputStream T = Class ..., Impl := Inputs(T)
|
||||||
# Objectを受け入れるストリームは、Strを受け入れるともみなせる
|
# Objectを受け入れるストリームは、Strを受け入れるともみなせる
|
||||||
assert InputStream(Str) > InputStream(Object)
|
assert InputStream(Str) > InputStream(Object)
|
||||||
|
|
||||||
OutputStream T = Class ..., Impl: Outputs(T)
|
OutputStream T = Class ..., Impl := Outputs(T)
|
||||||
# Strを出力するストリームは、Objectを出力するともみなせる
|
# Strを出力するストリームは、Objectを出力するともみなせる
|
||||||
assert OutputStream(Str) < OutputStream(Object)
|
assert OutputStream(Str) < OutputStream(Object)
|
||||||
```
|
```
|
||||||
|
|
|
@ -44,15 +44,15 @@ FinalWrapper.
|
||||||
また、`Enum`を使うと、その選択肢となる型がリダイレクト属性として自動的に定義されます。
|
また、`Enum`を使うと、その選択肢となる型がリダイレクト属性として自動的に定義されます。
|
||||||
|
|
||||||
```erg
|
```erg
|
||||||
Ok = Class Impl: Singleton
|
Ok = Class Impl := Singleton
|
||||||
Err = Class Impl: Singleton
|
Err = Class Impl := Singleton
|
||||||
ErrWithInfo = Inherit {info = Str}
|
ErrWithInfo = Inherit {info = Str}
|
||||||
Status = Enum Ok, Err, ErrWithInfo
|
Status = Enum Ok, Err, ErrWithInfo
|
||||||
stat: Status = Status.cons(ErrWithInfo) {info = "error caused by ..."}
|
stat: Status = Status.cons(ErrWithInfo) {info = "error caused by ..."}
|
||||||
match! stat:
|
match! stat:
|
||||||
Status.Ok -> ...
|
Status.Ok -> ...
|
||||||
Status.Err -> ...
|
Status.Err -> ...
|
||||||
Status.ErrWithInfo.{info;} -> ...
|
Status.ErrWithInfo::{info;} -> ...
|
||||||
```
|
```
|
||||||
|
|
||||||
```erg
|
```erg
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
Point = Class {x = Int; y = Int}, Impl: Add() and Eq()
|
Point = Class {x = Int; y = Int}, Impl := Add() and Eq()
|
||||||
Point.
|
Point.
|
||||||
new x, y = Self::__new__ {x; y}
|
new x, y = Self::__new__ {x; y}
|
||||||
norm &self = self::x**2 + self::y**2
|
norm &self = self::x**2 + self::y**2
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
@Inheritable
|
@Inheritable
|
||||||
Point2D = Class {x = Int; y = Int}
|
Point2D = Class {x = Int; y = Int}
|
||||||
Point2D.
|
Point2D.
|
||||||
new x, y = Self::__new__ {x; y}
|
new x, y = Self::__new__ {x = x; y = y}
|
||||||
norm ref self = self::x**2 + self::y**2
|
norm ref self = self::x**2 + self::y**2
|
||||||
|
|
||||||
Point3D = Inherit Point2D, Additional: {z = Int}
|
Point3D = Inherit Point2D, Additional := {z = Int}
|
||||||
Point3D.
|
Point3D.
|
||||||
@Override
|
@Override
|
||||||
new x, y, z = Self::__new__ {x; y; z}
|
new x, y, z = Self::__new__ {x = x; y = y; z = z}
|
||||||
@Override
|
@Override
|
||||||
norm ref self = self::x**2 + self::y**2 + self::z**2
|
norm ref self = self::x**2 + self::y**2 + self::z**2
|
||||||
|
|
||||||
UnpackPoint2D = Class {x = Int; y = Int}, Impl: Unpack
|
UnpackPoint2D = Class {x = Int; y = Int}, Impl := Unpack
|
||||||
|
|
||||||
p = UnpackPoint2D.{x = 1; y = 2}
|
p = UnpackPoint2D::{x = 1; y = 2}
|
||||||
UnpackPoint2D.{x; y} = p
|
UnpackPoint2D::{x = x; y = x} = p
|
||||||
|
|
|
@ -1,20 +1,20 @@
|
||||||
LitExpr = Class {.i = Int}, Impl: Show
|
LitExpr = Class {.i = Int}, Impl := Show
|
||||||
LitExpr.
|
LitExpr.
|
||||||
new i = Self::__new__ {.i;}
|
new i = Self::__new__ {.i;}
|
||||||
show &self = "{self.i}"
|
show &self = "{self.i}"
|
||||||
AddExpr = Class {.lhs = Expr, .rhs = Expr}, Impl: Show
|
AddExpr = Class {.lhs = Expr, .rhs = Expr}, Impl := Show
|
||||||
AddExpr.
|
AddExpr.
|
||||||
new lhs, rhs = Self::__new__ {.lhs; .rhs}
|
new lhs, rhs = Self::__new__ {.lhs; .rhs}
|
||||||
show &self = "{self.lhs} + {self.rhs}"
|
show &self = "{self.lhs} + {self.rhs}"
|
||||||
SubExpr = Class {.lhs = Expr, .rhs = Expr}, Impl: Show
|
SubExpr = Class {.lhs = Expr, .rhs = Expr}, Impl := Show
|
||||||
SubExpr.
|
SubExpr.
|
||||||
new lhs, rhs = Self::__new__ {.lhs; .rhs}
|
new lhs, rhs = Self::__new__ {.lhs; .rhs}
|
||||||
show &self = "{self.lhs} - {self.rhs}"
|
show &self = "{self.lhs} - {self.rhs}"
|
||||||
PosExpr = Class {.expr = Expr}, Impl: Show
|
PosExpr = Class {.expr = Expr}, Impl := Show
|
||||||
PosExpr.
|
PosExpr.
|
||||||
new expr = Self::__new__ {.expr;}
|
new expr = Self::__new__ {.expr;}
|
||||||
show &self = "+{self.expr}"
|
show &self = "+{self.expr}"
|
||||||
NegExpr = Class {.expr = Expr}, Impl: Show
|
NegExpr = Class {.expr = Expr}, Impl := Show
|
||||||
NegExpr.
|
NegExpr.
|
||||||
new expr = Self::__new__ {.expr;}
|
new expr = Self::__new__ {.expr;}
|
||||||
show &self = "-{self.expr}"
|
show &self = "-{self.expr}"
|
||||||
|
|
|
@ -1,18 +1,18 @@
|
||||||
Nil T = Class Impl: Phantom(T) and Eq
|
Nil T = Class Impl := Phantom(T) and Eq
|
||||||
Cons T, N = Inherit {head = T; rest = List(T, N-1)}
|
Cons T, N = Inherit {head = T; rest = List(T, N-1)}
|
||||||
List: (Type, Nat) -> Type
|
List: (Type, Nat) -> Type
|
||||||
List T, 0 = Class Nil T
|
List T, 0 = Class Nil T
|
||||||
List T, N = Class Cons(T, N), Impl: Eq
|
List T, N = Class Cons(T, N), Impl := Eq
|
||||||
List.
|
List.
|
||||||
nil T = List(T, 0).new Nil(T).new()
|
nil T = List(T, 0).new Nil(T).new()
|
||||||
cons|T, N| rest: List(T, N-1), head: T = List(T, N).new Cons(T, N).{head; rest}
|
cons|T, N| rest: List(T, N-1), head: T = List(T, N).new Cons(T, N)::{head; rest}
|
||||||
{nil, cons} = List
|
{nil, cons} = List
|
||||||
|
|
||||||
a = cons(nil(Int), 1) |> cons 2 |> cons 3
|
a = cons(nil(Int), 1) |> cons 2 |> cons 3
|
||||||
match a:
|
match a:
|
||||||
Cons(_, _).{head=h1; rest=Cons(_, _).{head=h2; rest}} ->
|
Cons(_, _)::{head=h1; rest=Cons(_, _)::{head=h2; rest}} ->
|
||||||
assert h1 == 3
|
assert h1 == 3
|
||||||
assert h2 == 2
|
assert h2 == 2
|
||||||
assert rest == Cons.{head = 1; rest = nil(Int)}
|
assert rest == Cons::{head = 1; rest = nil(Int)}
|
||||||
_ ->
|
_ ->
|
||||||
pass
|
pass
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
p = (1, 2)
|
p = (1, 2)
|
||||||
assert p.0 == 1
|
assert p.0 == 1
|
||||||
|
|
||||||
q = (1, 1.0)
|
q = (1, True)
|
||||||
assert q.1 == 1.0
|
assert q.1
|
||||||
|
|
||||||
i, j = 0, 1
|
i, j = 0, 1
|
||||||
assert i == 0
|
assert i == 0
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue