diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..9909679 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,34 @@ +# Repository Guidelines + +## Project Structure & Module Organization +- `src/java` holds the Java implementation (packages under `io.compgen.cgpipe`). +- `src/conf` and `src/scripts` contain runtime configuration and launcher assets. +- `src/test-scripts` contains language-level test fixtures (`*.mvp`, `*.mvpt`). +- `docs` includes user and language reference documentation. +- `lib` and `blib` hold third-party jars; `build`, `dist` are build outputs. + +## Build, Test, and Development Commands +- `ant jar` builds the CLI artifacts into `dist/` (includes `cgpipe` and `cgsub`). +- `ant clean` removes `build/` and `dist/` output. +- `./test.sh` runs the language tests in `src/test-scripts` and compares against `.good` files. +- `./build_docs.sh` regenerates documentation (when needed). + +## Coding Style & Naming Conventions +- Java code uses tabs for indentation; match the existing style in nearby files. +- Package naming follows `io.compgen.cgpipe.*`; classes use `PascalCase`, methods/vars use `camelCase`. +- Keep changes compatible with Java 11 (see `build.xml` compiler settings). +- No automated formatter is configured; avoid large, unrelated reformatting. + +## Testing Guidelines +- Tests are script-based; each `*.mvp`/`*.mvpt` should have a matching `.good` output file. +- Add or update tests for language/runtime changes and verify with `./test.sh`. +- Use `./test.sh -v` (or `-vv/-vvv`) to see expected vs. actual output diffs. + +## Commit & Pull Request Guidelines +- Git history shows short, direct subjects (e.g., “debug”, “missing comment”); follow this concise style. +- Use imperative, present-tense summaries and include context in the PR description. +- Include test results (`./test.sh`) and note any config or scheduler assumptions. + +## Configuration & Runtime Notes +- CGPipe reads configuration from `.cgpiperc` files and environment (`CGPIPE_HOME`, `CGPIPE_ENV`). +- Scheduler templates live under `src/java/io/compgen/cgpipe/runner`; update templates with care. diff --git a/docs/03-Language_Syntax.md b/docs/03-Language_Syntax.md index 42fdd63..62a98c6 100644 --- a/docs/03-Language_Syntax.md +++ b/docs/03-Language_Syntax.md @@ -248,6 +248,9 @@ Basic syntax: do something... done + for val + do something... # while-style loop; runs while val is true + ## Build target definitions Targets are the files that you want to create. They are defined on a single @@ -475,4 +478,3 @@ a var: will result in this being added to the body: echo "target" - diff --git a/src/java/io/compgen/cgpipe/parser/node/ASTNode.java b/src/java/io/compgen/cgpipe/parser/node/ASTNode.java index d4039d1..088f813 100644 --- a/src/java/io/compgen/cgpipe/parser/node/ASTNode.java +++ b/src/java/io/compgen/cgpipe/parser/node/ASTNode.java @@ -57,8 +57,13 @@ protected ASTNode parseTokens(TokenList tokens) throws ASTParseException { return this.next; } + int sliceDepth = 0; for (Token tok: tokens) { - if (tok.isColon()) { + if (tok.isSliceOpen()) { + sliceDepth++; + } else if (tok.isSliceClose() && sliceDepth > 0) { + sliceDepth--; + } else if (tok.isColon() && sliceDepth == 0) { this.next = new TargetNode(this, tokens); return this.next; } @@ -71,6 +76,7 @@ public ASTNode exec(ExecContext context) throws ASTExecException { // System.err.println("Eval: " + StringUtils.join(",", tokens)); VarValue val = Eval.evalTokenExpression(tokens, context); if (val == VarNull.NULL) { +// context.getRoot().dump(); throw new ASTExecException("Null expression: " + tokens); } // System.err.println("<<< " + val.toString()); @@ -112,4 +118,3 @@ public ASTNode getParent() { return parent; } } - diff --git a/src/java/io/compgen/cgpipe/parser/tokens/Tokenizer.java b/src/java/io/compgen/cgpipe/parser/tokens/Tokenizer.java index dee0983..6dac542 100644 --- a/src/java/io/compgen/cgpipe/parser/tokens/Tokenizer.java +++ b/src/java/io/compgen/cgpipe/parser/tokens/Tokenizer.java @@ -61,6 +61,7 @@ public static TokenList tokenize(NumberedLine line, boolean inTargetDef) throws if (!inSlice) { throw new ASTParseException("Missing opening ["); } + inSlice = false; } if (!inSlice && tok.isColon()) { foundColon = true; diff --git a/src/test-scripts/varvar.mvpt b/src/test-scripts/varvar.mvpt new file mode 100644 index 0000000..a172957 --- /dev/null +++ b/src/test-scripts/varvar.mvpt @@ -0,0 +1,16 @@ +foo = "foobar" +bar = foo[3:] + +print(foo) +print(bar) +print(foo[3:]) + +i=0 + +for foo == "foobar" && i < 2 + print(foo) + foo2 = foo[1:] + foo = foo2 + i = i + 1 + print(foo) +done diff --git a/src/test-scripts/varvar.mvpt.good b/src/test-scripts/varvar.mvpt.good new file mode 100644 index 0000000..4d31c03 --- /dev/null +++ b/src/test-scripts/varvar.mvpt.good @@ -0,0 +1,5 @@ +foobar +bar +bar +foobar +oobar diff --git a/src/test-scripts/while.mvpt.good b/src/test-scripts/while.mvpt.good index 0719398..6202ea0 100644 --- a/src/test-scripts/while.mvpt.good +++ b/src/test-scripts/while.mvpt.good @@ -7,3 +7,4 @@ 7 8 9 +here diff --git a/test.sh b/test.sh index 47bb883..4127790 100755 --- a/test.sh +++ b/test.sh @@ -16,8 +16,9 @@ fi if [ "$1" == "" ]; then rm -f test/err - find src/test-scripts -name '*.mvp' -exec $0 $VERBOSE \{\} \; - find src/test-scripts -name '*.mvpt' -exec $0 $VERBOSE \{\} \; + # Skip remote-dependent tests during bulk runs. + find src/test-scripts -name '*.mvp' ! -name 'help.mvp' -exec $0 $VERBOSE \{\} \; + find src/test-scripts -name '*.mvpt' ! -name 'remote.mvpt' -exec $0 $VERBOSE \{\} \; if [ -e test/err ]; then rm test/err