Merge pull request #114 from erg-lang/class

Renovate Parser
This commit is contained in:
Shunsuke Shibayama 2022-09-02 11:54:13 +09:00 committed by GitHub
commit 04d754b329
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
75 changed files with 1402 additions and 1357 deletions

View file

@ -42,10 +42,10 @@
l2[10] # IndexError: `l2` has 7 elements but was accessed the 11th element
2.times! do!:
print! "hello, ", end: ""
print! "hello, ", end := ""
# => hello, hello,
-2.times! do!:
print! "hello, ", end: ""
print! "hello, ", end := ""
# TypeError: `.times!` is a method of `Nat` (0 or more Int), not `Int`
{Meter; Sec; meter; yard; sec; ...} = import "unit"

View file

@ -46,10 +46,10 @@
l2[10] # IndexError: `l2`は7つの要素を持っていますが、11番目の要素のアクセスしようとしています
2.times! do!:
print! "hello, ", end: ""
print! "hello, ", end := ""
# => hello, hello,
-2.times! do!:
print! "hello,", end: ""
print! "hello,", end := ""
# TypeError: `.times!``Nat`(0以上のInt)のメソッドです、`Int`ではありません
{Meter; Sec; meter; yard; sec; ...} = import "unit"

View file

@ -45,10 +45,10 @@
l2[10] # 下标错误:`l2`只有7个元素但却被访问了第11个元素
2.times! do!:
print! "hello, ", end: ""
print! "hello, ", end := ""
# => hello, hello,
-2.times! do!:
print! "hello, ", end: ""
print! "hello, ", end := ""
# 类型错误:`.times!``Nat`(0或更大整数)的方法,不是`Int`
{Meter; Sec; meter; yard; sec; ...} = import "unit"

View file

@ -45,10 +45,10 @@
l2[10] # 下標錯誤:`l2`只有7個元素但卻被訪問了第11個元素
2.times! do!:
print! "hello, ", end: ""
print! "hello, ", end := ""
# => hello, hello,
-2.times! do!:
print! "hello, ", end: ""
print! "hello, ", end := ""
# 類型錯誤:`.times!``Nat`(0或更大整數)的方法,不是`Int`
{Meter; Sec; meter; yard; sec; ...} = import "unit"

View file

@ -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]
fn payload(self) -> Vec<$Inner> {
self.0
@ -232,7 +232,7 @@ macro_rules! impl_stream_for_wrapper {
#[macro_export]
macro_rules! impl_stream {
($Strc: ident, $Inner: ident, $field: ident) => {
impl erg_common::traits::Stream<$Inner> for $Strc {
impl $crate::traits::Stream<$Inner> for $Strc {
#[inline]
fn payload(self) -> Vec<$Inner> {
self.$field

View file

@ -701,6 +701,9 @@ impl CodeGenerator {
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) {
if body.is_type() {
return self.emit_mono_type_def(sig, body);

View 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,
}
}
}

View file

@ -51,6 +51,7 @@ impl Context {
ident.inspect(),
&spec_t,
body_t,
self.get_type_mismatch_hint(&spec_t, body_t),
));
}
Ok(())
@ -120,6 +121,7 @@ impl Context {
"match",
&class("LambdaFunc"),
t,
self.get_type_mismatch_hint(&class("LambdaFunc"), t),
));
}
}
@ -616,6 +618,7 @@ impl Context {
&name[..],
param_t,
arg_t,
self.get_type_mismatch_hint(param_t, arg_t),
)
})?;
if let Some(name) = param.name() {
@ -656,6 +659,7 @@ impl Context {
&name[..],
param_t,
arg_t,
self.get_type_mismatch_hint(param_t, arg_t),
)
})
}
@ -698,6 +702,7 @@ impl Context {
&name[..],
pt.typ(),
arg_t,
self.get_type_mismatch_hint(pt.typ(), arg_t),
)
})?;
} else {

View file

@ -2,6 +2,7 @@
//! `Context` is used for type inference and type checking.
pub mod cache;
pub mod compare;
pub mod hint;
pub mod initialize;
pub mod inquire;
pub mod instantiate;

View file

@ -393,6 +393,7 @@ impl Context {
"import::name",
&Str,
mod_name.ref_t(),
self.get_type_mismatch_hint(&Str, mod_name.ref_t()),
));
}
}

View file

@ -1017,6 +1017,7 @@ impl Context {
param_name.unwrap_or(&Str::ever("_")),
maybe_sup,
maybe_sub,
self.get_type_mismatch_hint(maybe_sup, maybe_sub),
));
}
match (maybe_sub, maybe_sup) {

View file

@ -513,6 +513,7 @@ impl TyCheckError {
name: &str,
expect: &Type,
found: &Type,
hint: Option<Str>,
) -> Self {
Self::new(
ErrorCore::new(
@ -525,7 +526,7 @@ impl TyCheckError {
"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}"),
),
None,
hint,
),
caused_by,
)

View file

@ -264,7 +264,7 @@ impl Evaluator {
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![];
for attr in record.attrs.iter() {
if let Some(elem) = self.eval_const_block(&attr.body.block, ctx) {

View file

@ -97,7 +97,7 @@ pub struct KwArg {
impl NestedDisplay for KwArg {
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)
}
}

View file

@ -55,6 +55,7 @@ impl ASTLowerer {
name,
expect,
found,
self.ctx.get_type_mismatch_hint(expect, found),
)
})
}
@ -216,7 +217,7 @@ impl ASTLowerer {
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!());
let mut hir_record =
hir::Record::new(record.l_brace, record.r_brace, hir::RecordAttrs::new());
@ -336,8 +337,6 @@ impl ASTLowerer {
&hir_args.kw_args,
&self.ctx.name,
)?;
log!(err "{}", obj);
log!(err "{:?}", call.method_name);
Ok(hir::Call::new(obj, call.method_name, hir_args, t))
}

View file

@ -95,12 +95,18 @@ impl PosArg {
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct KwArg {
pub keyword: Token,
pub t_spec: Option<TypeSpec>,
pub expr: Expr,
}
impl NestedDisplay for KwArg {
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)
}
}
@ -109,8 +115,12 @@ impl_display_from_nested!(KwArg);
impl_locational!(KwArg, keyword, expr);
impl KwArg {
pub const fn new(keyword: Token, expr: Expr) -> Self {
Self { keyword, expr }
pub const fn new(keyword: Token, t_spec: Option<TypeSpec>, expr: Expr) -> Self {
Self {
keyword,
t_spec,
expr,
}
}
}
@ -169,6 +179,10 @@ impl Args {
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 {
self.kw_args.is_empty()
}
@ -296,12 +310,13 @@ impl Public {
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct Attribute {
pub obj: Box<Expr>,
pub vis: Token,
pub name: Local,
}
impl NestedDisplay for Attribute {
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 Attribute {
pub fn new(obj: Expr, name: Local) -> Self {
pub fn new(obj: Expr, vis: Token, name: Local) -> Self {
Self {
obj: Box::new(obj),
vis,
name,
}
}
@ -388,8 +404,8 @@ impl Accessor {
Self::Public(Public::new(dot, symbol))
}
pub fn attr(obj: Expr, name: Local) -> Self {
Self::Attr(Attribute::new(obj, name))
pub fn attr(obj: Expr, vis: Token, name: Local) -> Self {
Self::Attr(Attribute::new(obj, vis, name))
}
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 {
fn from(attrs: Vec<Def>) -> Self {
Self(attrs)
@ -663,13 +685,13 @@ impl RecordAttrs {
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct Record {
pub struct NormalRecord {
pub l_brace: Token,
pub r_brace: Token,
pub attrs: RecordAttrs,
}
impl NestedDisplay for Record {
impl NestedDisplay for NormalRecord {
fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, level: usize) -> fmt::Result {
writeln!(f, "{{")?;
self.attrs.fmt_nest(f, level + 1)?;
@ -677,10 +699,10 @@ impl NestedDisplay for Record {
}
}
impl_display_from_nested!(Record);
impl_locational!(Record, l_brace, r_brace);
impl_display_from_nested!(NormalRecord);
impl_locational!(NormalRecord, l_brace, r_brace);
impl Record {
impl NormalRecord {
pub fn new(l_brace: Token, r_brace: Token, attrs: RecordAttrs) -> Self {
Self {
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)]
pub struct NormalSet {
l_brace: Token,
@ -1168,7 +1198,7 @@ pub struct ConstKwArg {
impl NestedDisplay for ConstKwArg {
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)]
pub struct SubrTySpec {
pub struct SubrTypeSpec {
pub kind: SubrKindSpec,
pub lparen: Option<Token>,
pub non_defaults: Vec<ParamTySpec>,
@ -1412,11 +1442,11 @@ pub struct SubrTySpec {
pub return_t: Box<TypeSpec>,
}
impl fmt::Display for SubrTySpec {
impl fmt::Display for SubrTypeSpec {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"({}, {}, |= {}) {} {}",
"({}, {}, := {}) {} {}",
fmt_vec(&self.non_defaults),
fmt_option!(pre "...", &self.var_args),
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 {
if let Some(lparen) = &self.lparen {
Location::concat(lparen, self.return_t.as_ref())
@ -1437,7 +1467,7 @@ impl Locational for SubrTySpec {
}
}
impl SubrTySpec {
impl SubrTypeSpec {
pub fn new(
kind: SubrKindSpec,
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.
/// * Dict: `[Str: Str]`, etc.
/// * Option: `Int?`, etc.
/// * And (Intersection type): Add and Sub and Mul (== Num), etc.
/// * Not (Diff type): Pos == Nat not {0}, etc.
/// * Or (Union type): Int or None (== Option Int), etc.
/// * Enum: `{0, 1}` (== Binary), etc.
/// * Range: 1..12, 0.0<..1.0, etc.
/// * Record: {.into_s: Self.() -> Str }, etc.
/// * Func: Int -> Int, etc.
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
/// * Subr: Int -> Int, Int => None, T.(X) -> Int, etc.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum TypeSpec {
PreDeclTy(PreDeclTypeSpec),
/* Composite types */
Array {
t: PreDeclTypeSpec,
len: ConstExpr,
},
Array(ArrayTypeSpec),
Tuple(Vec<TypeSpec>),
// Dict(),
// Option(),
@ -1488,7 +1528,7 @@ pub enum TypeSpec {
rhs: ConstExpr,
},
// Record(),
Subr(SubrTySpec),
Subr(SubrTypeSpec),
}
impl fmt::Display for TypeSpec {
@ -1498,7 +1538,7 @@ impl fmt::Display for TypeSpec {
Self::And(lhs, rhs) => write!(f, "{lhs} and {rhs}"),
Self::Not(lhs, rhs) => write!(f, "{lhs} not {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::Enum(elems) => write!(f, "{{{elems}}}"),
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) => {
Location::concat(lhs.as_ref(), rhs.as_ref())
}
Self::Array { t, len } => Location::concat(t, len),
Self::Array(arr) => arr.loc(),
// TODO: ユニット
Self::Tuple(tys) => Location::concat(tys.first().unwrap(), tys.last().unwrap()),
Self::Enum(set) => set.loc(),
@ -1548,7 +1588,7 @@ impl TypeSpec {
defaults: Vec<ParamTySpec>,
return_t: TypeSpec,
) -> Self {
Self::Subr(SubrTySpec::new(
Self::Subr(SubrTypeSpec::new(
SubrKindSpec::Func,
lparen,
non_defaults,
@ -1565,7 +1605,7 @@ impl TypeSpec {
defaults: Vec<ParamTySpec>,
return_t: TypeSpec,
) -> Self {
Self::Subr(SubrTySpec::new(
Self::Subr(SubrTypeSpec::new(
SubrKindSpec::Proc,
lparen,
non_defaults,
@ -1623,6 +1663,14 @@ impl Decorator {
pub const fn new(expr: Expr) -> Self {
Self(expr)
}
pub fn expr(&self) -> &Expr {
&self.0
}
pub fn into_expr(self) -> Expr {
self.0
}
}
/// 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)]
pub struct ParamRecordPattern {
l_brace: Token,
@ -2100,11 +2162,15 @@ pub enum ParamPattern {
VarArgsName(VarName),
Lit(Literal),
Array(ParamArrayPattern),
Tuple(ParamTuplePattern),
Record(ParamRecordPattern),
Ref(VarName),
RefMut(VarName),
VarArgs(VarName),
}
impl_display_for_enum!(ParamPattern; Discard, VarName, VarArgsName, Lit, Array, Record);
impl_locational_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, Tuple, Record, Ref, RefMut, VarArgs);
impl ParamPattern {
pub const fn inspect(&self) -> Option<&Str> {
@ -2148,7 +2214,7 @@ impl NestedDisplay for ParamSignature {
if let Some(default_val) = &self.opt_default_val {
write!(
f,
"{}{} |= {}",
"{}{} := {}",
self.pat,
fmt_option!(pre ": ", self.t_spec),
default_val
@ -2163,7 +2229,9 @@ impl_display_from_nested!(ParamSignature);
impl Locational for ParamSignature {
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)
} else {
self.pat.loc()
@ -2220,6 +2288,8 @@ impl Locational for Params {
Location::concat(l, r)
} else if !self.non_defaults.is_empty() {
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() {
Location::concat(&self.defaults[0], self.defaults.last().unwrap())
} else {
@ -2340,9 +2410,9 @@ impl SubrSignature {
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct LambdaSignature {
pub bounds: TypeBoundSpecs,
pub params: Params,
pub return_t_spec: Option<TypeSpec>,
pub bounds: TypeBoundSpecs,
}
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)]
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(式)
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum Expr {
@ -2548,18 +2671,19 @@ pub enum Expr {
Tuple(Tuple),
Dict(Dict),
Set(Set),
Record(Record),
Record(NormalRecord),
BinOp(BinOp),
UnaryOp(UnaryOp),
Call(Call),
Lambda(Lambda),
Decl(Decl),
TypeAsc(TypeAscription),
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_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 {
pub fn is_match_call(&self) -> bool {

View file

@ -244,7 +244,12 @@ impl Desugarer {
Accessor::subscr(obj, Expr::Lit(Literal::nat(n, sig.ln_begin().unwrap())))
}
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)));

View file

@ -664,7 +664,11 @@ impl Iterator for Lexer /*<'a>*/ {
_ => 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, "."),
},
Some(',') => self.accept(Comma, ","),
@ -673,6 +677,10 @@ impl Iterator for Lexer /*<'a>*/ {
self.consume();
self.accept(DblColon, "::")
}
Some('=') => {
self.consume();
self.accept(Walrus, ":=")
}
Some('>') => {
self.consume();
self.accept(SupertypeOf, ":>")
@ -694,10 +702,6 @@ impl Iterator for Lexer /*<'a>*/ {
self.consume();
self.accept(BitOr, "||")
}
Some('=') => {
self.consume();
self.accept(OrEqual, "|=")
}
_ => self.accept(VBar, "|"),
},
Some('^') => {

File diff suppressed because it is too large Load diff

View file

@ -105,8 +105,8 @@ pub enum TokenKind {
CrossOp,
/// =
Equal,
/// |=
OrEqual,
/// :=
Walrus,
/// ->
FuncArrow,
/// =>
@ -175,7 +175,7 @@ pub enum TokenCategory {
LEnclosure,
/// ) } } Dedent
REnclosure,
/// , : :: :> <: . |> |=
/// , : :: :> <: . |> :=
SpecialBinOp,
/// =
DefOp,
@ -212,7 +212,7 @@ impl TokenKind {
| InfLit => TokenCategory::Literal,
PrePlus | PreMinus | PreBitNot | Mutate => TokenCategory::UnaryOp,
Try => TokenCategory::PostfixOp,
Comma | Colon | DblColon | SupertypeOf | SubtypeOf | Dot | Pipe | OrEqual => {
Comma | Colon | DblColon | SupertypeOf | SubtypeOf | Dot | Pipe | Walrus => {
TokenCategory::SpecialBinOp
}
Equal => TokenCategory::DefOp,
@ -250,7 +250,7 @@ impl TokenKind {
FuncArrow | ProcArrow => 60, // -> =>
Colon | SupertypeOf | SubtypeOf => 50, // : :> <:
Comma => 40, // ,
Equal | OrEqual => 20, // = |=
Equal | Walrus => 20, // = :=
Newline | Semi => 10, // \n ;
LParen | LBrace | LSqBr | Indent => 0, // ( { [ Indent
_ => return None,

View file

@ -704,7 +704,7 @@ impl LimitedDisplay for SubrType {
var_params.typ().limited_fmt(f, limit - 1)?;
}
for pt in self.default_params.iter() {
write!(f, ", {} |= ", pt.name().unwrap())?;
write!(f, ", {} := ", pt.name().unwrap())?;
pt.typ().limited_fmt(f, limit - 1)?;
}
write!(f, ") {} ", self.kind.arrow())?;
@ -1075,7 +1075,7 @@ impl fmt::Display for ArgsOwnership {
write!(f, ", ...{o:?}")?;
}
for (name, o) in self.defaults.iter() {
write!(f, ", {name} |= {o:?}")?;
write!(f, ", {name} := {o:?}")?;
}
write!(f, ")")?;
Ok(())

View file

@ -3,7 +3,7 @@
[![badge](https://img.shields.io/endpoint.svg?url=https%3A%2F%2Fgezf7g7pd5.execute-api.ap-northeast-1.amazonaws.com%2Fdefault%2Fsource_up_to_date%3Fowner%3Derg-lang%26repos%3Derg%26ref%3Dmain%26path%3Ddoc/EN/syntax/00_basic.md%26commit_hash%3D21e8145e83fb54ed77e7631deeee8a7e39b028a3)
](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.
>
> [The Erg book original version (Japanese)](http://mtshiba.me/TheErgBook/)

View file

@ -41,7 +41,7 @@ T = Trait {
.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`
```

View file

@ -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 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
math_log x: Ratio, base |= math.E = ...
math_log x: Ratio, base := math.E = ...
assert math_log(100, 10) == 2
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`.
```erg
p! x |= 0 = print!
p! x := 0 = print!
p!(2) # 2
p!() # 0
p!(None) # None
@ -106,20 +106,20 @@ p!(None) # None
Can also be used with type specification and patterns.
```erg
math_log x, base: Ratio |= math.E = ...
f [x, y] |= [1, 2] = ...
math_log x, base: Ratio := math.E = ...
f [x, y] := [1, 2] = ...
```
However, within the default arguments, it is not possible to call the procedures (described later) or assign mutable objects.
```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.
```erg
f x |= 1, y |= x = ... # NG
f x := 1, y := x = ... # NG
```
## Variable-length arguments

View file

@ -134,20 +134,20 @@ f {x: Int; y: Int} = ...
```erg
Point = Inherit {x = Int; y = Int}
p = Point.{x = 1; y = 2}
Point.{x; y} = p
p = Point::{x = 1; y = 2}
Point::{x; y} = p
Nil T = Class Impl: Phantom T
Nil T = Class Impl := Phantom T
Cons T = Inherit {head = T; rest = List T}
List T = Enum Nil(T), Cons(T)
List T.
first self =
match self:
Cons.{head; ...} -> x
Cons::{head; ...} -> x
_ -> ...
second self =
match self:
Cons.{rest=Cons.{head; ...} ; ...} -> head
Cons::{rest=Cons::{head; ...} ; ...} -> head
_ -> ...
```

View file

@ -20,7 +20,21 @@ 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.
## Inheritable
@ -37,7 +51,7 @@ Use to override an attribute, which by default Erg will fail if you try to defin
## Impl
Indicates implementation of the argument trace.
Indicates implementation of traits.
```erg
ClosedAdd = Trait {
@ -47,11 +61,11 @@ ClosedSub = Trait {
. `_-_` = Self.(Self) -> Self
}
C = Class({i = Int}, Impl: ClosedAdd and ClosedSub)
C = Class {i = Int}
C.
@Impl Add.
@Impl ClosedAdd
`_+_` self, other = C.new {i = self::i + other::i}
@Impl Sub
@Impl ClosedSub
`_-_` self, other = C.new {i = self::i - other::}
```
@ -70,9 +84,9 @@ Add R = Trait {
@Attach AddForInt, AddForOdd
ClosedAdd = Subsume Add(Self)
AddForInt = Patch(Int, Impl: ClosedAdd)
AddForInt = Patch(Int, Impl := ClosedAdd)
AddForInt.AddO = Int
AddForOdd = Patch(Odd, Impl: ClosedAdd)
AddForOdd = Patch(Odd, Impl := ClosedAdd)
AddForOdd.AddO = Even
```
@ -86,7 +100,7 @@ assert Int.AddO == Int
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
@Attach X

View file

@ -17,7 +17,7 @@ It looks like just an increase in `|>`, but since the bond strength is low, the
``` erg
rand = -1.0..1.0 |>.sample!()
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)`
evens = 1..100 |>.iter |>.filter i -> i % 2 == 0 |>.collect Array
# or

View file

@ -1,9 +1,8 @@
# The Grammar of Erg (ver 0.1.0, provisional)
special_op ::= '=' | '->' | '=>' | '.' | ',' | ':' | '|>' | '&'
special_op ::= '=' | '->' | '=>' | '.' | ',' | ':' | '::' | '|>' | '&'
separator ::= ';' | '\n'
escape ::= '\'
comment_marker ::= '#'
comment ::= '#' .* '\n'
reserved_symbol ::= special_op | separator | comment_marker
number ::= [0-9]
first_last_dight ::= number
@ -28,7 +27,8 @@ parenthesis ::= '(' | ')'
bracket ::= '{' | '}'
square_bracket ::= '[' | ']'
enclosure ::= parenthesis | bracket | square_bracket
infix_op ::= '+' | '-' | '*' | '/' | '//' | '**' | '%' | '&&' | '||' | '^^' | '<' | '<=' | '>' | '>='
infix_op ::= '+' | '-' | '*' | '/' | '//' | '**'
| '%' | '&&' | '||' | '^^' | '<' | '<=' | '>' | '>='
| 'and' | 'or' | 'is' | 'as' | 'isnot' | 'in' | 'notin' | 'dot' | 'cross'
prefix_op ::= '+' | '-' | '*' | '**' | '..' | '..<' | '~' | '&' | '!'
postfix_op ::= '?' | '..' | '<..'
@ -68,10 +68,21 @@ decorator ::= call
lambda_func ::= params_opt_t '->' body
lambda_proc ::= params_opt_t '=>' body
lambda ::= lambda_func | lambda_proc
array ::= '[' enc_args ']'
normal_array ::= '[' enc_args ']'
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 ::= /* ... */
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+
program ::= expr? | (line | comment)*

View file

@ -70,7 +70,7 @@ You can also use a subtype specification when defining a class to statically che
```erg
# Class C is a subtype of Show
C = Class Object, Impl: Show
C = Class Object, Impl := Show
C.show self = ... # Show's required attributes.
```

View file

@ -27,7 +27,7 @@ Point2D <: Norm # TypeError: Point2D is not a subtype of Norm
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
T = Trait {.x = Int}
@ -49,7 +49,7 @@ assert points.iter().map(x -> x.norm()).collect(Array) == [5, 25].
## 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`.
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.
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
Add = Trait {

View file

@ -3,7 +3,7 @@
[![badge](https://img.shields.io/endpoint.svg?url=https%3A%2F%2Fgezf7g7pd5.execute-api.ap-northeast-1.amazonaws.com%2Fdefault%2Fsource_up_to_date%3Fowner%3Derg-lang%26repos%3Derg%26ref%3Dmain%26path%3Ddoc/EN/syntax/type/05_inheritance.md%26commit_hash%3D8586bf6f02bd04fd5c823b3a476238881ef037de)](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 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
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()`.
```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)`.

View file

@ -113,7 +113,7 @@ Reverse = Trait {
.reverse = Self.() -> Self
}
StrReverse = Patch Str, Impl: Reverse
StrReverse = Patch Str, Impl := Reverse
StrReverse.
reverse self =
self.iter().rev().collect(Str)
@ -128,7 +128,7 @@ NumericStr = Inherit Str
NumericStr.
...
NumStrRev = Patch NumericStr, Impl: Reverse
NumStrRev = Patch NumericStr, Impl := Reverse
NumStrRev.
...
# DuplicatePatchError: NumericStr is already associated with `Reverse`
@ -160,7 +160,7 @@ Reverse = Trait {
.reverse = Self.() -> Self
}
StrReverse = Patch(Str, Impl: Reverse)
StrReverse = Patch(Str, Impl := Reverse)
StrReverse.
reverse self =
self.iter().rev().collect(Str)

View file

@ -34,7 +34,7 @@ f x =
print! f::x, module::x
# 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).
x self = self::Phantom
@ -46,7 +46,7 @@ Transitions are specified with `~>`.
```erg
# 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!().
# Variables that do not change can be omitted by passing `_`.
start! ref! self("stopped" ~> "running") =

View file

@ -53,7 +53,7 @@ assert not c in D
## Subtyping of subroutines
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.
```erg
@ -66,7 +66,7 @@ f2 x, y: Add = 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

View file

@ -5,8 +5,8 @@
Erg can create Generalized Algebraic Data Types (GADTs) by classifying Or (Union) types.
```erg
Nil T = Class(Impl: Phantom T)
Cons T = Class {head = T; rest = List T}, Impl: Unpack
Nil T = Class(Impl := Phantom T)
Cons T = Class {head = T; rest = List T}, Impl := Unpack
List T: Type = Class(Nil T or Cons T)
List.
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
List: (Type, {"Empty", "Nonempty"}) -> Type
List T, "Empty" = Class(Impl: Phantom T)
List T, "Nonempty" = Class {head = T; rest = List(T, _)}, Impl: Unpack
List T, "Empty" = Class(Impl := Phantom T)
List T, "Nonempty" = Class {head = T; rest = List(T, _)}, Impl := Unpack
List.
nil|T|() = Self(T, "Empty").new Nil(T).new()
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
List: (Type, Nat) -> Type
List T, 0 = Class(Impl: Phantom T)
List T, N = Class {head = T; rest = List(T, N-1)}, Impl: Unpack
List T, 0 = Class(Impl := Phantom T)
List T, N = Class {head = T; rest = List(T, N-1)}, Impl := Unpack
List.
nil|T|() = Self(T, 0).new Nil(T).new()
cons head, rest | T, N = Self(T, N).new {head; rest}

View file

@ -5,25 +5,25 @@
First, let's look at an example of the use of default parameters.
```erg
f: (Int, Int, z |= Int) -> Int
f(x, y, z |= 0) = x + y + z
f: (Int, Int, z := Int) -> Int
f(x, y, z := 0) = x + y + z
g: (Int, Int, z |= Int, w |= Int) -> Int
g(x, y, z |= 0, w |= 1) = x + y + z + w
g: (Int, Int, z := Int, w := Int) -> Int
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, 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(g, [1, 2, 3]) == 8
```
The parameters after `|=` are default parameters.
The parameters after `:=` are default parameters.
The subtyping rules are as follows.
```erg
((X, y |= Y) -> Z) <: (X -> Z)
((X, y |= Y, ...) -> Z) -> Z) <: ((X, ...) -> Z)
((X, y := Y) -> 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.

View file

@ -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.
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
Light = Subsume Marker
@ -19,7 +19,7 @@ Person = Class {.name = Str; .age = Nat} and Light
```erg
M = Subsume Marker
MarkedInt = Inherit Int, Impl: M
MarkedInt = Inherit Int, Impl := M
i = MarkedInt.new(2)
assert i + 1 == 2
@ -29,5 +29,5 @@ assert i in M
The marker class can also be removed with the `Excluding` argument.
```erg
NInt = Inherit MarkedInt, Impl: N, Excluding: M
NInt = Inherit MarkedInt, Impl := N, Excluding: M
```

View file

@ -5,7 +5,7 @@
The ``T!`` type is described as a box type that can be replaced by any ``T`` type object.
```erg
Particle!State: {"base", "excited"}! = Class(... Impl: Phantom State)
Particle!State: {"base", "excited"}! = Class(... Impl := Phantom State)
Particle!
# This method moves the State from "base" to "excited".
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.
```erg
Nil T = Class(Impl: Phantom T)
Nil T = Class(Impl := Phantom T)
List T, !0 = Inherit Nil T
List T, N: Nat! = Class {head = T; rest = List(T, !N-1)}
List(T, !N).

View file

@ -2,17 +2,17 @@
[![badge](https://img.shields.io/endpoint.svg?url=https%3A%2F%2Fgezf7g7pd5.execute-api.ap-northeast-1.amazonaws.com%2Fdefault%2Fsource_up_to_date%3Fowner%3Derg-lang%26repos%3Derg%26ref%3Dmain%26path%3Ddoc/EN/syntax/type/advanced/overloading.md%26commit_hash%3D317b5973c354984891523d14a5e6e8f1cc3923ec)](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.
```erg
Add1 = Trait {
.add1: Self.() -> Self
}
IntAdd1 = Patch Int, Impl: Add1
IntAdd1 = Patch Int, Impl := Add1
IntAdd1.
add1 self = self + 1
RatioAdd1 = Patch Ratio, Impl: Add1
RatioAdd1 = Patch Ratio, Impl := Add1
RatioAdd1.
add1 self = self + 1.0
@ -37,7 +37,7 @@ Also, overloading of types with different numbers of arguments can be reproduced
```erg
C = Class {.x = Int; .y = Int}
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)
```
@ -64,7 +64,7 @@ Second, it is incompatible with default arguments. When a function with default
```erg
f x: Int = ...
f(x: Int, y |= 0) = ...
f(x: Int, y := 0) = ...
f(1) # which is chosen?
```

View file

@ -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.
```erg
Nil T = Class(Impl: Phantom T)
Nil T = Class(Impl := Phantom T)
List T, 0 = Inherit Nil T
List T, N: Nat = Class {head = T; rest = List(T, N-1)}

View file

@ -10,7 +10,7 @@ Add R = Trait {
.AddO = Type
}
AddForInt = Patch(Int, Impl: Add Int)
AddForInt = Patch(Int, Impl := Add Int)
AddForInt.
AddO = Int
```

View file

@ -42,7 +42,7 @@ Add R = Trait {
}
ClosedAdd = Subsume Add(Self)
ClosedAddForInt = Patch(Int, Impl: ClosedAdd)
ClosedAddForInt = Patch(Int, Impl := ClosedAdd)
ClosedAddForInt.
AddO = Int

View file

@ -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.
```erg
Ok = Class Impl: Singleton
Err = Class Impl: Singleton
Ok = Class Impl := Singleton
Err = Class Impl := Singleton
ErrWithInfo = Inherit {info = Str}
Status = Enum Ok, Err, ErrWithInfo
stat: Status = Status.cons(ErrWithInfo) {info = "error caused by ..."}
match! stat:
Status.Ok -> ...
Status.Err -> ...
Status.ErrWithInfo.{info;} -> ...
Status.ErrWithInfo::{info} -> ...
```
```erg

View file

@ -114,15 +114,15 @@ ClassはInt, Bool, Strなど
Complex以外の例として、Vector, Matrix, TensorはNum(Matrix, Tensorの*はそれぞれdot, productと同じ)
### Complex (= Inherit(Object, Impl: Num))
### Complex (= Inherit(Object, Impl := Num))
* `imag: Ratio`: 虚部を返す
* `real: Ratio`: 実部を返す
* `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`: 分子を返す
* `denominator: Int`: 分母を返す

View file

@ -1,4 +1,4 @@
# Interval begin, end: WellOrder
# Interval begin, end := WellOrder
整列集合型(WellOrder)の部分型を表す型です。Interval型にはPreOpen(x<..y)などの派生型が存在します

View file

@ -1,6 +1,6 @@
# 型推論アルゴリズム
> __Info__: この項は編集中であり、一部に間違いを含む可能性があります。
> __Warning__: この項は編集中であり、一部に間違いを含む可能性があります。
以下で用いる表記方法を示します。

View file

@ -1,6 +1,6 @@
# 基本事項
> __Info__: 本ドキュメントは未完成です。校正(文体、正しいリンクが張られているか、など)がなされていません。また、Ergの文法はバージョン0.*の間に破壊的変更が加えられる可能性があり、それに伴うドキュメントの更新が追いついていない可能性があります。予めご了承ください。
> __Warning__: 本ドキュメントは未完成です。校正(文体、正しいリンクが張られているか、など)がなされていません。また、Ergの文法はバージョン0.*の間に破壊的変更が加えられる可能性があり、それに伴うドキュメントの更新が追いついていない可能性があります。予めご了承ください。
> また、本ドキュメントの誤りを見つけた場合は、[こちらのフォーム](https://forms.gle/HtLYRfYzWCAaeTGb6)または[GitHubリポジトリ](https://github.com/mtshiba/TheErgBook/issues/new)から修正の提案をしていただけると幸いです。
本ドキュメントは、Ergの基本文法について解説するものです。[標準API](../API/index.md)や[Ergコントリビューター向けの内部資料](../dev_guide/index.md)は別のディレクトリに置かれています。

View file

@ -39,7 +39,7 @@ T = Trait {
.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`
```

View file

@ -84,10 +84,10 @@ f x:
ある引数が大抵の場合決まりきっており省略できるようにしたい場合、デフォルト引数を使うと良いでしょう。
デフォルト引数は`|=`(or-assign operator)で指定します。`base`が指定されなかったら`math.E``base`に代入します。
デフォルト引数は`:=`(or-assign operator)で指定します。`base`が指定されなかったら`math.E``base`に代入します。
```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) == math_log(100, math.E)
@ -96,7 +96,7 @@ assert math_log(100) == math_log(100, math.E)
引数を指定しないことと`None`を代入することは区別されるので注意してください。
```erg
p! x |= 0 = print! x
p! x := 0 = print! x
p!(2) # 2
p!() # 0
p!(None) # None
@ -105,20 +105,20 @@ p!(None) # None
型指定、パターンと併用することもできます。
```erg
math_log x, base: Ratio |= math.E = ...
f [x, y] |= [1, 2] = ...
math_log x, base: Ratio := math.E = ...
f [x, y] := [1, 2] = ...
```
しかしデフォルト引数内では、後述するプロシージャを呼び出したり、可変オブジェクトを代入したりすることができません。
```erg
f x |= p! 1 = ... # NG
f x := p! 1 = ... # NG
```
また、定義したばかりの引数はデフォルト引数に渡す値として使えません。
```erg
f x |= 1, y |= x = ... # NG
f x := 1, y := x = ... # NG
```
## 可変長引数

View file

@ -141,7 +141,7 @@ foo.public() # AttributeError: 'Foo' has no attribute 'public' ('public' is defi
{Foo; ...} = import "foo"
FooImpl = Patch Foo
FooImpl::
FooImpl :=:
private self = pass
FooImpl.
public self = self::private()

View file

@ -135,20 +135,20 @@ f {x: Int; y: Int} = ...
```erg
Point = Inherit {x = Int; y = Int}
p = Point.{x = 1; y = 2}
Point.{x; y} = p
p = Point::{x = 1; y = 2}
Point::{x; y} = p
Nil T = Class Impl: Phantom T
Nil T = Class Impl := Phantom T
Cons T = Inherit {head = T; rest = List T}
List T = Enum Nil(T), Cons(T)
List T.
first self =
match self:
Cons.{head; ...} -> x
Cons::{head; ...} -> x
_ -> ...
second self =
match self:
Cons.{rest=Cons.{head; ...}; ...} -> head
Cons::{rest=Cons::{head; ...}; ...} -> head
_ -> ...
```

View file

@ -17,7 +17,21 @@ X = ...
X = deco(X)
```
Ergでは変数の再代入が出来ないので、上のようなコードは通らず、デコレータが必要なのです。
Ergでは変数の再代入が出来ないので、上のようなコードは通りません。
単なる変数の場合は`X = deco(...)`と同じなのですが、インスタントブロックやサブルーチンの場合はそうすることができないので、デコレータが必要になってきます。
```erg
@deco
f x =
y = ...
x + y
# コードが横長になるのを防ぐこともできる
@LongNameDeco1
@LongNameDeco2
C = Class ...
```
以下に、頻出の組み込みデコレータを紹介します。
## Inheritable
@ -44,7 +58,7 @@ Sub = Trait {
.`_-_` = Self.(Self) -> Self
}
C = Class({i = Int}, Impl: Add and Sub)
C = Class({i = Int}, Impl := Add and Sub)
C.
@Impl Add
`_+_` self, other = C.new {i = self::i + other::i}
@ -66,9 +80,9 @@ Add R = Trait {
@Attach AddForInt, AddForOdd
ClosedAdd = Subsume Add(Self)
AddForInt = Patch(Int, Impl: ClosedAdd)
AddForInt = Patch(Int, Impl := ClosedAdd)
AddForInt.AddO = Int
AddForOdd = Patch(Odd, Impl: ClosedAdd)
AddForOdd = Patch(Odd, Impl := ClosedAdd)
AddForOdd.AddO = Even
```

View file

@ -15,7 +15,7 @@ assert f(g(x, y)) == ((x, y) |> g |> f)
rand = -1.0..1.0 |>.sample!()
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
# パイプライン演算子を使わずに実装する場合、

View file

@ -1,9 +1,8 @@
# The Grammar of Erg (ver 0.1.0, provisional)
special_op ::= '=' | '->' | '=>' | '.' | ',' | ':' | '|>' | '&'
special_op ::= '=' | '->' | '=>' | '.' | ',' | ':' | '::' | '|>' | '&'
separator ::= ';' | '\n'
escape ::= '\'
comment_marker ::= '#'
comment ::= '#' .* '\n'
reserved_symbol ::= special_op | separator | comment_marker
number ::= [0-9]
first_last_dight ::= number
@ -28,7 +27,8 @@ parenthesis ::= '(' | ')'
bracket ::= '{' | '}'
square_bracket ::= '[' | ']'
enclosure ::= parenthesis | bracket | square_bracket
infix_op ::= '+' | '-' | '*' | '/' | '//' | '**' | '%' | '&&' | '||' | '^^' | '<' | '<=' | '>' | '>='
infix_op ::= '+' | '-' | '*' | '/' | '//' | '**'
| '%' | '&&' | '||' | '^^' | '<' | '<=' | '>' | '>='
| 'and' | 'or' | 'is' | 'as' | 'isnot' | 'in' | 'notin' | 'dot' | 'cross'
prefix_op ::= '+' | '-' | '*' | '**' | '..' | '..<' | '~' | '&' | '!'
postfix_op ::= '?' | '..' | '<..'
@ -68,10 +68,21 @@ decorator ::= call
lambda_func ::= params_opt_t '->' body
lambda_proc ::= params_opt_t '=>' body
lambda ::= lambda_func | lambda_proc
array ::= '[' enc_args ']'
normal_array ::= '[' enc_args ']'
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 ::= /* ... */
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+
program ::= expr? | (line | comment)*

View file

@ -215,8 +215,8 @@ age = match person:
```erg
Point = Inherit {x = Int; y = Int}
p = Point.{x = 1; y = 2}
Point.{x; y} = p
p = Point::{x = 1; y = 2}
Point::{x; y} = p
```
## 内包表記

View file

@ -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
Add = Trait {

View file

@ -125,7 +125,7 @@ Inherited!.
例えば`Real`(`Add()`を実装する)のサブタイプである`Int`では`Add()`を再実装しているようにみえます。
```erg
Int = Class ..., Impl: Add() and ...
Int = Class ..., Impl := Add() and ...
```
しかし実際は`Real``Add()``Add(Real, Real)`の略で、`Int`では`Add(Int, Int)`で上書きしているだけです。

View file

@ -110,7 +110,7 @@ Reverse = Trait {
.reverse = Self.() -> Self
}
StrReverse = Patch Str, Impl: Reverse
StrReverse = Patch Str, Impl := Reverse
StrReverse.
reverse self =
self.iter().rev().collect(Str)
@ -125,7 +125,7 @@ NumericStr = Inherit Str
NumericStr.
...
NumStrRev = Patch NumericStr, Impl: Reverse
NumStrRev = Patch NumericStr, Impl := Reverse
NumStrRev.
...
# DuplicatePatchError: NumericStr is already associated with `Reverse`
@ -157,7 +157,7 @@ Reverse = Trait {
.reverse = Self.() -> Self
}
StrReverse = Patch(Str, Impl: Reverse)
StrReverse = Patch(Str, Impl := Reverse)
StrReverse.
reverse self =
self.iter().rev().collect(Str)

View file

@ -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}`となります。

View file

@ -32,7 +32,7 @@ f x =
print! f::x, module::x
# Phantom型は型引数と同じ値になるPhantomという属性を持っている
T X: Int = Class Impl: Phantom X
T X: Int = Class Impl := Phantom X
T(X).
x self = self::Phantom
@ -44,7 +44,7 @@ T(1).x() # 1
```erg
# `Id`は不変型なので遷移させることはできないことに注意
VM!(State: {"stopped", "running"}! |= _, Id: Nat |= _) = Class(..., Impl: Phantom! State)
VM!(State: {"stopped", "running"}! := _, Id: Nat := _) = Class(..., Impl := Phantom! State)
VM!().
# 変わらない変数は`_`を渡せば省略可能, デフォルト引数にしておけば書く必要すらない
start! ref! self("stopped" ~> "running") =

View file

@ -3,8 +3,8 @@
ErgはOr型をクラス化することで一般化代数的データ型(GADTs)を作成出来ます。
```erg
Nil T = Class(Impl: Phantom T)
Cons T = Class {head = T; rest = List T}, Impl: Unpack
Nil T = Class(Impl := Phantom T)
Cons T = Class {head = T; rest = List T}, Impl := Unpack
List T: Type = Class(Nil T or Cons T)
List.
nil|T|() = Self(T).new Nil(T).new()
@ -30,8 +30,8 @@ _: List Int = cons 1, i
```erg
List: (Type, {"Empty", "Nonempty"}) -> Type
List T, "Empty" = Class(Impl: Phantom T)
List T, "Nonempty" = Class {head = T; rest = List(T, _)}, Impl: Unpack
List T, "Empty" = Class(Impl := Phantom T)
List T, "Nonempty" = Class {head = T; rest = List(T, _)}, Impl := Unpack
List.
nil|T|() = Self(T, "Empty").new Nil(T).new()
cons head, rest | T = Self(T, "Nonempty").new {head; rest}
@ -48,8 +48,8 @@ Ergではさらに精密化して、長さを持つリストを定義できま
```erg
List: (Type, Nat) -> Type
List T, 0 = Class(Impl: Phantom T)
List T, N = Class {head = T; rest = List(T, N-1)}, Impl: Unpack
List T, 0 = Class(Impl := Phantom T)
List T, N = Class {head = T; rest = List(T, N-1)}, Impl := Unpack
List.
nil|T|() = Self(T, 0).new Nil(T).new()
cons head, rest | T, N = Self(T, N).new {head; rest}

View file

@ -3,25 +3,25 @@
まず、デフォルト引数の使用例を見る。
```erg
f: (Int, Int, z |= Int) -> Int
f(x, y, z |= 0) = x + y + z
f: (Int, Int, z := Int) -> Int
f(x, y, z := 0) = x + y + z
g: (Int, Int, z |= Int, w |= Int) -> Int
g(x, y, z |= 0, w |= 1) = x + y + z + w
g: (Int, Int, z := Int, w := Int) -> Int
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, 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(g, [1, 2, 3]) == 8
```
`|=`以降の引数はデフォルト引数である。
`:=`以降の引数はデフォルト引数である。
部分型付け規則は以下の通り。
```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番目は、デフォルト引数のある関数は、ない関数と同一視できる、という意味である。

View file

@ -17,7 +17,7 @@ Person = Class {.name = Str; .age = Nat} and Light
```erg
M = Subsume Marker
MarkedInt = Inherit Int, Impl: M
MarkedInt = Inherit Int, Impl := M
i = MarkedInt.new(2)
assert i + 1 == 2
@ -27,5 +27,5 @@ assert i in M
マーカークラスは`Excluding`引数で外すことも可能である。
```erg
NInt = Inherit MarkedInt, Impl: N, Excluding: M
NInt = Inherit MarkedInt, Impl := N, Excluding: M
```

View file

@ -3,7 +3,7 @@
`T!`型は任意の`T`型オブジェクトを入れられて差し替え可能なボックス型であると説明した。
```erg
Particle! State: {"base", "excited"}! = Class(..., Impl: Phantom State)
Particle! State: {"base", "excited"}! = Class(..., Impl := Phantom State)
Particle!.
# このメソッドはStateを"base"から"excited"に遷移させる
apply_electric_field!(ref! self("base" ~> "excited"), field: Vector) = ...
@ -31,7 +31,7 @@ v: [Str; !1]
可変構造型はもちろんユーザー定義も可能である。ただし、不変構造型とは構成法に関していくつか違いがあるので注意が必要である。
```erg
Nil T = Class(Impl: Phantom T)
Nil T = Class(Impl := Phantom T)
List T, !0 = Inherit Nil T
List T, N: Nat! = Class {head = T; rest = List(T, !N-1)}
List(T, !N).

View file

@ -7,10 +7,10 @@ Ergでは __アドホック多相__ をサポートしない。すなわち、
Add1 = Trait {
.add1: Self.() -> Self
}
IntAdd1 = Patch Int, Impl: Add1
IntAdd1 = Patch Int, Impl := Add1
IntAdd1.
add1 self = self + 1
RatioAdd1 = Patch Ratio, Impl: Add1
RatioAdd1 = Patch Ratio, Impl := Add1
RatioAdd1.
add1 self = self + 1.0
@ -35,7 +35,7 @@ assert add1(1.0) == 2.0
```erg
C = Class {.x = Int; .y = Int}
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)
```
@ -62,7 +62,7 @@ id "str" # TypeError: id is not implemented for Str
```erg
f x: Int = ...
f(x: Int, y |= 0) = ...
f(x: Int, y := 0) = ...
f(1) # which is chosen?
```

View file

@ -32,7 +32,7 @@ List T, N: Nat = Class {head = T; rest = List(T, N-1)}
このようなときにちょうどよいのが幽霊型である。幽霊型はサイズ0の型を一般化した型である。
```erg
Nil T = Class(Impl: Phantom T)
Nil T = Class(Impl := Phantom T)
List T, 0 = Inherit Nil T
List T, N: Nat = Class {head = T; rest = List(T, N-1)}
@ -46,7 +46,7 @@ assert nil.__size__ == 0
この場合も、`state`はオブジェクトの実体に現れないハリボテの型変数である。
```erg
VM! State: {"stopped", "running"}! = Class(..., Impl: Phantom! State)
VM! State: {"stopped", "running"}! = Class(..., Impl := Phantom! State)
VM!("stopped").
start ref! self("stopped" ~> "running") =
self.do_something!()

View file

@ -8,7 +8,7 @@ Add R = Trait {
.AddO = Type
}
AddForInt = Patch(Int, Impl: Add Int)
AddForInt = Patch(Int, Impl := Add Int)
AddForInt.
AddO = Int
```

View file

@ -40,7 +40,7 @@ Add R = Trait {
}
ClosedAdd = Subsume Add(Self)
ClosedAddForInt = Patch(Int, Impl: ClosedAdd)
ClosedAddForInt = Patch(Int, Impl := ClosedAdd)
ClosedAddForInt.
AddO = Int

View file

@ -133,11 +133,11 @@ K T = Class(...)
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を受け入れるともみなせる
assert InputStream(Str) > InputStream(Object)
OutputStream T = Class ..., Impl: Outputs(T)
OutputStream T = Class ..., Impl := Outputs(T)
# Strを出力するストリームは、Objectを出力するともみなせる
assert OutputStream(Str) < OutputStream(Object)
```

View file

@ -44,15 +44,15 @@ FinalWrapper.
また、`Enum`を使うと、その選択肢となる型がリダイレクト属性として自動的に定義されます。
```erg
Ok = Class Impl: Singleton
Err = Class Impl: Singleton
Ok = Class Impl := Singleton
Err = Class Impl := Singleton
ErrWithInfo = Inherit {info = Str}
Status = Enum Ok, Err, ErrWithInfo
stat: Status = Status.cons(ErrWithInfo) {info = "error caused by ..."}
match! stat:
Status.Ok -> ...
Status.Err -> ...
Status.ErrWithInfo.{info;} -> ...
Status.ErrWithInfo::{info;} -> ...
```
```erg

View file

@ -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.
new x, y = Self::__new__ {x; y}
norm &self = self::x**2 + self::y**2

View file

@ -1,17 +1,17 @@
@Inheritable
Point2D = Class {x = Int; y = Int}
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
Point3D = Inherit Point2D, Additional: {z = Int}
Point3D = Inherit Point2D, Additional := {z = Int}
Point3D.
@Override
new x, y, z = Self::__new__ {x; y; z}
new x, y, z = Self::__new__ {x = x; y = y; z = z}
@Override
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}
UnpackPoint2D.{x; y} = p
p = UnpackPoint2D::{x = 1; y = 2}
UnpackPoint2D::{x = x; y = x} = p

View file

@ -1,20 +1,20 @@
LitExpr = Class {.i = Int}, Impl: Show
LitExpr = Class {.i = Int}, Impl := Show
LitExpr.
new i = Self::__new__ {.i;}
show &self = "{self.i}"
AddExpr = Class {.lhs = Expr, .rhs = Expr}, Impl: Show
AddExpr = Class {.lhs = Expr, .rhs = Expr}, Impl := Show
AddExpr.
new lhs, rhs = Self::__new__ {.lhs; .rhs}
show &self = "{self.lhs} + {self.rhs}"
SubExpr = Class {.lhs = Expr, .rhs = Expr}, Impl: Show
SubExpr = Class {.lhs = Expr, .rhs = Expr}, Impl := Show
SubExpr.
new lhs, rhs = Self::__new__ {.lhs; .rhs}
show &self = "{self.lhs} - {self.rhs}"
PosExpr = Class {.expr = Expr}, Impl: Show
PosExpr = Class {.expr = Expr}, Impl := Show
PosExpr.
new expr = Self::__new__ {.expr;}
show &self = "+{self.expr}"
NegExpr = Class {.expr = Expr}, Impl: Show
NegExpr = Class {.expr = Expr}, Impl := Show
NegExpr.
new expr = Self::__new__ {.expr;}
show &self = "-{self.expr}"

View file

@ -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)}
List: (Type, Nat) -> Type
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.
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
a = cons(nil(Int), 1) |> cons 2 |> cons 3
match a:
Cons(_, _).{head=h1; rest=Cons(_, _).{head=h2; rest}} ->
Cons(_, _)::{head=h1; rest=Cons(_, _)::{head=h2; rest}} ->
assert h1 == 3
assert h2 == 2
assert rest == Cons.{head = 1; rest = nil(Int)}
assert rest == Cons::{head = 1; rest = nil(Int)}
_ ->
pass

View file

@ -1,8 +1,8 @@
p = (1, 2)
assert p.0 == 1
q = (1, 1.0)
assert q.1 == 1.0
q = (1, True)
assert q.1
i, j = 0, 1
assert i == 0