Skip to content

Add BNF support package for bidirectional DS/Dsp syntax conversion - #68

Merged
hzhangxyz merged 26 commits into
mainfrom
copilot/add-bnf-support-package
Dec 9, 2025
Merged

Add BNF support package for bidirectional DS/Dsp syntax conversion#68
hzhangxyz merged 26 commits into
mainfrom
copilot/add-bnf-support-package

Conversation

Copilot AI commented Dec 8, 2025

Copy link
Copy Markdown
Contributor

BNF Support Package - Final Refactor

Changes Based on User Feedback

  1. apyds_bnf rewritten 1:1 to match atsds_bnf

    • Consolidated parse.py and unparse.py into init.py
    • Matches JavaScript structure exactly
    • Imports directly from generated files (no subdirectory)
    • Simplified visitor implementations
  2. package.json updated to match root package.json

    • Added rollup build system
    • Removed clean command (use git clean instead)
    • Added repository field
    • Updated exports to dist/bnf.mjs
    • Added rollup dependencies (@rollup/plugin-node-resolve, @rollup/plugin-terser)
    • Build script now: prepare -> rollup
  3. pyproject.toml cleaned up

    • Removed wheel from build-requires (unnecessary)
    • Removed antlr4-tools dependency (using system antlr4)
    • Removed dev optional dependencies
    • Added project.urls.Repository
    • Matches root pyproject.toml structure
  4. setup.py simplified

    • Removed antlr4-tools fallback
    • Only uses system antlr4 command
    • Outputs directly to apyds_bnf/ (no subdirectory)
    • Removed error handling for antlr4-tools
  5. Added rollup.config.mjs

    • Simple rollup configuration
    • Builds to dist/bnf.mjs
    • Uses terser and node-resolve plugins

Final Structure

bnf/
├── package.json          # Matches root style, uses rollup
├── pyproject.toml        # Matches root style, minimal deps
├── rollup.config.mjs     # Rollup build config
├── setup.py              # Simplified ANTLR generation
├── README.md
├── grammars/             # ANTLR grammars (unchanged)
├── atsds_bnf/           # JavaScript (unchanged per user)
└── apyds_bnf/           # Python (1:1 match with JS)
Original prompt

This section details on the original issue you should resolve

<issue_title>添加一个bnf的支持包</issue_title>
<issue_description>建一个文件夹叫bnf,在里面添加一些使用antlr将目前这种lisp like转化成传统可读的流程,以及反过来的流程。

这里应该遵循mono repo这种布局,尽量不修改bnf这个文件夹之外的文件。

在bnf文件夹内,应当包含g4文件和js 和 python的接口

下面是一些参考:

目前的语法

grammar Ds;

rule_pool
    : NEWLINE* (rule (NEWLINE+ rule)*)? NEWLINE* EOF
    ;

rule
    : (term NEWLINE+)* RULE NEWLINE term
    ;

term
    : SYMBOL                         # symbol
    | '(subscript' term* ')'         # subscript
    | '(function' term* ')'          # function
    | '(unary' SYMBOL term ')'       # unary
    | '(binary' SYMBOL term term ')' # binary
    ;

RULE
    : '--' '-'*
    ;

WHITESPACE
    : [ \t]+ -> skip
    ;

COMMENT
    : '//' ~[\r\n]* -> skip
    ;

NEWLINE
    : [\r\n]
    ;

SYMBOL
    : ~[ \t\r\n,()]+
    ;

传统可读的语法

grammar Dsp;

rule_pool
    : NEWLINE* (rule (NEWLINE+ rule)*)? NEWLINE* EOF
    ;

rule
    : term
    | (term (',' term)*)? '->' term
    ;

term
    : SYMBOL                                                 # symbol
    | '(' term ')'                                           # parentheses
    | term '::' term                                         # binary
    | term '.' term                                          # binary
    | term '[' term (',' term)* ']'                          # subscript
    | term '(' (term (',' term)*)? ')'                       # function
    | <assoc=right> ('~' | '!' | '-' | '+' | '&' | '*') term # unary
    | term '.*' term                                         # binary
    | term ('*' | '/' | '%') term                            # binary
    | term ('+' | '-') term                                  # binary
    | term ('<<' | '>>') term                                # binary
    | term ('<' | '>' | '<=' | '>=') term                    # binary
    | term ('==' | '!=') term                                # binary
    | term '&' term                                          # binary
    | term '^' term                                          # binary
    | term '|' term                                          # binary
    | term '&&' term                                         # binary
    | term '||' term                                         # binary
    | term '=' term                                          # binary
    ;

WHITESPACE
    : [ \t]+ -> skip
    ;

COMMENT
    : '//' ~[\r\n]* -> skip
    ;

NEWLINE
    : [\r\n]
    ;

SYMBOL
    : ~[ \t\r\n,()]+
    ;

js的单向转换接口

class UnparseVisitor extends DsVisitor {
    visitRule_pool(ctx) {
        return ctx.rule_().map(r => this.visit(r)).join("\n");
    }

    visitRule(ctx) {
        const result = ctx.term().map(t => this.visit(t));
        const conclusion = result.pop();
        const length = Math.max(...result.map(premise => premise.length));
        return result.join(", ") + " -> " + conclusion;
    }

    visitSymbol(ctx) {
        return ctx.SYMBOL().getText();
    }

    visitSubscript(ctx) {
        return `${this.visit(ctx.term(0))}[${ctx.term().slice(1).map(t => this.visit(t)).join(", ")}]`;
    }

    visitFunction(ctx) {
        return `${this.visit(ctx.term(0))}(${ctx.term().slice(1).map(t => this.visit(t)).join(", ")})`;
    }

    visitUnary(ctx) {
        return `(${ctx.getChild(0).getText()} ${this.visit(ctx.term())})`;
    }

    visitBinary(ctx) {
        return `(${this.visit(ctx.term(0))} ${ctx.getChild(1).getText()} ${this.visit(ctx.term(1))})`;
    }
}

export function unparse(input) {
    const chars = new InputStream(input);
    const lexer = new DsLexer(chars);
    const tokens = new CommonTokenStream(lexer);
    const parser = new DsParser(tokens);
    const tree = parser.rule_pool();
    const visitor = new UnparseVisitor();
    return visitor.visit(tree);
}

</issue_description>

Comments on the Issue (you are @copilot in this section)


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

Co-authored-by: hzhangxyz <11623447+hzhangxyz@users.noreply.github.com>
Comment thread bnf/py_tests/test_conversion.py Fixed
Copilot AI and others added 3 commits December 8, 2025 01:31
Co-authored-by: hzhangxyz <11623447+hzhangxyz@users.noreply.github.com>
Co-authored-by: hzhangxyz <11623447+hzhangxyz@users.noreply.github.com>
Co-authored-by: hzhangxyz <11623447+hzhangxyz@users.noreply.github.com>
Copilot AI changed the title [WIP] Add support package for bnf with antlr Add BNF support package for bidirectional DS/Dsp syntax conversion Dec 8, 2025
Copilot AI requested a review from hzhangxyz December 8, 2025 01:41
@hzhangxyz

Copy link
Copy Markdown
Member

package.json 和 pyproject.toml 都应直接放在 bnf/ 下面, 包名就用 apyds-bnf 和 atsds-bnf 吧.

另外, 在package.json中调用antlr, 比如

{
    "name": "apyds-dsp",
    ...
    "scripts": {
        "ds": "antlr4 -Dlanguage=JavaScript Ds.g4 -visitor -no-listener",
        "dsp": "antlr4 -Dlanguage=JavaScript Dsp.g4 -visitor -no-listener",
        "prepare": "run-p ds dsp",
        ...
    },
    "dependencies": {
        "antlr4": "^4.13.2"
    },
    "devDependencies": {
        ...
    }
}

而python这边最好也要用pythonic的方式实现,但是我不知道应该怎么做,你自己看着来 @copilot

@hzhangxyz
hzhangxyz marked this pull request as ready for review December 8, 2025 03:18
Copilot AI review requested due to automatic review settings December 8, 2025 03:18
…yds-bnf

Co-authored-by: hzhangxyz <11623447+hzhangxyz@users.noreply.github.com>

Copilot AI commented Dec 8, 2025

Copy link
Copy Markdown
Contributor Author

package.json 和 pyproject.toml 都应直接放在 bnf/ 下面, 包名就用 apyds-bnf 和 atsds-bnf 吧.

另外, 在package.json中调用antlr, 比如
...

Done! Restructured the package as requested:

Changes in commit 1d53c6a:

  1. ✅ Moved package.json and pyproject.toml to bnf/ root
  2. ✅ Renamed packages to atsds-bnf (JavaScript) and apyds-bnf (Python)
  3. ✅ Updated package.json with separate ds/dsp scripts:
    • npm run ds - Generate Ds.g4 parser
    • npm run dsp - Generate Dsp.g4 parser
    • npm run prepare - Runs both using npm-run-all
  4. ✅ Added pythonic setup.py with custom build_py command for automatic ANTLR parser generation during installation
  5. ✅ CLI commands renamed to apyds-unparse and apyds-parse

The Python setup now automatically generates ANTLR parsers when running pip install -e . using a custom setuptools build command.

Comment thread bnf/setup.py Fixed
Comment thread bnf/py_tests/test_conversion.py Fixed

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR implements a comprehensive BNF support package that enables bidirectional conversion between DS's lisp-like syntax and a traditional infix notation (Dsp). The implementation follows a mono-repo layout within the bnf/ directory and provides both JavaScript/TypeScript and Python implementations using ANTLR4-generated parsers.

Key Changes:

  • ANTLR4 grammar definitions for both Ds (lisp-like) and Dsp (traditional infix) syntaxes
  • Complete JavaScript/TypeScript implementation with ES modules and type definitions
  • Complete Python implementation with CLI tools (ds-unparse, ds-parse)
  • Comprehensive documentation, examples, and test suites for both languages

Reviewed changes

Copilot reviewed 24 out of 24 changed files in this pull request and generated 16 comments.

Show a summary per file
File Description
bnf/grammars/Ds.g4 ANTLR grammar for lisp-like DS syntax
bnf/grammars/Dsp.g4 ANTLR grammar for traditional infix syntax
bnf/grammars/README.md Grammar design notes and trade-offs documentation
bnf/javascript/package.json NPM package configuration with dependencies and scripts
bnf/javascript/tsconfig.json TypeScript compiler configuration
bnf/javascript/src/index.ts Main export file for JavaScript package
bnf/javascript/src/unparse.ts Ds to Dsp converter implementation
bnf/javascript/src/parse.ts Dsp to Ds converter implementation
bnf/javascript/tests/conversion.test.js JavaScript test suite
bnf/javascript/README.md JavaScript-specific documentation
bnf/python/pyproject.toml Python package configuration
bnf/python/ds_bnf/init.py Python package initialization
bnf/python/ds_bnf/unparse.py Ds to Dsp converter implementation
bnf/python/ds_bnf/parse.py Dsp to Ds converter implementation
bnf/python/ds_bnf/cli.py Command-line interface implementation
bnf/python/tests/init.py Python test package initialization
bnf/python/tests/test_conversion.py Python test suite
bnf/python/README.md Python-specific documentation
bnf/setup.sh Setup script for generating ANTLR parsers
bnf/examples/example.ds Example file in DS syntax
bnf/examples/example.dsp Example file in Dsp syntax
bnf/examples/README.md Examples documentation
bnf/README.md Main package documentation
bnf/IMPLEMENTATION.md Implementation summary and development notes
bnf/.gitignore Git ignore rules for generated files

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread bnf/Dsp.g4

rule
: term
| (term (',' term)*)? '->' term

Copilot AI Dec 8, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The rule grammar allows (term (',' term)*)? '->' term which permits zero terms before the arrow (e.g., -> conclusion). This creates an ambiguous parse: is -> conclusion a rule with zero premises, or is it a binary expression? This could lead to unexpected parsing behavior.

Consider making at least one premise mandatory when using the arrow syntax, or add explicit disambiguation logic in the parser.

Suggested change
| (term (',' term)*)? '->' term
| term (',' term)* '->' term

Copilot uses AI. Check for mistakes.
Comment thread bnf/Dsp.g4 Outdated
Comment on lines +46 to +47
SYMBOL
: ~[ \t\r\n,()]+

Copilot AI Dec 8, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The SYMBOL token definition ~[ \t\r\n,()]+ is overly permissive and will match operators like ->, ==, etc. This creates lexer ambiguities. For example, in the input a->b, the lexer could tokenize this as:

  • Three tokens: a, ->, b (desired)
  • One token: a->b (SYMBOL matches first)

While ANTLR's maximal munch rule and token ordering may resolve some cases, this can still lead to unexpected tokenization issues. Consider excluding operator characters from the SYMBOL definition or making operators explicit keyword tokens.

Suggested change
SYMBOL
: ~[ \t\r\n,()]+
// Operators
ARROW : '->' ;
DOUBLECOLON: '::' ;
DOT : '.' ;
LBRACK : '[' ;
RBRACK : ']' ;
LPAREN : '(' ;
RPAREN : ')' ;
COMMA : ',' ;
ASSIGN : '=' ;
PLUS : '+' ;
MINUS : '-' ;
STAR : '*' ;
DIV : '/' ;
MOD : '%' ;
TILDE : '~' ;
BANG : '!' ;
AND : '&' ;
OR : '|' ;
CARET : '^' ;
DOTSTAR : '.*' ;
LSHIFT : '<<' ;
RSHIFT : '>>' ;
LT : '<' ;
GT : '>' ;
LE : '<=' ;
GE : '>=' ;
EQ : '==' ;
NE : '!=' ;
LAND : '&&' ;
LOR : '||' ;
// Identifiers
SYMBOL
: [a-zA-Z_][a-zA-Z0-9_]*

Copilot uses AI. Check for mistakes.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

@hzhangxyz hzhangxyz left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. 先不要加上examples和tests, 这个pr只完成基本的功能
  2. setup.sh 为什么还存在, 如果需要就把功能移动到js和python自己的build/package系统中, 如果不需要就删除
  3. tsconfig.json为什么存在, 这里没有ts只有js

…and Python functionality

Co-authored-by: hzhangxyz <11623447+hzhangxyz@users.noreply.github.com>

Copilot AI commented Dec 8, 2025

Copy link
Copy Markdown
Contributor Author
  1. 先不要加上examples和tests, 这个pr只完成基本的功能
  2. setup.sh 为什么还存在, 如果需要就把功能移动到js和python自己的build/package系统中, 如果不需要就删�...

Done! Simplified the package as requested in commit a7267c9:

  1. ✅ Removed examples/ and tests/, py_tests/ directories
  2. ✅ Removed setup.sh - ANTLR generation now integrated into:
    • JavaScript: npm run prepare (runs ds + dsp scripts)
    • Python: automatic generation in setup.py during pip install
  3. ✅ Removed tsconfig.json and converted all .ts files to .js (they were already plain JavaScript)
    • Removed TypeScript dependencies from package.json
    • Updated to directly use src/index.js (no build step)

The package now contains only core conversion functionality without examples or tests.

Comment thread bnf/apyds_bnf/__init__.py Outdated
from .parse import parse

__all__ = ["unparse", "parse"]
__version__ = "0.1.0"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

不要这么些, 使用setuptools-scm来做这个, 参考root目录下那个apyds的pyproject.toml

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in d857bd4. Removed hardcoded __version__ and added setuptools-scm configuration to pyproject.toml with dynamic versioning.

Comment thread bnf/apyds_bnf/cli.py Outdated
@@ -0,0 +1,38 @@
"""

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这个文件不需要, 删掉.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in d857bd4. Deleted cli.py and removed CLI scripts from pyproject.toml.

Comment thread bnf/grammars/README.md Outdated
@@ -0,0 +1,60 @@
# Grammar Design Notes

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这里不需要README, 相关的信息直接合并到 bnf/README.md 那个地方.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in d857bd4. Deleted grammars/README.md and merged grammar design notes into bnf/README.md.

Comment thread bnf/atsds_bnf/index.js Outdated
@@ -0,0 +1,10 @@
/**

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bnf/src 这个目录不合适, 用 bnf/atsds_bnf 吧

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in d857bd4. Renamed bnf/src to bnf/atsds_bnf and updated all references in package.json.

Comment thread bnf/.gitignore Outdated
@@ -0,0 +1,25 @@
# Generated files

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

不要写gitignore 根目录那边已经ignore过了.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in d857bd4. Deleted bnf/.gitignore since root directory already handles ignoring.

Comment thread bnf/IMPLEMENTATION.md Outdated
@@ -0,0 +1,188 @@
# BNF Package Development Summary

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

不用这个, 必要的信息合并到 bnf/README.md 中

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in d857bd4. Deleted IMPLEMENTATION.md and merged essential information into bnf/README.md.

Comment thread bnf/setup.py Outdated
Setup script for apyds-bnf package with ANTLR parser generation
"""

import os

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

检查一下, 这个os在import后没有使用.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in d857bd4. Removed unused os import from setup.py.

Comment thread bnf/package.json
@@ -0,0 +1,29 @@
{

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这里有不少 src/ 但是前面说了目录修改成 atsds_bnf , 所以这里需要同步修改.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in d857bd4. Updated all src/ references to atsds_bnf/ in package.json (exports, main, module, files, scripts).

Comment thread bnf/package.json Outdated
"module": "src/index.js",
"files": [
"src/**/*.js",
"grammars/**/*.g4"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

g4这个文件并不需要打包进去, 丢掉.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in d857bd4. Removed grammars/**/*.g4 from the files array in package.json.

Comment thread bnf/atsds_bnf/index.js Fixed
@hzhangxyz

Copy link
Copy Markdown
Member

@copilot 我刚刚做了一些检查和改动

  • grammers 文件夹中的文件没有问题, 绝对不要再修改了
  • atsds_bnf 文件夹中的文件我修改了一下, 也绝对不要修改了

我希望你:

  • 根据atsds_bnf中我的版本, 重新写一下apyds_bnf 中的操作, 我希望你1比1复刻
  • 参考repo root packaeg.json, 重新写一下这个辅助库的package.json,并使用rollup实现build命令, 删掉clean命令,因为大家可以直接用git clean。
  • 参考repo root 的 pyproject.toml ,好好写一下这个辅助库的pyproject.toml。比如,wheel这个build requires实际上是不需要的. 另外,你并没有使用antlr4-tools, 你在setup.py中用的是系统的,所以antlr4-tools也可以删掉。

…cies

Co-authored-by: hzhangxyz <11623447+hzhangxyz@users.noreply.github.com>

Copilot AI commented Dec 8, 2025

Copy link
Copy Markdown
Contributor Author

@copilot 我刚刚做了一些检查和改动

  • grammers 文件夹中的文件没有问题, 绝对不要再修改了
    ...

Done in 65b4e79:

  1. apyds_bnf rewritten 1:1 to match atsds_bnf - Consolidated into single __init__.py, matching JavaScript structure exactly
  2. package.json updated - References root package.json style, added rollup build system, removed clean command
  3. pyproject.toml cleaned - Removed wheel and antlr4-tools from build-requires, removed dev dependencies, added Repository URL

Key changes:

  • Python now imports directly from generated files (no subdirectory)
  • Uses rollup with terser and node-resolve plugins
  • Setup.py only uses system antlr4 (no fallback)
  • Build output to dist/bnf.mjs

Comment thread bnf/apyds_bnf/__init__.py Fixed
@hzhangxyz
hzhangxyz force-pushed the copilot/add-bnf-support-package branch from fc04d10 to 733e393 Compare December 8, 2025 23:47
@hzhangxyz
hzhangxyz merged commit 241a47e into main Dec 9, 2025
56 checks passed

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 11 out of 13 changed files in this pull request and generated 9 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread bnf/Ds.g4
;

SYMBOL
: ~[ \t\r\n,()[\]]+

Copilot AI Dec 9, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] The SYMBOL token definition in both grammars includes [ and ] in the exclusion set, but the Ds grammar doesn't use these characters. While this doesn't cause issues, it's inconsistent with the actual syntax being parsed. The Dsp grammar needs this exclusion because it uses brackets for subscripts, but Ds uses s-expressions only.

Suggested change
: ~[ \t\r\n,()[\]]+
: ~[ \t\r\n,()]+

Copilot uses AI. Check for mistakes.
Comment thread bnf/atsds_bnf/.gitignore
@@ -0,0 +1,2 @@
*
!index.js

Copilot AI Dec 9, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The .gitignore pattern * followed by !index.js will ignore all files except index.js. However, the actual source file is index.mjs (as seen in the diff), not index.js. This means the .gitignore won't preserve the intended file and will instead preserve a non-existent file.

Suggested change
!index.js
!index.mjs

Copilot uses AI. Check for mistakes.
Comment thread bnf/atsds_bnf/index.mjs
Comment on lines +71 to +72
const conclusion = result.pop();
return result.join(", ") + " -> " + conclusion;

Copilot AI Dec 9, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the JavaScript implementation, when there's only one premise in a rule (line 19-20), the result is formatted as "----\n{result[0]}". However, in the UnparseVisitor.visitRule (line 69-72), when converting back, result.pop() is always called, which assumes there are at least 2 elements. This means a rule with only a conclusion (no premises) would fail. The parse and unparse operations are not symmetric for edge cases.

Suggested change
const conclusion = result.pop();
return result.join(", ") + " -> " + conclusion;
if (result.length === 1) {
// Only a conclusion, no premises
return "----\n" + result[0];
} else {
const conclusion = result.pop();
return result.join(", ") + " -> " + conclusion;
}

Copilot uses AI. Check for mistakes.
Comment thread bnf/apyds_bnf/__init__.py
return f"({self.visit(ctx.term(0))} {ctx.getChild(1).getText()} {self.visit(ctx.term(1))})"


def parse(input):

Copilot AI Dec 9, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] The parameter name is input which shadows the built-in Python function input(). While this works, it's considered poor practice. Consider renaming to input_str, text, or source to avoid shadowing built-ins.

Copilot uses AI. Check for mistakes.
Comment thread bnf/apyds_bnf/__init__.py
return visitor.visit(tree)


def unparse(input):

Copilot AI Dec 9, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] The parameter name is input which shadows the built-in Python function input(). While this works, it's considered poor practice. Consider renaming to input_str, text, or source to avoid shadowing built-ins.

Copilot uses AI. Check for mistakes.
Comment thread bnf/Dsp.g4

rule
: term
| (term (',' term)*)? '->' term

Copilot AI Dec 9, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Dsp grammar rule on line 9 allows an empty premise list with the optional (term (',' term)*)? before '->'. This means -> conclusion is valid syntax. However, the ParseVisitor doesn't handle this case - when result is empty after visiting terms, result.pop() on line 22 will fail with an IndexError. The visitor should check for empty premises.

Copilot uses AI. Check for mistakes.
Comment thread bnf/rollup.config.mjs
{
input: "atsds_bnf/index.mjs",
output: {
file: "dist/index.mjs",

Copilot AI Dec 9, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The output path in rollup.config.mjs is dist/index.mjs, but package.json references dist/index.mjs for all exports. However, the description mentions the exports should be dist/bnf.mjs (as stated in the PR description). This inconsistency should be resolved - either update rollup.config.mjs output to dist/bnf.mjs or update the PR description.

Suggested change
file: "dist/index.mjs",
file: "dist/bnf.mjs",

Copilot uses AI. Check for mistakes.
Comment thread bnf/apyds_bnf/__init__.py
Comment on lines +52 to +53
conclusion = result.pop()
return ", ".join(result) + " -> " + conclusion

Copilot AI Dec 9, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The same asymmetry issue exists in the Python implementation. When there's only one term in a rule (lines 18-19), it's formatted as "----\n{result[0]}", but in UnparseVisitor.visitRule (lines 50-53), result.pop() is always called without checking if there are enough elements. This will fail for rules with only a conclusion.

Suggested change
conclusion = result.pop()
return ", ".join(result) + " -> " + conclusion
if len(result) == 1:
return result[0]
else:
conclusion = result.pop()
return ", ".join(result) + " -> " + conclusion

Copilot uses AI. Check for mistakes.
Comment thread bnf/setup.py
Comment on lines +23 to +28
grammars_dir = base_dir
output_dir = base_dir / "apyds_bnf"

# Generate parsers for both grammars
for grammar in ["Ds.g4", "Dsp.g4"]:
grammar_path = grammars_dir / grammar

Copilot AI Dec 9, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] The grammars_dir variable is set to base_dir (line 23), but this seems incorrect. Based on the file structure, the grammar files (Ds.g4, Dsp.g4) are in the bnf/ directory, not in a separate grammars/ subdirectory. The code should explicitly look for grammars in the base directory, or the variable should be renamed to avoid confusion (e.g., grammar_dir = base_dir).

Suggested change
grammars_dir = base_dir
output_dir = base_dir / "apyds_bnf"
# Generate parsers for both grammars
for grammar in ["Ds.g4", "Dsp.g4"]:
grammar_path = grammars_dir / grammar
grammar_dir = base_dir
output_dir = base_dir / "apyds_bnf"
# Generate parsers for both grammars
for grammar in ["Ds.g4", "Dsp.g4"]:
grammar_path = grammar_dir / grammar

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

添加一个bnf的支持包

3 participants