From 5ef21917aee6b4b6d7063b9e96adb573b33bbd2b Mon Sep 17 00:00:00 2001 From: LordBaryhobal Date: Thu, 9 Jul 2026 23:13:52 +0200 Subject: [PATCH 1/7] chore: update and clean some examples --- .../00_syntax_prototype/01_simple_types.py | 5 +- .../00_syntax_prototype/02_custom_types.midas | 71 ++++- .../00_syntax_prototype/02_custom_types.py | 14 +- .../03_custom_types_v2.midas | 73 ----- .../01_simple_operations.py | 2 +- .../02_simple_types.py | 5 +- .../03_control_flow.py | 14 +- .../04_complex_types.midas | 4 +- .../04_complex_types.py | 10 +- .../01_simple_type_checking/06_overloads.py | 8 +- .../cases/midas-parser/01_simple_types.midas | 8 +- .../01_simple_types.midas.ref.json | 289 ++++++++++++------ 12 files changed, 283 insertions(+), 220 deletions(-) delete mode 100644 examples/00_syntax_prototype/03_custom_types_v2.midas diff --git a/examples/00_syntax_prototype/01_simple_types.py b/examples/00_syntax_prototype/01_simple_types.py index 725fdf4..c974415 100644 --- a/examples/00_syntax_prototype/01_simple_types.py +++ b/examples/00_syntax_prototype/01_simple_types.py @@ -7,10 +7,9 @@ from __future__ import annotations df: Frame[ verified: bool, birth_year: int, - height: float + ( _ > 0 ) + ( _ < 250 ), + height: float, name: str, - date: datetime, + date: object, float, # unnamed unknown: _, # untyped - _ # unnamed and untyped ] diff --git a/examples/00_syntax_prototype/02_custom_types.midas b/examples/00_syntax_prototype/02_custom_types.midas index 017e40c..7b0336c 100644 --- a/examples/00_syntax_prototype/02_custom_types.midas +++ b/examples/00_syntax_prototype/02_custom_types.midas @@ -1,24 +1,63 @@ -// Simple custom type derived from floats -type Latitude -type Longitude +// Simple custom type derived from float +type Custom = float + +// Simple custom types with constraints +type Latitude = float where (-90 <= _ & _ <= 90) +type Longitude = float where (-180 <= _ & _ <= 180) + +// Generic custom type (a Difference of T is derived from T, e.g. a difference of floats is a float +type Difference[T] = T // Complex custom type, containing two values accessible through properties -type GeoLocation { - lat: Latitude - lon: Longitude +type GeoLocation = object + +extend GeoLocation { + prop lat: Latitude + prop lon: Longitude } -type LatitudeDiff -type LongitudeDiff +type GeoLocationDifference = object + +extend GeoLocationDifference { + prop lat: Difference[Latitude] + prop lon: Difference[Longitude] +} + +// Define operations on our custom type // Simple operation defined on our custom types -op - = -op - = +extend Latitude { + def __sub__: fn(Latitude, /) -> Difference[Latitude] +} -// Simple custom type with a constraint -type Age +extend Longitude { + def __sub__: fn(Longitude, /) -> Difference[Longitude] +} -// Predefined custom constraints that can be referenced in other definitions -constraint Positive = _ >= 0 -constraint StrictlyPositive = _ > 0 -//constraint Even = _ % 2 == 0 \ No newline at end of file +extend GeoLocation { + // This type is compatible with the `-` operation with another GeoLocation + // i.e. you can subtract a GeoLocation from another GeoLocation, resulting + // in a GeoLocationDifference + def __sub__: fn(GeoLocation, /) -> GeoLocationDifference +} + + +// Predefined custom predicates that can be referenced in other definitions +predicate Positive(v: float) = v >= 0 +predicate StrictlyPositive(v: float) = v > 0 +predicate Equatorial(loc: GeoLocation) = (-10 <= loc.lat <= 10) +predicate Arctic(loc: GeoLocation) = (loc.lat >= 66) + +type Person = object + +extend Person { + prop name: str + + // Property with an inline constraint + prop age: int where (0 <= _ & _ < 150) + + // Property referencing a predicate + prop height: float where StrictlyPositive(_) + + prop home: GeoLocation +} diff --git a/examples/00_syntax_prototype/02_custom_types.py b/examples/00_syntax_prototype/02_custom_types.py index 8678ba0..e78d458 100644 --- a/examples/00_syntax_prototype/02_custom_types.py +++ b/examples/00_syntax_prototype/02_custom_types.py @@ -8,8 +8,8 @@ df: Frame[ ] # Properties of a type can be used on a column of that type -lat: Column[GeoLocation] = df["location"].lat -lon: Column[GeoLocation] = df["location"].lon +lat: Column[Latitude] = ... +lon: Column[Longitude] = ... # Unregistered operations between types are not permitted lat + lon # Invalid operation @@ -18,13 +18,3 @@ lat + lon # Invalid operation lat1: Latitude = lat[0] lat2: Latitude = lat[1] lat_diff: Difference[Latitude] = lat2 - lat1 # Valid operation - -# In addition to the type, a column can have one or more constraints, either defined inline or in a separate file -df2: Frame[ - age: int + (_ >= 0), - height: float + (_ >= 0), -] -df2_bis: Frame[ - age: int + Positive, - height: float + Positive, -] diff --git a/examples/00_syntax_prototype/03_custom_types_v2.midas b/examples/00_syntax_prototype/03_custom_types_v2.midas deleted file mode 100644 index 31b0f53..0000000 --- a/examples/00_syntax_prototype/03_custom_types_v2.midas +++ /dev/null @@ -1,73 +0,0 @@ -// Simple custom type derived from float -type Custom(float) - -// Simple custom types with constraints -type Latitude(float) where (-90 <= _ <= 90) -type Longitude(float) where (-180 <= _ <= 180) - -// Generic custom type (a Difference of T is derived from T, e.g. a difference of floats is a float -type Difference[T](T) - -// Complex custom type, containing two values accessible through properties -type GeoLocation { - lat: Latitude - lon: Longitude -} - -// Define operations on our custom type -extend GeoLocation { - // This type is compatible with the `-` operation with another GeoLocation - // i.e. you can subtract a GeoLocation from another GeoLocation, resulting - // in a Difference of GeoLocations - op __sub__(GeoLocation) -> Difference[GeoLocation] -} - -// For complex generics, you need to specify how the genericity the properties -// are handled -type Difference[GeoLocation] { - lat: Difference[Latitude] - lon: Difference[Longitude] -} - -// Simple operation defined on our custom types -extend Latitude { - op __sub__(Latitude) -> Difference[Latitude] -} - -extend Longitude { - op __sub__(Longitude) -> Difference[Longitude] -} - -// Predefined custom predicates that can be referenced in other definitions -predicate Positive(v: float) = v >= 0 -predicate StrictlyPositive(v: float) = v > 0 -predicate Equatorial(loc: GeoLocation) = (-10 <= loc.lat <= 10) -predicate Arctic(loc: GeoLocation) = (loc.lat >= 66) - -type Person { - name: str - - // Property with an inline constraint - age: int? where (0 <= _ < 150) - - // Property referencing a predicate - height: float where StrictlyPositive - - home: GeoLocation -} - -// Custom complex type derived from another complex type, with a constraint -// on a property -// Multiple proposed syntaxes, not yet defined - -// Explicit, but new keyword -type EquatorialPerson refines Person where Equatorial(_.home) - -// Explicit with existing keyword, might be confusing if expectations regarding 'is' -type EquatorialPerson is Person where Equatorial(_.home) - -// Consistent and Python-friendly but can be confused with structural extension -type EquatorialPerson(Person) where Equatorial(_.home) - -// Allow new properties, probably not useful -type EquatorialPerson extends Person where Equatorial(_.home) diff --git a/examples/01_simple_type_checking/01_simple_operations.py b/examples/01_simple_type_checking/01_simple_operations.py index 4e767f2..8d7c6f8 100644 --- a/examples/01_simple_type_checking/01_simple_operations.py +++ b/examples/01_simple_type_checking/01_simple_operations.py @@ -6,7 +6,7 @@ c = a + b # -> int c = "invalid" # -> can't assign str to int variable d = True -e = d + d +e = d + d # -> addition not defined between booleans f: float = a diff --git a/examples/01_simple_type_checking/02_simple_types.py b/examples/01_simple_type_checking/02_simple_types.py index c015a75..ad5118d 100644 --- a/examples/01_simple_type_checking/02_simple_types.py +++ b/examples/01_simple_type_checking/02_simple_types.py @@ -1,6 +1,7 @@ # type: ignore # ruff: disable [F821] -distance: Meter = cast(Meter, 123.45) -time: Second = cast(Second, 6.7) +distance = cast(Meter, 123.45) +time = cast(Second, 6.7) speed = distance / time +print(speed) diff --git a/examples/01_simple_type_checking/03_control_flow.py b/examples/01_simple_type_checking/03_control_flow.py index 772c9ac..f0ba59b 100644 --- a/examples/01_simple_type_checking/03_control_flow.py +++ b/examples/01_simple_type_checking/03_control_flow.py @@ -1,3 +1,5 @@ +# Return types must have a LUB +# Valid def minimum(x: int, y: int): if x < y: return x @@ -5,18 +7,28 @@ def minimum(x: int, y: int): return y +# Invalid +def func(a: int): + if a < 5: + return "Oops" + return True + + a = 15 b = 72 c = minimum(a, b) +# Recursive but typable thanks to return hint def factorial(n: int) -> int: if n <= 1: return 1 return n * factorial(n - 1) -category = "Category 1" if a < 10 else "Category 2" +# Branches must be of the same type +category = "Category 1" if a < 10 else "Category 2" # Valid +category = "Category 1" if a < 10 else 3 # Invalid def foo() -> None: diff --git a/examples/01_simple_type_checking/04_complex_types.midas b/examples/01_simple_type_checking/04_complex_types.midas index adc76b3..fb1c255 100644 --- a/examples/01_simple_type_checking/04_complex_types.midas +++ b/examples/01_simple_type_checking/04_complex_types.midas @@ -15,7 +15,9 @@ extend Coordinate { type Difference[T <: float] = T type MeterDifference = Difference[Meter] -type CompDiff[T <: float] = { +type CompDiff[T <: float] = object + +extend CompDiff[T <: float] { prop d1: Difference[T] prop d2: Difference[T] } \ No newline at end of file diff --git a/examples/01_simple_type_checking/04_complex_types.py b/examples/01_simple_type_checking/04_complex_types.py index f1d1215..1ee0873 100644 --- a/examples/01_simple_type_checking/04_complex_types.py +++ b/examples/01_simple_type_checking/04_complex_types.py @@ -1,20 +1,20 @@ # type: ignore # ruff: disable [F821] -p1: Coordinate -p2: Coordinate +p1 = cast(Coordinate, object()) +p2 = cast(Coordinate, object()) diff_x = p2.x - p1.x diff_y = p2.y - p1.y dist = diff_x + diff_y -p2.x += cast(Meter, 1) +p2.x += cast(Meter, 1.0) p2.y = True # invalid, wrong type p2.z = 3 # invalid, no property 'z' on Coordinate p2.x.a = 3 # invalid, no properties on Meter -foo: list[float] = [] +foo = cast(list[float], []) append = foo.append @@ -23,7 +23,7 @@ foo.append(2) append(True) # invalid, must be float append(2) -bar: list[list[Meter]] +bar = cast(list[list[Meter]], []) bar.append([p2.x]) diff --git a/examples/01_simple_type_checking/06_overloads.py b/examples/01_simple_type_checking/06_overloads.py index 86406e0..1a9427a 100644 --- a/examples/01_simple_type_checking/06_overloads.py +++ b/examples/01_simple_type_checking/06_overloads.py @@ -1,9 +1,9 @@ # type: ignore # ruff: disable [F821] -foo: Foo -t1: T1 -t2: T2 +foo = cast(Foo, object()) +t1 = cast(T1, object()) +t2 = cast(T2, object()) a = foo.bar(t1) b = foo.bar(t2) @@ -13,6 +13,6 @@ func = foo.bar c = func(t1) d = func(t2) -t2b: T2b +t2b = cast(T2b, object()) e = foo.bar(t2b) diff --git a/tests/cases/midas-parser/01_simple_types.midas b/tests/cases/midas-parser/01_simple_types.midas index 3b982e1..7b0336c 100644 --- a/tests/cases/midas-parser/01_simple_types.midas +++ b/tests/cases/midas-parser/01_simple_types.midas @@ -2,8 +2,8 @@ type Custom = float // Simple custom types with constraints -type Latitude = float where (-90 <= _ <= 90) -type Longitude = float where (-180 <= _ <= 180) +type Latitude = float where (-90 <= _ & _ <= 90) +type Longitude = float where (-180 <= _ & _ <= 180) // Generic custom type (a Difference of T is derived from T, e.g. a difference of floats is a float type Difference[T] = T @@ -54,10 +54,10 @@ extend Person { prop name: str // Property with an inline constraint - prop age: Optional[int where (0 <= _ < 150)] + prop age: int where (0 <= _ & _ < 150) // Property referencing a predicate - prop height: float where StrictlyPositive + prop height: float where StrictlyPositive(_) prop home: GeoLocation } diff --git a/tests/cases/midas-parser/01_simple_types.midas.ref.json b/tests/cases/midas-parser/01_simple_types.midas.ref.json index 62936de..f764a4b 100644 --- a/tests/cases/midas-parser/01_simple_types.midas.ref.json +++ b/tests/cases/midas-parser/01_simple_types.midas.ref.json @@ -187,8 +187,8 @@ "column": 38 }, { - "type": "LESS_EQUAL", - "lexeme": "<=", + "type": "AND", + "lexeme": "&", "line": 5, "column": 39 }, @@ -196,25 +196,49 @@ "type": "WHITESPACE", "lexeme": " ", "line": 5, + "column": 40 + }, + { + "type": "UNDERSCORE", + "lexeme": "_", + "line": 5, "column": 41 }, + { + "type": "WHITESPACE", + "lexeme": " ", + "line": 5, + "column": 42 + }, + { + "type": "LESS_EQUAL", + "lexeme": "<=", + "line": 5, + "column": 43 + }, + { + "type": "WHITESPACE", + "lexeme": " ", + "line": 5, + "column": 45 + }, { "type": "NUMBER", "lexeme": "90", "line": 5, - "column": 42 + "column": 46 }, { "type": "RIGHT_PAREN", "lexeme": ")", "line": 5, - "column": 44 + "column": 48 }, { "type": "NEWLINE", "lexeme": "\n", "line": 5, - "column": 45 + "column": 49 }, { "type": "TYPE", @@ -325,8 +349,8 @@ "column": 40 }, { - "type": "LESS_EQUAL", - "lexeme": "<=", + "type": "AND", + "lexeme": "&", "line": 6, "column": 41 }, @@ -334,25 +358,49 @@ "type": "WHITESPACE", "lexeme": " ", "line": 6, + "column": 42 + }, + { + "type": "UNDERSCORE", + "lexeme": "_", + "line": 6, "column": 43 }, + { + "type": "WHITESPACE", + "lexeme": " ", + "line": 6, + "column": 44 + }, + { + "type": "LESS_EQUAL", + "lexeme": "<=", + "line": 6, + "column": 45 + }, + { + "type": "WHITESPACE", + "lexeme": " ", + "line": 6, + "column": 47 + }, { "type": "NUMBER", "lexeme": "180", "line": 6, - "column": 44 + "column": 48 }, { "type": "RIGHT_PAREN", "lexeme": ")", "line": 6, - "column": 47 + "column": 51 }, { "type": "NEWLINE", "lexeme": "\n", "line": 6, - "column": 48 + "column": 52 }, { "type": "NEWLINE", @@ -2240,22 +2288,40 @@ }, { "type": "IDENTIFIER", - "lexeme": "Optional", + "lexeme": "int", "line": 57, "column": 15 }, { - "type": "LEFT_BRACKET", - "lexeme": "[", + "type": "WHITESPACE", + "lexeme": " ", "line": 57, - "column": 23 + "column": 18 }, { - "type": "IDENTIFIER", - "lexeme": "int", + "type": "WHERE", + "lexeme": "where", + "line": 57, + "column": 19 + }, + { + "type": "WHITESPACE", + "lexeme": " ", "line": 57, "column": 24 }, + { + "type": "LEFT_PAREN", + "lexeme": "(", + "line": 57, + "column": 25 + }, + { + "type": "NUMBER", + "lexeme": "0", + "line": 57, + "column": 26 + }, { "type": "WHITESPACE", "lexeme": " ", @@ -2263,8 +2329,8 @@ "column": 27 }, { - "type": "WHERE", - "lexeme": "where", + "type": "LESS_EQUAL", + "lexeme": "<=", "line": 57, "column": 28 }, @@ -2272,17 +2338,35 @@ "type": "WHITESPACE", "lexeme": " ", "line": 57, + "column": 30 + }, + { + "type": "UNDERSCORE", + "lexeme": "_", + "line": 57, + "column": 31 + }, + { + "type": "WHITESPACE", + "lexeme": " ", + "line": 57, + "column": 32 + }, + { + "type": "AND", + "lexeme": "&", + "line": 57, "column": 33 }, { - "type": "LEFT_PAREN", - "lexeme": "(", + "type": "WHITESPACE", + "lexeme": " ", "line": 57, "column": 34 }, { - "type": "NUMBER", - "lexeme": "0", + "type": "UNDERSCORE", + "lexeme": "_", "line": 57, "column": 35 }, @@ -2293,8 +2377,8 @@ "column": 36 }, { - "type": "LESS_EQUAL", - "lexeme": "<=", + "type": "LESS", + "lexeme": "<", "line": 57, "column": 37 }, @@ -2302,55 +2386,25 @@ "type": "WHITESPACE", "lexeme": " ", "line": 57, - "column": 39 - }, - { - "type": "UNDERSCORE", - "lexeme": "_", - "line": 57, - "column": 40 - }, - { - "type": "WHITESPACE", - "lexeme": " ", - "line": 57, - "column": 41 - }, - { - "type": "LESS", - "lexeme": "<", - "line": 57, - "column": 42 - }, - { - "type": "WHITESPACE", - "lexeme": " ", - "line": 57, - "column": 43 + "column": 38 }, { "type": "NUMBER", "lexeme": "150", "line": 57, - "column": 44 + "column": 39 }, { "type": "RIGHT_PAREN", "lexeme": ")", "line": 57, - "column": 47 - }, - { - "type": "RIGHT_BRACKET", - "lexeme": "]", - "line": 57, - "column": 48 + "column": 42 }, { "type": "NEWLINE", "lexeme": "\n", "line": 57, - "column": 49 + "column": 43 }, { "type": "NEWLINE", @@ -2442,11 +2496,29 @@ "line": 60, "column": 30 }, + { + "type": "LEFT_PAREN", + "lexeme": "(", + "line": 60, + "column": 46 + }, + { + "type": "UNDERSCORE", + "lexeme": "_", + "line": 60, + "column": 47 + }, + { + "type": "RIGHT_PAREN", + "lexeme": ")", + "line": 60, + "column": 48 + }, { "type": "NEWLINE", "lexeme": "\n", "line": 60, - "column": 46 + "column": 49 }, { "type": "NEWLINE", @@ -2544,7 +2616,7 @@ "constraint": { "_type": "GroupingExpr", "expr": { - "_type": "BinaryExpr", + "_type": "LogicalExpr", "left": { "_type": "BinaryExpr", "left": { @@ -2560,10 +2632,17 @@ "_type": "WildcardExpr" } }, - "operator": "<=", + "operator": "&", "right": { - "_type": "LiteralExpr", - "value": 90 + "_type": "BinaryExpr", + "left": { + "_type": "WildcardExpr" + }, + "operator": "<=", + "right": { + "_type": "LiteralExpr", + "value": 90 + } } } } @@ -2582,7 +2661,7 @@ "constraint": { "_type": "GroupingExpr", "expr": { - "_type": "BinaryExpr", + "_type": "LogicalExpr", "left": { "_type": "BinaryExpr", "left": { @@ -2598,10 +2677,17 @@ "_type": "WildcardExpr" } }, - "operator": "<=", + "operator": "&", "right": { - "_type": "LiteralExpr", - "value": 180 + "_type": "BinaryExpr", + "left": { + "_type": "WildcardExpr" + }, + "operator": "<=", + "right": { + "_type": "LiteralExpr", + "value": 180 + } } } } @@ -3013,42 +3099,40 @@ "kind": "PROPERTY", "name": "age", "type": { - "_type": "GenericType", + "_type": "ConstraintType", "type": { "_type": "NamedType", - "name": "Optional" + "name": "int" }, - "args": [ - { - "_type": "ConstraintType", - "type": { - "_type": "NamedType", - "name": "int" + "constraint": { + "_type": "GroupingExpr", + "expr": { + "_type": "LogicalExpr", + "left": { + "_type": "BinaryExpr", + "left": { + "_type": "LiteralExpr", + "value": 0 + }, + "operator": "<=", + "right": { + "_type": "WildcardExpr" + } }, - "constraint": { - "_type": "GroupingExpr", - "expr": { - "_type": "BinaryExpr", - "left": { - "_type": "BinaryExpr", - "left": { - "_type": "LiteralExpr", - "value": 0 - }, - "operator": "<=", - "right": { - "_type": "WildcardExpr" - } - }, - "operator": "<", - "right": { - "_type": "LiteralExpr", - "value": 150 - } + "operator": "&", + "right": { + "_type": "BinaryExpr", + "left": { + "_type": "WildcardExpr" + }, + "operator": "<", + "right": { + "_type": "LiteralExpr", + "value": 150 } } } - ] + } } }, { @@ -3062,8 +3146,17 @@ "name": "float" }, "constraint": { - "_type": "VariableExpr", - "name": "StrictlyPositive" + "_type": "CallExpr", + "callee": { + "_type": "VariableExpr", + "name": "StrictlyPositive" + }, + "arguments": [ + { + "_type": "WildcardExpr" + } + ], + "keywords": {} } } }, From 9f3dfd686ba8eefb3075cc9d34c7b236cefb0d4e Mon Sep 17 00:00:00 2001 From: LordBaryhobal Date: Thu, 9 Jul 2026 23:14:37 +0200 Subject: [PATCH 2/7] chore: remove syntax prototype examples --- .../00_syntax_prototype/01_simple_types.py | 15 ----- .../00_syntax_prototype/02_custom_types.midas | 63 ------------------- .../00_syntax_prototype/02_custom_types.py | 20 ------ examples/00_syntax_prototype/04_functions.py | 15 ----- .../05_custom_types_v3.midas | 33 ---------- 5 files changed, 146 deletions(-) delete mode 100644 examples/00_syntax_prototype/01_simple_types.py delete mode 100644 examples/00_syntax_prototype/02_custom_types.midas delete mode 100644 examples/00_syntax_prototype/02_custom_types.py delete mode 100644 examples/00_syntax_prototype/04_functions.py delete mode 100644 examples/00_syntax_prototype/05_custom_types_v3.midas diff --git a/examples/00_syntax_prototype/01_simple_types.py b/examples/00_syntax_prototype/01_simple_types.py deleted file mode 100644 index c974415..0000000 --- a/examples/00_syntax_prototype/01_simple_types.py +++ /dev/null @@ -1,15 +0,0 @@ -# type: ignore -# ruff: disable[F821] -from __future__ import annotations - -# A simple data-frame with different column of various simple types -# Columns can be named and/or typed -df: Frame[ - verified: bool, - birth_year: int, - height: float, - name: str, - date: object, - float, # unnamed - unknown: _, # untyped -] diff --git a/examples/00_syntax_prototype/02_custom_types.midas b/examples/00_syntax_prototype/02_custom_types.midas deleted file mode 100644 index 7b0336c..0000000 --- a/examples/00_syntax_prototype/02_custom_types.midas +++ /dev/null @@ -1,63 +0,0 @@ -// Simple custom type derived from float -type Custom = float - -// Simple custom types with constraints -type Latitude = float where (-90 <= _ & _ <= 90) -type Longitude = float where (-180 <= _ & _ <= 180) - -// Generic custom type (a Difference of T is derived from T, e.g. a difference of floats is a float -type Difference[T] = T - -// Complex custom type, containing two values accessible through properties -type GeoLocation = object - -extend GeoLocation { - prop lat: Latitude - prop lon: Longitude -} - -type GeoLocationDifference = object - -extend GeoLocationDifference { - prop lat: Difference[Latitude] - prop lon: Difference[Longitude] -} - -// Define operations on our custom type - -// Simple operation defined on our custom types -extend Latitude { - def __sub__: fn(Latitude, /) -> Difference[Latitude] -} - -extend Longitude { - def __sub__: fn(Longitude, /) -> Difference[Longitude] -} - -extend GeoLocation { - // This type is compatible with the `-` operation with another GeoLocation - // i.e. you can subtract a GeoLocation from another GeoLocation, resulting - // in a GeoLocationDifference - def __sub__: fn(GeoLocation, /) -> GeoLocationDifference -} - - -// Predefined custom predicates that can be referenced in other definitions -predicate Positive(v: float) = v >= 0 -predicate StrictlyPositive(v: float) = v > 0 -predicate Equatorial(loc: GeoLocation) = (-10 <= loc.lat <= 10) -predicate Arctic(loc: GeoLocation) = (loc.lat >= 66) - -type Person = object - -extend Person { - prop name: str - - // Property with an inline constraint - prop age: int where (0 <= _ & _ < 150) - - // Property referencing a predicate - prop height: float where StrictlyPositive(_) - - prop home: GeoLocation -} diff --git a/examples/00_syntax_prototype/02_custom_types.py b/examples/00_syntax_prototype/02_custom_types.py deleted file mode 100644 index e78d458..0000000 --- a/examples/00_syntax_prototype/02_custom_types.py +++ /dev/null @@ -1,20 +0,0 @@ -# type: ignore -# ruff: disable[F821] -from __future__ import annotations - -# A data-frame using a custom type -df: Frame[ - location: GeoLocation -] - -# Properties of a type can be used on a column of that type -lat: Column[Latitude] = ... -lon: Column[Longitude] = ... - -# Unregistered operations between types are not permitted -lat + lon # Invalid operation - -# Registered operations are permitted -lat1: Latitude = lat[0] -lat2: Latitude = lat[1] -lat_diff: Difference[Latitude] = lat2 - lat1 # Valid operation diff --git a/examples/00_syntax_prototype/04_functions.py b/examples/00_syntax_prototype/04_functions.py deleted file mode 100644 index 3b07899..0000000 --- a/examples/00_syntax_prototype/04_functions.py +++ /dev/null @@ -1,15 +0,0 @@ -# type: ignore -# ruff: disable[F821] -from __future__ import annotations - - -def func( - col1: Column[float + (0 <= _ <= 1)], - col2: Column[float + (0 <= _ <= 1)], -) -> Column[float + (0 <= _ <= 2)]: - result: Column[float + (0 <= _ <= 2)] = col1 + col2 - return result - - -def func2(a: int, /, b: float, *, c: str): - pass diff --git a/examples/00_syntax_prototype/05_custom_types_v3.midas b/examples/00_syntax_prototype/05_custom_types_v3.midas deleted file mode 100644 index a339318..0000000 --- a/examples/00_syntax_prototype/05_custom_types_v3.midas +++ /dev/null @@ -1,33 +0,0 @@ -type Foo1 = float -type Foo2 = float where (_ > 3) -type Foo3 = int | float -type Foo4 = int where (_ > 3) | float where (_ > 3) -type Foo5 = (int | float) where (_ > 3) -type Foo6 = { - foo: float - bar: float where (_ > 3) -} - -type Foo7[T] = T where (_ > 3) -type Foo8[A, B<:int] = { - a: A - b: B -} - -type Complex = { - a: int - b: int -} -type Complex2 = Complex where (_.a > 3 & _.b < 5) - -predicate Positive(n: int) = n >= 0 - -extend Foo1 { - op __add__(Foo1) -> Foo1 -} - -extend Foo7[T] { - op __add__(Foo7[T]) -> Foo7[T] -} - -type Optional[T] = None | T From dade8eb0f486bd4960d1edb91667cfa982e798c9 Mon Sep 17 00:00:00 2001 From: LordBaryhobal Date: Thu, 9 Jul 2026 23:20:49 +0200 Subject: [PATCH 3/7] chore: move currency demo in subfolder --- .../02_demonstration/{ => currency}/demo.midas | 0 examples/02_demonstration/{ => currency}/demo.py | 0 examples/02_demonstration/demo_stubs.pyi | 14 -------------- 3 files changed, 14 deletions(-) rename examples/02_demonstration/{ => currency}/demo.midas (100%) rename examples/02_demonstration/{ => currency}/demo.py (100%) delete mode 100644 examples/02_demonstration/demo_stubs.pyi diff --git a/examples/02_demonstration/demo.midas b/examples/02_demonstration/currency/demo.midas similarity index 100% rename from examples/02_demonstration/demo.midas rename to examples/02_demonstration/currency/demo.midas diff --git a/examples/02_demonstration/demo.py b/examples/02_demonstration/currency/demo.py similarity index 100% rename from examples/02_demonstration/demo.py rename to examples/02_demonstration/currency/demo.py diff --git a/examples/02_demonstration/demo_stubs.pyi b/examples/02_demonstration/demo_stubs.pyi deleted file mode 100644 index 6615018..0000000 --- a/examples/02_demonstration/demo_stubs.pyi +++ /dev/null @@ -1,14 +0,0 @@ -from __future__ import annotations -from typing import Generic, TypeVar - -class Currency(float): ... - -_T0 = TypeVar("_T0", bound=Currency, covariant=True) - -class Price(Currency, Generic[_T0]): - def __add__(self, _0: Price[_T0], /) -> Price[_T0]: ... - -class EUR(Currency): ... -class USD(Currency): ... -class CHF(Currency): ... -class Discount(float): ... From edc2a654927823b3e629d46cd2ff5ef3a33dce96 Mon Sep 17 00:00:00 2001 From: LordBaryhobal Date: Thu, 9 Jul 2026 23:24:52 +0200 Subject: [PATCH 4/7] chore: remove test file --- test.py | 33 --------------------------------- 1 file changed, 33 deletions(-) delete mode 100644 test.py diff --git a/test.py b/test.py deleted file mode 100644 index 522bbac..0000000 --- a/test.py +++ /dev/null @@ -1,33 +0,0 @@ -import json -from pathlib import Path - -from midas.ast.printer import MidasAstPrinter -from midas.lexer.midas import MidasLexer -from midas.lexer.token import Token -from midas.parser.midas import MidasParser - - -def test_midas(): - # Midas type definitions - path: Path = Path("examples") / "00_syntax_prototype" / "03_custom_types_v2.midas" - definitions: str = path.read_text() - midas_lexer: MidasLexer = MidasLexer(definitions, path.name) - tokens: list[Token] = midas_lexer.process() - # print([f"{t.type.name}('{t.lexeme}')" for t in tokens]) - with open("tokens.json", "w") as f: - json.dump([f"{t.type.name}('{t.lexeme}')" for t in tokens], f, indent=4) - - parser = MidasParser(tokens) - parsed = parser.parse() - print(parsed) - for err in parser.errors: - print(err.get_report()) - printer = MidasAstPrinter() - for stmt in parsed: - if stmt is None: - print("None") - continue - print(printer.print(stmt)) - - -test_midas() From b64110bb06ea6f373f383fc7f8535af61cd98d8e Mon Sep 17 00:00:00 2001 From: LordBaryhobal Date: Thu, 9 Jul 2026 23:36:50 +0200 Subject: [PATCH 5/7] chore: remove draft architecture diagram --- docs/architecture.typ | 150 ------------------------------------------ 1 file changed, 150 deletions(-) delete mode 100644 docs/architecture.typ diff --git a/docs/architecture.typ b/docs/architecture.typ deleted file mode 100644 index d83bdc6..0000000 --- a/docs/architecture.typ +++ /dev/null @@ -1,150 +0,0 @@ -#import "@preview/cetz:0.5.2": canvas, draw - -#let diagram-only = false - -#set document( - title: [Midas Architecture], - //author: "Louis Heredero", -) - -#set text( - font: "Source Sans 3", -) - -#let diagram = canvas({ - let framed = draw.content.with( - padding: (x: .8em, y: 1em), - frame: "rect", - stroke: black, - ) - let arrow = draw.line.with(mark: (end: ">", fill: black)) - framed( - (0, 0), - name: "python-parser", - )[Python parser] - - draw.content( - (rel: (0, 1), to: "python-parser.north"), - padding: 5pt, - anchor: "south", - name: "source-py", - )[_`source.py`_] - arrow("source-py", "python-parser") - - framed( - (rel: (3, 0), to: "python-parser.east"), - anchor: "west", - name: "custom-parser", - align(center)[Custom python\ parser], - ) - - arrow("python-parser", "custom-parser", name: "arrow-python-ast") - draw.content( - "arrow-python-ast", - anchor: "south", - padding: 5pt, - )[`ast.Module`] - - framed( - (rel: (-3, -2), to: "custom-parser.south"), - anchor: "east", - name: "python-resolver", - )[Python Resolver] - arrow( - "custom-parser", - ((), "|-", "python-resolver.east"), - "python-resolver", - name: "arrow-python-custom-ast", - ) - draw.content( - (rel: (1.5, 0), to: "arrow-python-custom-ast.end"), - padding: 5pt, - anchor: "south", - )[P-AST#footnote[#strong[P]ython *AST*]] - draw.content( - "python-resolver.west", - padding: 5pt, - anchor: "south-east", - )[Resolved P-AST@fn-past] - - draw.circle( - (rel: (1, -2), to: "custom-parser.south-east"), - radius: .4, - name: "midas-loader", - ) - arrow( - "custom-parser", - "midas-loader", - name: "arrow-load-midas", - mark: (end: (symbol: ">", fill: black), start: "o"), - ) - draw.content( - "arrow-load-midas", - anchor: "west", - padding: 5pt, - )[```python midas.using("types.midas")```] - - framed( - (rel: (0, -2), to: "midas-loader.south"), - name: "midas-parser", - )[Midas lexer/parser] - arrow("midas-loader", "midas-parser", name: "arrow-midas-source") - draw.content( - "arrow-midas-source", - anchor: "west", - padding: 5pt, - )[_`types.midas`_] - - - framed( - (rel: (-2, 0), to: "midas-parser.west"), - anchor: "east", - name: "midas-resolver", - )[Midas Resolver] - arrow("midas-parser", "midas-resolver", name: "arrow-midas-ast") - draw.content( - "arrow-midas-ast", - anchor: "south", - padding: 5pt, - )[M-AST#footnote[#strong[M]idas *AST*]] - - framed( - (rel: (-3, 0), to: "midas-resolver.west"), - anchor: "east", - name: "checker", - )[Checker] - arrow("midas-resolver", "checker", name: "arrow-type-ctx") - arrow( - "python-resolver", - ((), "-|", "checker.north"), - "checker", - ) - draw.content( - "arrow-type-ctx", - anchor: "south", - padding: 5pt, - )[Types context] -}) - -#show: doc => if diagram-only { - set page(width: auto, height: auto, margin: .5cm) - diagram -} else { doc } - -#align(center, title()) - -#v(1cm) - -#figure( - diagram, - caption: [Midas type-checker architecture], -) - -== Components - -- *Python parser*: builtin Python AST parser, extracts abstract syntax from the raw Python source (```python ast.parse(...)```) -- *Custom python parser*: converts the raw Python AST into custom, more suitable constructs, especially for type annotations -- *Python resolver*: resolves bindings and references, tracks binding scopes -- *Midas lexer/parser*: parses a Midas type definition file and extracts its AST -- *Midas resolver*: walks the AST and fills the environment with the defined types and operations -- *Checker*: evaluates expressions and checks type coherence From 28be45eb8f8d002df5fa1354b175665073d26f5c Mon Sep 17 00:00:00 2001 From: LordBaryhobal Date: Thu, 9 Jul 2026 23:37:08 +0200 Subject: [PATCH 6/7] chore: add CI badge --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index da1460c..0af334b 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@

Midas

+ + *Midas* is a type system to _Maintain Integrity of Data with Annotated Structures_. In Greek mythology, [Midas](https://en.wikipedia.org/wiki/Midas) was a Phrygian king who was blessed with the gift of turning everything he touched into gold. *Midas* aims at providing Python developers with a simple annotation system to enable compile-time integrity and data type checks, as well as generating runtime assertions. From dce35391b477a1671dc653744e07216499d0a5a7 Mon Sep 17 00:00:00 2001 From: LordBaryhobal Date: Thu, 9 Jul 2026 23:37:22 +0200 Subject: [PATCH 7/7] chore: add justfile --- justfile | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 justfile diff --git a/justfile b/justfile new file mode 100644 index 0000000..f69655d --- /dev/null +++ b/justfile @@ -0,0 +1,14 @@ +# Local Variables: +# mode: makefile +# End: +set shell := ["bash", "-uc"] + +build-docs: + typst c --root . docs/manual.typ + typst c --root . docs/function_subtyping.typ + +tests: + uv run -m tests + +check-docstrings: + uv run scripts/docstring_checker.py