Skip to content

Commit aa479a7

Browse files
committed
fix: derive POS tags from upstream semantics and restore -R variants
The generated postype.go did not compile: POS_P, POS_PV and POS_PA were all emitted as "P", which produced duplicate cases in the isValid switch. Rewrite the generator to evaluate POSTag enum initializers the way the C++ compiler does and to transcribe tagToString/tagRToString, instead of relying on hardcoded special cases and an "ends with i" heuristic. That corrects three mappings that never matched upstream: - pa = p + 1 == max, so tagToString returns "@", not "P" - pvi/pai fall through the irregular switch default, so both are "@", not "PV-I"/"PA-I" - the -R variants are reachable only through tagRToString, which is what kiwi_res_tag calls; dropping them made ParsePOSType fail on ordinary sentences such as "편지를 받았다", re-introducing #39 Deduplicate the isValid switch by value so aliases can no longer break the build, keep POS_USER_0..4 as deprecated aliases so the rename does not break downstream code, and add a regression test covering both the -R tags and a regular conjugation through Analyze. Verify the generated code inside the sync workflow: pull requests opened with GITHUB_TOKEN do not trigger CI, so nothing was checking it.
1 parent 78ffc23 commit aa479a7

6 files changed

Lines changed: 289 additions & 100 deletions

File tree

.github/workflows/sync-postypes.yaml

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,13 +41,13 @@ jobs:
4141
id: get_version
4242
run: |
4343
if [ -n "${{ github.event.inputs.kiwi_version }}" ]; then
44-
echo "version=${{ github.event.inputs.kiwi_version }}" >> $GITHUB_OUTPUT
44+
VERSION="${{ github.event.inputs.kiwi_version }}"
4545
else
4646
# Get latest release from GitHub API
4747
VERSION=$(curl -s https://api.github.com/repos/bab2min/Kiwi/releases/latest | jq -r '.tag_name')
48-
echo "version=$VERSION" >> $GITHUB_OUTPUT
4948
fi
50-
echo "Kiwi version: $(cat $GITHUB_OUTPUT | grep version | cut -d= -f2)"
49+
echo "version=$VERSION" >> $GITHUB_OUTPUT
50+
echo "Kiwi version: $VERSION"
5151
5252
- name: Extract POS tags
5353
id: extract
@@ -89,6 +89,15 @@ jobs:
8989
# Update Makefile version
9090
sed -i "s/KIWI_VERSION := .*/KIWI_VERSION := ${{ steps.get_version.outputs.version }}/" Makefile
9191
92+
# PRs opened with GITHUB_TOKEN do not trigger CI, so the generated code is
93+
# verified here instead. Without this a non-compiling postype.go can be
94+
# proposed and merged unnoticed.
95+
- name: Verify generated code
96+
if: steps.extract.outputs.changed == 'true'
97+
run: |
98+
make install-kiwi
99+
make test
100+
92101
- name: Create Pull Request
93102
if: steps.extract.outputs.changed == 'true'
94103
uses: peter-evans/create-pull-request@v7

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,6 @@ ModelGenerator/
2626

2727
# Python virtual environment
2828
.venv/
29+
30+
# Generated by scripts/extract_postags.py before it replaces postype.go
31+
postype_generated.go

Makefile

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,18 +25,27 @@ format:
2525
# go install mvdan.cc/gofumpt@latest
2626
gofumpt -l -w .
2727

28+
VENV := .venv
29+
VENV_PYTHON := $(VENV)/bin/python
30+
31+
# `source` is not available under /bin/sh on Debian-family systems, so the
32+
# venv interpreter is invoked directly instead of activating the venv.
33+
$(VENV_PYTHON):
34+
python3 -m venv $(VENV)
35+
$(VENV)/bin/pip install --quiet tree-sitter tree-sitter-cpp
36+
2837
.PHONY: sync-postypes
29-
sync-postypes:
38+
sync-postypes: $(VENV_PYTHON)
3039
@echo "Extracting POS tags from Kiwi $(KIWI_VERSION)..."
31-
source .venv/bin/activate && python scripts/extract_postags.py $(KIWI_VERSION)
40+
$(VENV_PYTHON) scripts/extract_postags.py $(KIWI_VERSION)
3241
@echo "Generated postype_generated.go"
3342
@echo "Comparing with current postype.go..."
3443
@diff -u postype.go postype_generated.go || true
3544
@echo "To apply changes, run: mv postype_generated.go postype.go"
3645

3746
.PHONY: check-postypes
38-
check-postypes:
39-
@source .venv/bin/activate && python scripts/extract_postags.py $(KIWI_VERSION)
47+
check-postypes: $(VENV_PYTHON)
48+
@$(VENV_PYTHON) scripts/extract_postags.py $(KIWI_VERSION)
4049
@if diff -q postype.go postype_generated.go > /dev/null 2>&1; then \
4150
echo "POS types are in sync with Kiwi $(KIWI_VERSION)"; \
4251
else \

postype.go

Lines changed: 21 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

postype_test.go

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,32 @@ func TestParsePOSType(t *testing.T) {
2525
want: POS_UNKNOWN,
2626
wantErr: true,
2727
},
28+
// kiwi_res_tag is implemented with tagRToString, so the -R variants
29+
// reach Go for regular conjugations. See #39.
30+
{
31+
name: "VV-R is a POSType",
32+
arg: "VV-R",
33+
want: POS_VV_R,
34+
wantErr: false,
35+
},
36+
{
37+
name: "XSA-R is a POSType",
38+
arg: "XSA-R",
39+
want: POS_XSA_R,
40+
wantErr: false,
41+
},
42+
{
43+
name: "VV-I is a POSType",
44+
arg: "VV-I",
45+
want: POS_VV_I,
46+
wantErr: false,
47+
},
48+
{
49+
name: "@ is a POSType",
50+
arg: "@",
51+
want: POS_PA,
52+
wantErr: false,
53+
},
2854
}
2955
for _, tt := range tests {
3056
t.Run(tt.name, func(t *testing.T) {
@@ -39,3 +65,26 @@ func TestParsePOSType(t *testing.T) {
3965
})
4066
}
4167
}
68+
69+
// TestAnalyzeRegularConjugation guards against #39. Kiwi tags a regular verb
70+
// whose stem ends in ㄷ/ㅂ/ㅅ as VV-R rather than VV, so dropping the -R
71+
// constants makes Analyze fail on ordinary sentences.
72+
func TestAnalyzeRegularConjugation(t *testing.T) {
73+
kiwi, err := New("./base", WithNumThread(1))
74+
assert.NoError(t, err)
75+
76+
for _, sentence := range []string{"편지를 받았다", "나는 공을 잡았다", "그는 크게 웃었다"} {
77+
t.Run(sentence, func(t *testing.T) {
78+
res, err := kiwi.Analyze(sentence)
79+
assert.NoError(t, err)
80+
81+
var tags []POSType
82+
for _, result := range res {
83+
for _, token := range result.Tokens {
84+
tags = append(tags, token.Tag)
85+
}
86+
}
87+
assert.Contains(t, tags, POS_VV_R)
88+
})
89+
}
90+
}

0 commit comments

Comments
 (0)