From 5c66c4b6455220719cbf346b621f58fb463bc80f Mon Sep 17 00:00:00 2001 From: LordBaryhobal Date: Wed, 8 Jul 2026 13:32:32 +0200 Subject: [PATCH 1/5] docs: update syntax railroad diagrams --- syntax/midas.typ | 93 +++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 76 insertions(+), 17 deletions(-) diff --git a/syntax/midas.typ b/syntax/midas.typ index b0b6438..b05c2a5 100644 --- a/syntax/midas.typ +++ b/syntax/midas.typ @@ -27,20 +27,40 @@ svg.railroad .terminal rect { {[`reference` 'primary' ]} ``` +#let call-args = ``` +{[`call-args` "(" *","#`Same rules as Python`> ")"]} +``` + +#let call = ``` +{[`call` 'reference' ]} +``` + #let unary = ``` -{[`unary` <[ 'unary'], 'reference'>]} +{[`unary` <[<"+", "-", "!"> 'unary'], 'call'>]} +``` + +#let factor = ``` +{[`factor` 'unary'*<"*", "/">]} +``` + +#let term = ``` +{[`term` 'factor'*<"+", "-">]} ``` #let comparison = ``` -{[`comparison` 'unary'*<">", "<", ">=", "<=">]} +{[`comparison` 'term'*<">", "<", ">=", "<=">]} ``` #let equality = ``` {[`equality` 'comparison'*<"==", "!=">]} ``` +#let expression = ``` +{[`expression` 'equality'*"&"]} +``` + #let constraint = ``` -{[`constraint` 'equality'*"&"]} +{[`constraint` 'expression']} ``` #let template-param = ``` @@ -63,12 +83,16 @@ svg.railroad .terminal rect { {[`named-type` 'identifier']} ``` -#let type-params = ``` -{[`type-params` "[" "]"]} +#let type-args = ``` +{[`type-args` "[" "]"]} +``` + +#let frame-schema = ``` +{[`frame-schema` "[" "]"]} ``` #let generic-type = ``` -{[`generic-type` 'named-type' ]} +{[`generic-type` <["Frame" 'frame-schema'], ['named-type' ]>]} ``` #let grouped-type = ``` @@ -83,28 +107,48 @@ svg.railroad .terminal rect { {[`constraint-type` 'base-type' ]} ``` +#let pos-param = ``` +{[`pos-param` 'type' ]} +``` + +#let kw-param = ``` +{[`kw-param` 'identifier' ":" 'type' ]} +``` + +#let param-spec = ``` +{[`param-spec` "(" *",">#`Same rules as Python` ")"]} +``` + +#let func-type = ``` +{[`func-type` "fn" 'param-spec' "->" 'type']} +``` + #let type = ``` -{[`type` 'constraint-type']} +{[`type` <'func-type', 'constraint-type'>]} +``` + +#let alias-statement = ``` +{[`alias-statement` "alias" 'identifier' "=" 'type']} ``` #let type-statement = ``` {[`type-statement` "type" 'identifier' "=" 'type']} ``` -#let op-definition = ``` -{[`op-definition` "op" 'identifier' "(" 'type' ")" "->" 'type']} +#let member-stmt = ``` +{[`member-stmt` <"prop", "def"> 'identifier' ":" 'type']} ``` #let extend-statement = ``` -{[`extend-statement` "extend" 'type' "{" "}"]} +{[`extend-statement` "extend" 'type' "{" "}"]} ``` #let predicate-statement = ``` -{[`predicate-statement` "predicate" 'identifier' "(" 'identifier' ":" 'type' ")" "=" 'constraint']} +{[`predicate-statement` "predicate" 'identifier' "=" 'constraint']} ``` #let statement = ``` -{[`statement` <'type-statement', 'extend-statement', 'predicate-statement'>]} +{[`statement` <'alias-statement', 'type-statement', 'extend-statement', 'predicate-statement'>]} ``` #let rules = ( @@ -112,23 +156,33 @@ svg.railroad .terminal rect { grouping: grouping, primary: primary, reference: reference, + call-args: call-args, + call: call, unary: unary, + factor: factor, + term: term, comparison: comparison, equality: equality, + expression: expression, constraint: constraint, template-param: template-param, template: template, type-property: type-property, complex-type: complex-type, named-type: named-type, - type-params: type-params, + type-args: type-args, generic-type: generic-type, grouped-type: grouped-type, base-type: base-type, constraint-type: constraint-type, + pos-param: pos-param, + kw-param: kw-param, + param-spec: param-spec, + func-type: func-type, type: type, + alias-statement: alias-statement, type-statement: type-statement, - op-definition: op-definition, + member-stmt: member-stmt, extend-statement: extend-statement, predicate-statement: predicate-statement, statement: statement, @@ -140,14 +194,19 @@ svg.railroad .terminal rect { "template-param", "template", "type-property", + "call-args", "complex-type", - "type-params", + "type-args", "named-type", "grouped-type", "generic-type", "base-type", "constraint-type", - "op-definition", + "pos-param", + "kw-param", + "func-type", + "member-stmt", + "alias-statement", "type-statement", "extend-statement", "predicate-statement", @@ -164,7 +223,7 @@ svg.railroad .terminal rect { 2, outline(title: none), ), - height: 9cm, + height: 15cm, stroke: 1pt, inset: 1em, ) From 4f9099a4c40a31d70560a332b215c91398decc0f Mon Sep 17 00:00:00 2001 From: LordBaryhobal Date: Wed, 8 Jul 2026 13:41:47 +0200 Subject: [PATCH 2/5] chore: update VSCode syntax definition the TextMate language definition was completely rewritten by Claude from my Sublime Syntax definition some tests against Midas files show that it seems on par with the other definition Co-authored-by: Claude --- vscode-ext/language-configurations.json | 9 +- vscode-ext/package.json | 6 +- vscode-ext/syntaxes/midas.tmLanguage.json | 649 +++++++++++++++++----- 3 files changed, 524 insertions(+), 140 deletions(-) diff --git a/vscode-ext/language-configurations.json b/vscode-ext/language-configurations.json index ffd5219..6695a6f 100644 --- a/vscode-ext/language-configurations.json +++ b/vscode-ext/language-configurations.json @@ -1,19 +1,16 @@ { "brackets": [ ["{", "}"], - ["[", "]"], - ["<", ">"] + ["[", "]"] ], "autoClosingPairs": [ { "open": "{", "close": "}" }, { "open": "[", "close": "]" }, - { "open": "(", "close": ")" }, - { "open": "<", "close": ">" } + { "open": "(", "close": ")" } ], "surroundingPairs": [ ["{", "}"], ["[", "]"], - ["(", ")"], - ["<", ">"] + ["(", ")"] ] } \ No newline at end of file diff --git a/vscode-ext/package.json b/vscode-ext/package.json index bd2c40b..ab4f957 100644 --- a/vscode-ext/package.json +++ b/vscode-ext/package.json @@ -10,7 +10,6 @@ { "id": "midas", "extensions": [ - ".mpy", ".midas" ], "aliases": [ @@ -23,10 +22,7 @@ { "language": "midas", "scopeName": "source.midas", - "path": "./syntaxes/midas.tmLanguage.json", - "embeddedLanguages": { - "meta.embedded.block.python": "python" - } + "path": "./syntaxes/midas.tmLanguage.json" } ] } diff --git a/vscode-ext/syntaxes/midas.tmLanguage.json b/vscode-ext/syntaxes/midas.tmLanguage.json index 20d1ded..edf541d 100644 --- a/vscode-ext/syntaxes/midas.tmLanguage.json +++ b/vscode-ext/syntaxes/midas.tmLanguage.json @@ -2,167 +2,558 @@ "$schema": "https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json", "name": "Midas", "scopeName": "source.midas", - "patterns": [{ "include": "#statement" }], + "fileTypes": [ + "midas" + ], + "patterns": [ + { + "include": "#comments" + }, + { + "include": "#alias-stmt" + }, + { + "include": "#type-stmt" + }, + { + "include": "#extend-stmt" + }, + { + "include": "#extend-body" + }, + { + "include": "#predicate-stmt" + } + ], "repository": { - "comment": { - "begin": "(//)", - "end": "($)", - "name": "comment.line", - "beginCaptures": { - "1": { - "name": "comment.line.double-dash" - } - } - }, - "type-def": { - "begin": "\\b(type)\\s+([a-zA-Z_][a-zA-Z_\\d]*)", - "end": "$", - "beginCaptures": { - "1": { - "name": "keyword.control.type.midas" - }, - "2": { - "name" : "variable.name" - } - }, + "comments": { "patterns": [ - { "include": "#type-base" }, - { "include": "#type-body" } + { + "begin": "//", + "beginCaptures": { + "0": { + "name": "punctuation.definition.comment.midas" + } + }, + "end": "$", + "name": "comment.line.double-slash.midas" + }, + { + "begin": "/\\*", + "beginCaptures": { + "0": { + "name": "punctuation.definition.comment.midas" + } + }, + "end": "\\*/", + "endCaptures": { + "0": { + "name": "punctuation.definition.comment.midas" + } + }, + "name": "comment.block.midas" + } ] }, - "type-base": { - "begin": "(\\()([a-zA-Z_][a-zA-Z_\\d]*)(\\))", - "end": "$", - "beginCaptures": { - "1": { - "name": "punctuation.definition.base.begin.midas" - }, - "2": { - "name": "variable.name" - }, - "3": { - "name": "punctuation.definition.base.end.midas" - } - }, - "patterns": [ - { "include": "#type-cond" } - ] - }, - "type-cond": { - "begin": "where", - "end": "$", + "string": { + "begin": "\"", "beginCaptures": { "0": { - "name": "keyword.control.where.midas" + "name": "punctuation.definition.string.begin.midas" } - } + }, + "end": "\"", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.midas" + } + }, + "name": "string.quoted.double.c" }, - "type-body": { + "alias-stmt": { + "begin": "\\b(alias)\\b", + "beginCaptures": { + "1": { + "name": "keyword.declaration.midas" + } + }, + "end": "$", + "name": "meta.declaration.alias.midas", + "patterns": [ + { + "include": "#comments" + }, + { + "match": "[A-Za-z_][A-Za-z0-9_]*", + "name": "entity.name.type.midas" + }, + { + "begin": "=", + "beginCaptures": { + "0": { + "name": "keyword.operator.equal.midas" + } + }, + "end": "$", + "patterns": [ + { + "include": "#type-expr" + } + ] + } + ] + }, + "type-stmt": { + "begin": "\\b(type)\\b", + "beginCaptures": { + "1": { + "name": "keyword.declaration.midas" + } + }, + "end": "$", + "name": "meta.declaration.type.midas", + "patterns": [ + { + "include": "#comments" + }, + { + "match": "[A-Za-z_][A-Za-z0-9_]*", + "name": "entity.name.type.midas" + }, + { + "begin": "\\[", + "beginCaptures": { + "0": { + "name": "punctuation.section.brackets.begin.midas" + } + }, + "end": "\\]", + "endCaptures": { + "0": { + "name": "punctuation.section.brackets.end.midas" + } + }, + "patterns": [ + { + "include": "#comments" + }, + { + "include": "#type-params" + } + ] + }, + { + "begin": "=", + "beginCaptures": { + "0": { + "name": "keyword.operator.equal.midas" + } + }, + "end": "$", + "patterns": [ + { + "include": "#type-expr" + } + ] + } + ] + }, + "type-params": { + "patterns": [ + { + "include": "#comments" + }, + { + "match": "<:", + "name": "keyword.operator.subtype.midas" + }, + { + "match": "[A-Za-z][A-Za-z0-9_]*", + "name": "entity.name.type.midas" + } + ] + }, + "extend-stmt": { + "begin": "\\b(extend)\\b", + "beginCaptures": { + "1": { + "name": "keyword.declaration.midas" + } + }, + "end": "(?=\\{)|$", + "name": "meta.declaration.extend.midas", + "patterns": [ + { + "include": "#comments" + }, + { + "match": "[A-Za-z_][A-Za-z0-9_]*", + "name": "entity.name.type.midas" + }, + { + "begin": "\\[", + "beginCaptures": { + "0": { + "name": "punctuation.section.brackets.begin.midas" + } + }, + "end": "\\]", + "endCaptures": { + "0": { + "name": "punctuation.section.brackets.end.midas" + } + }, + "patterns": [ + { + "include": "#comments" + }, + { + "include": "#type-params" + } + ] + } + ] + }, + "extend-body": { "begin": "\\{", - "end": "\\}", "beginCaptures": { "0": { - "name": "punctuation.definition.type-body.begin.midas" + "name": "punctuation.section.block.begin.midas" } }, + "end": "\\}", "endCaptures": { "0": { - "name": "punctuation.definition.type-body.end.midas" + "name": "punctuation.section.block.end.midas" } }, "patterns": [ - {"include": "#type-prop"}, - {"include": "#comment"} + { + "include": "#comments" + }, + { + "include": "#member-stmt" + } ] }, - "type-prop": { - "match": "([a-zA-Z_][a-zA-Z_\\d]*)(:)\\s*([a-zA-Z_][a-zA-Z_\\d]*)", - "captures": { - "1": { - "name": "variable.name" + "member-stmt": { + "patterns": [ + { + "include": "#comments" }, - "2": { - "name": "punctuation.separator.annotation.midas" - }, - "3": { - "name": "meta.type.name" + { + "begin": "\\b(prop|def)\\b", + "beginCaptures": { + "1": { + "name": "keyword.other.midas" + } + }, + "end": "$", + "patterns": [ + { + "include": "#comments" + }, + { + "match": "[A-Za-z_][A-Za-z0-9_]*", + "name": "variable.other.member.midas" + }, + { + "begin": ":", + "beginCaptures": { + "0": { + "name": "punctuation.separator.annotation.midas" + } + }, + "end": "$", + "patterns": [ + { + "include": "#type-expr" + } + ] + } + ] } - } + ] }, - "extend-def": { - "begin": "\\b(extend)\\s*([a-zA-Z_][a-zA-Z_\\d]*)\\s+(\\{)", - "end": "\\}", + "predicate-stmt": { + "begin": "\\b(predicate)\\b", "beginCaptures": { "1": { - "name": "keyword.control.extend.midas" - }, - "2": { - "name": "variable.name" - }, - "3": { - "name": "punctuation.definition.extend-body.begin.midas" + "name": "keyword.declaration.midas" } }, - "endCaptures": { - "0": { - "name": "punctuation.definition.extend-body.end.midas" - } - }, - "patterns": [ - {"include": "#op-def"}, - {"include": "#comment"} - ] - }, - "op-def": { - "match": "\\b(op)\\s+(\\S+)\\s*\\(\\s*([a-zA-Z_][a-zA-Z_\\d]*)\\s*\\)\\s*(->)\\s*([a-zA-Z_][a-zA-Z_\\d]*)", - "captures": { - "1": { - "name": "keyword.control.op.midas" - }, - "2": { - "name" : "keyword.operator" - }, - "3": { - "name" : "variable.name" - }, - "4": { - "name" : "keyword.operator.assignment" - }, - "5": { - "name" : "variable.name" - } - } - }, - "pred-def": { - "begin": "(predicate)\\s+([a-zA-Z_][a-zA-Z_\\d]*)\\(([a-zA-Z_][a-zA-Z_\\d]*):\\s*([a-zA-Z_][a-zA-Z_\\d]*)\\)\\s*(=)", "end": "$", - "beginCaptures": { - "1": { - "name": "keyword.control.pred.midas" - }, - "2": { - "name": "variable.name" - }, - "3": { - "name": "variable.name" - }, - "4": { - "name": "variable.name" - }, - "5": { - "name": "keyword.operator.assignment" - } - }, + "name": "meta.declaration.predicate.midas", "patterns": [ - { "include": "source.python" } + { + "include": "#comments" + }, + { + "match": "[A-Za-z_][A-Za-z0-9_]*", + "name": "entity.name.function.midas" + }, + { + "begin": "\\(", + "beginCaptures": { + "0": { + "name": "punctuation.section.group.begin.midas" + } + }, + "end": "\\)", + "endCaptures": { + "0": { + "name": "punctuation.section.group.end.midas" + } + }, + "patterns": [ + { + "include": "#predicate-params" + } + ] + }, + { + "begin": "=", + "beginCaptures": { + "0": { + "name": "keyword.operator.equal.midas" + } + }, + "end": "$", + "patterns": [ + { + "include": "#constraint" + } + ] + } ] }, - "statement": { + "predicate-params": { "patterns": [ - { "include": "#comment" }, - { "include": "#type-def" }, - { "include": "#extend-def" }, - { "include": "#pred-def" } + { + "include": "#comments" + }, + { + "begin": "([A-Za-z_][A-Za-z0-9_]*)(:)", + "beginCaptures": { + "1": { + "name": "variable.parameter.midas" + }, + "2": { + "name": "punctuation.separator.annotation.midas" + } + }, + "end": "(?=,)|(?=\\))", + "patterns": [ + { + "include": "#type-expr" + } + ] + }, + { + "match": ",", + "name": "punctuation.separator.midas" + } + ] + }, + "type-expr": { + "patterns": [ + { + "include": "#comments" + }, + { + "begin": "\\b(fn)\\s*(\\()", + "beginCaptures": { + "1": { + "name": "keyword.other.midas" + }, + "2": { + "name": "punctuation.section.group.begin.midas" + } + }, + "end": "\\)", + "endCaptures": { + "0": { + "name": "punctuation.section.group.end.midas" + } + }, + "patterns": [ + { + "include": "#fn-params" + } + ] + }, + { + "match": "->", + "name": "keyword.operator.arrow.midas" + }, + { + "begin": "\\b(where)\\b", + "beginCaptures": { + "1": { + "name": "keyword.other.midas" + } + }, + "end": "$", + "patterns": [ + { + "include": "#constraint" + } + ] + }, + { + "begin": "(\\bFrame\\b)(\\s*)(\\[)", + "beginCaptures": { + "1": { + "name": "entity.name.type.midas" + }, + "3": { + "name": "punctuation.section.brackets.begin.midas" + } + }, + "end": "\\]", + "endCaptures": { + "0": { + "name": "punctuation.section.brackets.end.midas" + } + }, + "patterns": [ + { + "include": "#frame-schema" + } + ] + }, + { + "match": "\\bFrame\\b", + "name": "entity.name.type.midas" + }, + { + "match": "[A-Za-z_][A-Za-z0-9_]*", + "name": "entity.name.type.midas" + }, + { + "begin": "\\[", + "beginCaptures": { + "0": { + "name": "punctuation.section.brackets.begin.midas" + } + }, + "end": "\\]", + "endCaptures": { + "0": { + "name": "punctuation.section.brackets.end.midas" + } + }, + "patterns": [ + { + "include": "#comments" + }, + { + "include": "#type-expr" + }, + { + "match": ",", + "name": "punctuation.separator.midas" + } + ] + } + ] + }, + "fn-params": { + "patterns": [ + { + "include": "#comments" + }, + { + "begin": "([A-Za-z_][A-Za-z0-9_]*)(:)", + "beginCaptures": { + "1": { + "name": "variable.parameter.midas" + }, + "2": { + "name": "punctuation.separator.annotation.midas" + } + }, + "end": "(?=,)|(?=\\))", + "patterns": [ + { + "include": "#type-expr" + }, + { + "match": "\\?", + "name": "keyword.operator.qmark.midas" + } + ] + }, + { + "match": ",", + "name": "punctuation.separator.midas" + }, + { + "include": "#type-expr" + } + ] + }, + "constraint": { + "patterns": [ + { + "include": "#comments" + }, + { + "match": "\\d+(\\.\\d+)?", + "name": "constant.numeric.midas" + }, + { + "match": "\\b(true|false|none)\\b", + "name": "constant.language.midas" + }, + { + "include": "#string" + }, + { + "match": "(<=|>=|<|>|==|!=|&)", + "name": "keyword.operator.midas" + }, + { + "match": "_", + "name": "variable.language.midas" + }, + { + "match": "[A-Za-z_][A-Za-z0-9_]*(?=\\s*\\()", + "name": "variable.function.midas" + }, + { + "match": "[A-Za-z_][A-Za-z0-9_]*", + "name": "variable.other.readwrite.midas" + } + ] + }, + "frame-schema": { + "patterns": [ + { + "include": "#comments" + }, + { + "match": "[A-Za-z_][A-Za-z0-9_]*", + "name": "variable.other.member.midas" + }, + { + "begin": ":", + "beginCaptures": { + "0": { + "name": "punctuation.separator.annotation.midas" + } + }, + "end": "(?=,)|(?=\\])", + "patterns": [ + { + "include": "#type-expr" + } + ] + }, + { + "match": ",", + "name": "punctuation.separator.midas" + } ] } } From 6740344eba960468974688277ff688da4a7965df Mon Sep 17 00:00:00 2001 From: LordBaryhobal Date: Wed, 8 Jul 2026 14:07:37 +0200 Subject: [PATCH 3/5] docs: update Midas EBNF --- midas/parser/midas.py | 2 +- syntax/midas.ebnf | 71 +++++++++++++++++++++++++++++++++++-------- syntax/midas.typ | 13 ++++---- 3 files changed, 67 insertions(+), 19 deletions(-) diff --git a/midas/parser/midas.py b/midas/parser/midas.py index 146ef54..6678dbc 100644 --- a/midas/parser/midas.py +++ b/midas/parser/midas.py @@ -632,7 +632,7 @@ class MidasParser(Parser[list[Stmt]]): return WildcardExpr(location=token.get_location(), token=token) if self.match(TokenType.LEFT_PAREN): - expr: Expr = self.constraint() + expr: Expr = self.expression() right: Token = self.consume(TokenType.RIGHT_PAREN, "Unclosed parenthesis") return GroupingExpr(location=token.location_to(right), expr=expr) diff --git a/syntax/midas.ebnf b/syntax/midas.ebnf index 4626412..a2bf9de 100644 --- a/syntax/midas.ebnf +++ b/syntax/midas.ebnf @@ -4,40 +4,87 @@ Identifier ::= [a-zA-Z_] [a-zA-Z_0-9]* Integer ::= '\d+' Number ::= "-"? Integer ("." Integer)? Boolean ::= "False" | "True" +String ::= '(".*?")|(\'.*?\')' None ::= "None" -Value ::= Number | Boolean | None +Literal ::= Number | Boolean | String | None +UnaryOp ::= "+" | "-" | "!" +FactorOp ::= "*" | "/" +TermOp ::= "+" | "-" ComparisonOp ::= ">" | "<" | ">=" | "<=" EqualityOp ::= "==" | "!=" -Grouping ::= "(" Constraint ")" -Primary ::= "_" | Value | Identifier | Grouping +PosArg ::= Expression +KwArg ::= Identifier "=" Expression + +PosArgs ::= PosArg ("," PosArg)* +KwArgs ::= KwArg ("," KwArg)* +Args ::= ( + PosArgs + | KwArgs + | PosArgs "," KwArgs +) + +Grouping ::= "(" Expression ")" +Primary ::= "_" | Literal | Identifier | Grouping Reference ::= Primary ("." Identifier)* -Unary ::= "-"? Unary | Reference -Comparison ::= Unary (ComparisonOp Unary)* +CallArgs ::= "(" Args ")" +Call ::= Reference CallArgs* +Unary ::= UnaryOp Unary | Call +Factor ::= Unary (FactorOp Unary)* +Term ::= Factor (TermOp Factor)* +Comparison ::= Term (ComparisonOp Term)* Equality ::= Comparison (EqualityOp Comparison)* -Constraint ::= Equality ("&" Equality)* +Expression ::= Equality ("&" Equality)* +Constraint ::= Expression TemplateParam ::= Identifier ("<:" Type)? Template ::= "[" (TemplateParam ("," TemplateParam)*)? "]" +ParamType ::= Type "?"? +PosParam ::= (Identifier ":")? ParamType +KwParam ::= Identifier ":" ParamType + +PosParams ::= ( + (PosParam ("," PosParam)* ("," "/")?) + | "/" +) +MixedParams ::= KwParam ("," KwParam) +KwParams ::= ( + (("*", ",")? KwParam ("," KwParam)*) + | "*" +) +Params ::= ( + PosParams + | MixedParams + | KwParams + | (PosParams "," MixedParams) + | (PosParams "," KwParams) + | (MixedParams "," KwParams) + | (PosParams "," MixedParams "," KwParams) +) +ParamSpec ::= "(" Params? ")" TypeProperty ::= Identifier ":" Type ComplexType ::= "{" TypeProperty* "}" NamedType ::= Identifier -TypeParams ::= "[" (Type ("," Type)*)? "]" -GenericType ::= NamedType TypeParams? +TypeArgs ::= "[" (Type ("," Type)*)? "]" +FrameColumn ::= TOKEN ":" Type +FrameSchema ::= "[" (FrameColumn ("," FrameColumn)*)? "]" +GenericType ::= "Frame" FrameSchema | NamedType TypeArgs? GroupedType ::= "(" Type ")" BaseType ::= GroupedType | ComplexType | GenericType ConstraintType ::= BaseType ("where" Constraint)? +FuncType ::= "fn" ParamSpec "->" Type Type ::= ConstraintType -OpDefinition ::= "op" Identifier "(" Type ")" "->" Type -ExtendBody ::= "{" OpDefinition* "}" +MemberStatement ::= ("prop" | "def") Identifier ":" Type +ExtendBody ::= "{" MemberStatement* "}" +AliasStatement ::= "alias" Identifier "=" Type TypeStatement ::= "type" Identifier Template? "=" Type ExtendStatement ::= "extend" Type ExtendBody -PredicateStatement ::= "predicate" Identifier "(" Identifier ":" Type ")" "=" Constraint +PredicateStatement ::= "predicate" Identifier ParamSpec* "=" Constraint -Statement ::= TypeStatement | ExtendStatement | PredicateStatement +Statement ::= AliasStatement | TypeStatement | ExtendStatement | PredicateStatement diff --git a/syntax/midas.typ b/syntax/midas.typ index b05c2a5..736d0a3 100644 --- a/syntax/midas.typ +++ b/syntax/midas.typ @@ -7,20 +7,21 @@ svg.railroad .terminal rect { ``` #let css = default-css() + bytes(extra-css.text) -#let value = ``` -{[`value` < +#let literal = ``` +{[`literal` < [`number` 'digit' * ! ], [`boolean` <"False", "True">], + [`string` <["\"" 'char'*! "\""], ["'" 'char'*! "'"]>], [`none` "None"] >]} ``` #let grouping = ``` -{[`grouping` "(" 'constraint' ")"]} +{[`grouping` "(" 'expression' ")"]} ``` #let primary = ``` -{[`primary` <"_", 'value', 'identifier', 'grouping'>]} +{[`primary` <"_", 'literal', 'identifier', 'grouping'>]} ``` #let reference = ``` @@ -152,7 +153,7 @@ svg.railroad .terminal rect { ``` #let rules = ( - value: value, + literal: literal, grouping: grouping, primary: primary, reference: reference, @@ -190,7 +191,7 @@ svg.railroad .terminal rect { #let inline = ( "grouping", - "value", + "literal", "template-param", "template", "type-property", From e0a468a2c24768814280850f95377066a81383e8 Mon Sep 17 00:00:00 2001 From: LordBaryhobal Date: Wed, 8 Jul 2026 14:43:10 +0200 Subject: [PATCH 4/5] docs: update annotation syntax definitions --- syntax/annotations.ebnf | 22 ++------ syntax/annotations.typ | 117 ++++++++++++++++++++++------------------ 2 files changed, 71 insertions(+), 68 deletions(-) diff --git a/syntax/annotations.ebnf b/syntax/annotations.ebnf index 73caf4f..af18097 100644 --- a/syntax/annotations.ebnf +++ b/syntax/annotations.ebnf @@ -1,20 +1,8 @@ -identifier ::= '[a-zA-Z][a-zA-Z_]*' +Identifier ::= '[a-zA-Z][a-zA-Z_]*' -integer ::= '\d+' -number ::= integer ["." integer] -boolean ::= "False" | "True" -none ::= "None" +TypeArgs ::= "[" (Type ("," Type)*)? "]" -value ::= number | boolean | none -lambda-value ::= "_" | value -lambda-operator ::= ">" | "<" | ">=" | "<=" | "==" | "!=" -lambda ::= lambda-value lambda-operator lambda-value +FrameColumn ::= ((Identifier | "_") ":")? Type +FrameSchema ::= "[" (FrameColumn ("," FrameColumn)*)? "]" -constraint ::= identifier | "(" lambda ")" -base-type ::= identifier -type ::= base-type { "+" constraint } - -column-type ::= type | "_" -column-def ::= [ identifier ":" ] column-type - -frame-def ::= column-def { "," column-def } +Type ::= "Frame" FrameSchema | Identifier TypeArgs? diff --git a/syntax/annotations.typ b/syntax/annotations.typ index 8c66031..276a8fa 100644 --- a/syntax/annotations.typ +++ b/syntax/annotations.typ @@ -1,64 +1,72 @@ -#import "@preview/fervojo:0.1.1": render +#import "@preview/fervojo:0.1.1": default-css, render -#let value = ``` -{[`value` < - [`number` 'digit' * ! ], - [`boolean` <"False", "True">], - [`none` "None"] +#let extra-css = ```css +svg.railroad .terminal rect { + fill: #F7DCD4; +} +``` +#let css = default-css() + bytes(extra-css.text) + +#let type-args = ``` +{[`type-args` "[" "]"]} +``` + +#let frame-schema = ``` +{[`frame-schema` "[" ":"]? 'type']*","> "]"]} +``` + +#let type = ``` +{[`type` < + ["Frame" 'frame-schema'], + ['identifier' ] >]} ``` -#let constraint = ``` -{[`constraint` <"_", 'value'> <">", "<", ">=", "<=", "==", "!="> <"_", 'value'>]} -``` - -#let type-with-constraints = ``` -{[`type-with-constraints` 'identifier' ]} -``` - -#let column-def = ``` -{[`column-def` <"_", 'type-with-constraints'>]} -``` - -#let frame-def = ``` -{[`frame-def` 'column-def' * ","]} -``` - -#let annotation = ``` -{[`annotation` 'identifier' ]} -``` - #let rules = ( - value, - constraint, - type-with-constraints, - column-def, - frame-def, - annotation, + type-args: type-args, + frame-schema: frame-schema, + type: type, +) + +#let inline = ( + "type-args", + "frame-schema", ) #set text(font: "Source Sans 3") -= Type annotation syntax +#title[Supported Python annotation syntax] -#for rule in rules { - render(rule) -} += Outline -/* -#let by-name = ( - annotation: annotation, - frame-def: frame-def, - column-def: column-def, - type-with-constraints: type-with-constraints, - constraint: constraint, - value: value, +#box( + columns( + 2, + outline(title: none), + ), + height: 9cm, + stroke: 1pt, + inset: 1em, ) + += Statements and expressions + +#for (name, rule) in rules.pairs().rev() { + [== #name] + render(rule, css: css) +} + #let substitute(base-rule) = { let new-rule = base-rule - for (key, rule) in by-name.pairs() { - new-rule = new-rule.replace("'" + key + "'", rule.text.slice(1, -1)) + for name in inline { + let rule = rules.at(name) + let replacement = rule.text.slice(1, -1).replace(regex("\[`.*?`"), "[") + replacement = "[" + replacement + "#`" + name + "`]" + new-rule = new-rule.replace( + "'" + name + "'", + replacement, + ) } if new-rule != base-rule { new-rule = substitute(new-rule) @@ -66,9 +74,16 @@ return new-rule } -#let combined = raw(substitute(annotation.text)) - - #set page(flipped: true) -#render(combined) -*/ \ No newline at end of file + + += Combined rules + +#for (name, rule) in rules.pairs() { + if not name in inline { + [== #name] + let combined = substitute(rule.text) + render(raw(combined), css: css) + //raw(block: true, combined) + } +} From 3c97e75db6fd4dc5f93514954139079defe0e72f Mon Sep 17 00:00:00 2001 From: LordBaryhobal Date: Wed, 8 Jul 2026 14:43:52 +0200 Subject: [PATCH 5/5] feat(parser): allow subscript in type annotations --- midas/parser/python.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/midas/parser/python.py b/midas/parser/python.py index 269000e..b18bb62 100644 --- a/midas/parser/python.py +++ b/midas/parser/python.py @@ -380,7 +380,7 @@ class PythonParser: for col in cols: columns.append(self._parse_frame_column(col)) - case ast.Slice() | ast.Name(): + case ast.Slice() | ast.Name() | ast.Subscript(): columns.append(self._parse_frame_column(schema)) case _: @@ -391,7 +391,7 @@ class PythonParser: def _parse_frame_column(self, column: ast.expr) -> FrameColumn: loc: Location = Location.from_ast(column) match column: - case ast.Name(): + case ast.Name() | ast.Subscript(): return FrameColumn( location=loc, name=None,