Skip to content

Commit

Permalink
feat: recursive pattern match (#5)
Browse files Browse the repository at this point in the history
* dev: draft pattern matching

* fix: unexpected .e in eval

* fix: platform independent path for linker output

* fix: workaround for noCore import handling

* gg

* revert: expression change

* feat: pattern match on simple enum class

* feat: pattern match on sample class instance

* dev: match result

* dev: reorder syntax cons

* dev: pass all tests

* dev: simplify matchPat

* dev: start match building

* dev: refactor a bit

* dev: elementary value match

* dev: draft recursive match building

* dev: finish recursive match building

* dev: fix some recursion bugs

* dev: value coverage check

* dev: pass all samples

---------

Co-authored-by: seven-mile <[email protected]>
  • Loading branch information
Myriad-Dreamin and seven-mile authored Sep 26, 2024
1 parent 7d7b870 commit e93a0b7
Show file tree
Hide file tree
Showing 52 changed files with 1,882 additions and 770 deletions.
9 changes: 9 additions & 0 deletions fixtures/Type/matches/HelloWorld.cos-ast
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
class T { val x = 1; }
----- -----
T match {
case T => 1
}
-----
T match {
case _ => 1
}
5 changes: 5 additions & 0 deletions fixtures/Type/matches/class.cos-ast
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class T { val x = 1; val y = 1; }
----- -----
T(x: 1, y: 2) match {
case T(x, y) => x + y
}
18 changes: 18 additions & 0 deletions fixtures/Type/matches/json.cos-ast
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
class ValueT(T: Type) {
case Null;
case Elem(T);
}
val v1 = ValueT(i32).Null;
val v2: ValueT(i32) = v1;
----- -----
ValueT(i32).Null match {
case ValueT(i32).Null => 1
}
-----
v1 match {
case ValueT(i32).Null => 1
}
-----
v2 match {
case ValueT(i32).Null => 1
}
25 changes: 25 additions & 0 deletions fixtures/Type/matches/nat.cos-ast
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
class Nat {
case Zero
case Succ(Nat)
};
val v1 = Nat.Zero;
val v2: Nat = Nat.Succ(Nat.Zero);
----- -----
Nat.Zero match {
case Nat.Zero => 1
}
-----
Nat.Succ(Nat.Zero) match {
case Nat.Succ(Nat.Zero) => 1
}
-----
v2 match {
case Nat.Zero => 0
case Nat.Succ(x) => 1
}
-----
v2 match {
case Nat.Zero => 0
case Nat.Succ(Nat.Zero) => 1
case Nat.Succ(Nat.Succ(x)) => 2
}
32 changes: 32 additions & 0 deletions fixtures/Type/matches/number.cos-ast
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
val n1 = 1
----- -----
1 match {
case 1 => 2
}
-----
1 match {
case 0 => 2
}
-----
n1 match {
case 1 => 3
}
-----
n1 match {
case 0 => 4
}
-----
1 match {
case 0 => 5
case 1 => 6
}
-----
1 match {
case 0 => 7
case 1 => 8
}
-----
n1 + 1 match {
case 0 => 3
case 1 => 4
}
15 changes: 15 additions & 0 deletions fixtures/Type/matches/result.cos-ast
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
class Result[T, E] {
case Ok(T);
case Err(E);
};
val v0: Result(i32, i32) = Result(i32, i32).Ok(1);
val v1 = v0;
----- -----
v0 match {
case Result(i32, i32).Ok(t) => t
}
-----
v1 match {
case Result(i32, i32).Ok(t) => t
case Result(i32, i32).Err(e) => ???
}
37 changes: 37 additions & 0 deletions fixtures/Type/matches/string.cos-ast
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
val v1 = "yes"
----- -----
"yes" match {
case "yes" => 1
}
-----
"yes" match {
case "no" => 2
}
-----
v1 match {
case "yes" => 3
}
-----
v1 match {
case "no" => 4
}
-----
"yes" match {
case "yes" => 5
case "no" => 6
}
-----
"no" match {
case "yes" => 7
case "no" => 8
}
-----
v1 match {
case "yes" => 5
case "no" => 6
}
-----
v1 match {
case "yes" => 7
case "no" => 8
}
3 changes: 3 additions & 0 deletions fixtures/Type/patterns/HelloWorld.cos-ast
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
class T { val x = 1; }
-----
T match T
5 changes: 5 additions & 0 deletions fixtures/Type/patterns/class.cos-ast
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class T { val x = 1; }
-----
T(x: 1) match T
T(x: 1) match T(x: 1)
T match T(x: 1)
5 changes: 5 additions & 0 deletions fixtures/Type/patterns/class2.cos-ast
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class T { val x = 1; val y = 1; }
-----
T(x: 1, y: 2) match T
T(x: 1, y: 2) match T(x: 1)
T(x: 1) match T(x: 1)
20 changes: 20 additions & 0 deletions fixtures/Type/patterns/nat.cos-ast
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
class Nat {
case Zero
case Succ(Nat)
};
val v1 = Nat.Zero;
val v2 = Nat.Succ(Nat.Zero);
-----
Nat.Zero match Nat.Zero
Nat.Zero match Nat.Succ(Nat.Zero)
Nat.Succ(Nat.Zero) match Nat.Succ(Nat.Zero)
Nat.Succ(Nat.Zero) match Nat.Succ
Nat.Succ(Nat.Zero) match Nat
v1 match Nat.Succ(Nat.Zero)
v2 match Nat.Succ(Nat.Zero)
v2 match Nat.Succ
v2 match Nat
Nat.Zero match Nat.Succ(t)
v1 match Nat.Succ(t)
Nat.Succ(Nat.Zero) match Nat.Succ(t)
v2 match Nat.Succ(t)
12 changes: 12 additions & 0 deletions fixtures/Type/patterns/result.cos-ast
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
class Result[T, E] {
case Ok(T);
case Err(E);
};
val v0: Result(i32, i32) = Result(i32, i32).Ok(1);
val v1 = v0;
-----
Result(i32, i32).Ok(1) match Result(i32, i32).Ok(1)
Result(i32, i32).Ok(1) match Result(i32, i32).Ok(t)
Result(i32, i32).Ok(1) match Result(i32, i32).Ok(1)
v0 match Result(i32, i32).Ok(t)
v1 match Result(i32, i32).Ok(t)
2 changes: 2 additions & 0 deletions library/std/src/fmt.cos
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@

@noCore();

import std::result;
import std::str;

Expand Down
2 changes: 2 additions & 0 deletions library/std/src/option.cos
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@

@noCore();

class Option[T] {
case Some(T);
case None;
Expand Down
2 changes: 2 additions & 0 deletions library/std/src/prelude/core.cos
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@

@noCore();

import cSys from "@lib/c++/cstdlib"

import _ from std::prelude::lang
Expand Down
55 changes: 2 additions & 53 deletions library/std/src/prelude/core_stage1.cos
Original file line number Diff line number Diff line change
@@ -1,63 +1,12 @@

@noCore();

import "@lib/c++/cstdio"
import "@lib/c++/string"
import "@lib/c++/utility"
import "@lib/c++/iostream"

import _ from std::prelude::lang

code("""
// pub def str: Type = stringSys::std::string
using str = std::string;
template <typename T, typename Cond = void> struct DisplayTrait {};
""")

code("""
template <typename T> inline void print(const T &x) {
using TT = std::decay_t<T>;
DisplayTrait<TT>::print(x);
}
template <typename T> inline void println(const T &x) {
using TT = std::decay_t<T>;
// todo: atomic print
DisplayTrait<TT>::print(x);
printf("\n");
}
template <> struct DisplayTrait<str> {
static void print(const str &x) { printf("%s", x.c_str()); }
};
template <> struct DisplayTrait<bool> {
static void print(bool x) {
if (x) {
printf("true");
} else {
printf("false");
}
}
};
template <typename T>
struct DisplayTrait<
T, std::enable_if_t<std::is_integral_v<T> && std::is_signed_v<T>>> {
static void print(T x) { printf("%lld", static_cast<long long>(x)); }
};
template <typename T>
struct DisplayTrait<
T, std::enable_if_t<std::is_integral_v<T> && std::is_unsigned_v<T>>> {
static void print(T x) { printf("%llu", static_cast<unsigned long long>(x)); }
};
template <> struct DisplayTrait<float32_t> {
static void print(float32_t x) { printf("%f", x); }
};
template <> struct DisplayTrait<float64_t> {
static void print(float64_t x) { printf("%lf", x); }
};
""")

code("""
[[noreturn]] inline void panic(const std::string& msg) {
Expand Down
55 changes: 55 additions & 0 deletions library/std/src/prelude/lang.cos
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@

@noCore();

import "@lib/c++/cstdint"
import "@lib/c++/cinttypes"
import "@lib/c++/cstdio"
import "@lib/c++/memory"
import "@lib/c++/variant"
import "@lib/c++/tuple"
import "@lib/c++/string"
import cSys from "@lib/c++/cstdlib"

code("""
using float32_t = float;
using float64_t = double;
using float128_t = long double;
using str = std::string;
namespace cosmo {
template<typename T, typename I, bool isMut = false, typename Cond = void>
Expand All @@ -28,3 +32,54 @@ struct Impl;
}
""");

code("""
// pub def str: Type = stringSys::std::string
template <typename T, typename Cond = void> struct DisplayTrait {};
""")

code("""
template <typename T> inline void print(const T &x) {
using TT = std::decay_t<T>;
DisplayTrait<TT>::print(x);
}
template <typename T> inline void println(const T &x) {
using TT = std::decay_t<T>;
// todo: atomic print
DisplayTrait<TT>::print(x);
printf("\n");
}
template <> struct DisplayTrait<str> {
static void print(const str &x) { printf("%s", x.c_str()); }
};
template <> struct DisplayTrait<bool> {
static void print(bool x) {
if (x) {
printf("true");
} else {
printf("false");
}
}
};
template <typename T>
struct DisplayTrait<
T, std::enable_if_t<std::is_integral_v<T> && std::is_signed_v<T>>> {
static void print(T x) { printf("%lld", static_cast<long long>(x)); }
};
template <typename T>
struct DisplayTrait<
T, std::enable_if_t<std::is_integral_v<T> && std::is_unsigned_v<T>>> {
static void print(T x) { printf("%llu", static_cast<unsigned long long>(x)); }
};
template <> struct DisplayTrait<float32_t> {
static void print(float32_t x) { printf("%f", x); }
};
template <> struct DisplayTrait<float64_t> {
static void print(float64_t x) { printf("%lf", x); }
};
""")
Loading

0 comments on commit e93a0b7

Please sign in to comment.