Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 60 additions & 0 deletions cgo_harness/issue454_variant_cguard_fivesize_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
//go:build cgo && treesitter_c_parity

package cgoharness

import (
"bytes"
"strconv"
"testing"

"github.com/odvcencio/gotreesitter/internal/benchfixtures"
sitter "github.com/tree-sitter/go-tree-sitter"
)

func TestIssue454VariantCGuardFiveSizes(t *testing.T) {
sizes := []int{1024, 4096, 16384, 65536, benchfixtures.Issue454CFixtureBytes}
for _, size := range sizes {
size := size
t.Run(sizeLabel(size), func(t *testing.T) {
source := append([]byte(nil), benchfixtures.Issue454CSource()[:size]...)
site := bytes.Index(source, []byte("x0"))
if site < 0 {
t.Fatal("C edit marker is absent")
}
edited := append(append([]byte(nil), source[:site]...), source[site+1:]...)

goTree, goLang, err := parseWithGo(parityCase{name: "c"}, edited, nil)
if err != nil {
t.Fatalf("parse edited C witness with Go: %v", err)
}
t.Cleanup(goTree.Release)

cLang, err := ParityCLanguage("c")
if err != nil {
t.Fatalf("load locked C grammar: %v", err)
}
cParser := sitter.NewParser()
t.Cleanup(cParser.Close)
if err := cParser.SetLanguage(cLang); err != nil {
t.Fatalf("set locked C grammar: %v", err)
}
cTree := cParser.Parse(edited, nil)
if cTree == nil || cTree.RootNode() == nil {
t.Fatal("locked C parser returned no tree")
}
t.Cleanup(cTree.Close)

if diff := FirstDivergenceDumpV1(goTree.RootNode(), goLang, cTree.RootNode()); diff != nil {
t.Fatalf("size=%d locked-C parity diverged: %+v", size, *diff)
}
t.Logf("size=%d locked-C parity passed", size)
})
}
}

func sizeLabel(size int) string {
if size == benchfixtures.Issue454CFixtureBytes {
return "137KiB"
}
return strconv.Itoa(size) + "B"
}
30 changes: 26 additions & 4 deletions parser_recover_c.go
Original file line number Diff line number Diff line change
Expand Up @@ -4074,6 +4074,21 @@ func (p *Parser) cAppendVisibleSplice(dst []*Node, n *Node) []*Node {
return dst
}

func (p *Parser) cAppendVisibleSpliceWithFields(scratch *reduceBuildScratch, n *Node) {
if p == nil || scratch == nil || n == nil {
return
}
if n.symbol == errorSymbol || n.isMissing() || p.cSymbolVisible(n.symbol) {
scratch.appendNode(n)
return
}
if hiddenTreeHasFieldIDs(n) {
appendFlattenedHiddenChildrenWithFieldScratch(scratch, n, p.language.SymbolMetadata, nil)
return
}
appendFlattenedHiddenChildrenToScratch(scratch, n, p.language.SymbolMetadata, nil)
}

func (p *Parser) cAppendVisibleSpliceUntil(dst []*Node, n *Node, limit int) ([]*Node, bool) {
if n == nil {
return dst, true
Expand Down Expand Up @@ -4162,7 +4177,8 @@ func (p *Parser) cRecoverToState(v *glrStack, depth int, goal StateID, arena *no
// open ERROR node's children) and splice invisible nodes the way the
// engine's reduce does. The raw popped extent pins the ERROR span (C
// error regions cover invisible subtrees too).
children := make([]*Node, 0, len(wrapped)+2)
splice := reduceBuildScratch{}
splice.nodes = make([]*Node, 0, len(wrapped)+2)
openErr := (*cRecoverState)(nil)
if v.cRec != nil {
openErr = v.cRec
Expand All @@ -4175,14 +4191,17 @@ func (p *Parser) cRecoverToState(v *glrStack, depth int, goal StateID, arena *no
rawLast = n
if openErr != nil && n == openErr.openErr {
// Open-region children were visible-spliced at absorb time.
children = append(children, n.children...)
for _, child := range n.children {
splice.appendNode(child)
}
continue
}
// C parity: popped closed subtrees (ERROR carriers included) keep
// their identity inside the new ERROR; only invisible subtrees
// flatten.
children = p.cAppendVisibleSplice(children, n)
p.cAppendVisibleSpliceWithFields(&splice, n)
}
children, fieldIDs, fieldSources := materializeReduceChildrenFromScratch(&splice, arena)

fork := v.cloneWithScratch(gssScratch)
fork.cRec = nil
Expand Down Expand Up @@ -4215,6 +4234,7 @@ func (p *Parser) cRecoverToState(v *glrStack, depth int, goal StateID, arena *no

if rawFirst != nil {
errNode := p.newRecoveryParentNodeInArena(arena, errorSymbol, true, children, 0)
errNode.setFieldMetadata(fieldIDs, fieldSources)
cSetNodeSpan(errNode, rawFirst.startByte, rawLast.endByte, rawFirst.startPoint, rawLast.endPoint)
errNode.setHasError(true)
errNode.setExtra(true)
Expand Down Expand Up @@ -4277,7 +4297,9 @@ func (p *Parser) cAbsorbTokenIntoError(v *glrStack, tok Token, nodeCount *int, a
if leafVisible {
leaf = newLeafNodeInArena(arena, tok.Symbol, tok.Symbol == errorSymbol || p.isNamedSymbol(tok.Symbol),
tok.StartByte, tok.EndByte, tok.StartPoint, tok.EndPoint)
leaf.setHasError(true)
if p.language == nil || p.language.Name != "c" {
leaf.setHasError(true)
}
// C: if the token shifts as extra in state 1, mark it extra so it is
// not counted in error cost calculations.
if idx := p.lookupActionIndex(1, tok.Symbol); idx != 0 && int(idx) < len(p.language.ParseActions) {
Expand Down
Loading