blob: be11da9e41f0564141bc5dd6dcd578ab10dd387b [file] [log] [blame]
Akronb7e1f352025-05-16 15:45:23 +02001package parser
2
3import (
4 "encoding/json"
5 "fmt"
6 "strings"
7
8 "github.com/KorAP/KoralPipe-TermMapper2/pkg/ast"
9)
10
11// rawNode represents the raw JSON structure
12type rawNode struct {
13 Type string `json:"@type"`
14 Wrap json.RawMessage `json:"wrap,omitempty"`
15 Operands []rawNode `json:"operands,omitempty"`
16 Relation string `json:"relation,omitempty"`
17 Foundry string `json:"foundry,omitempty"`
18 Key string `json:"key,omitempty"`
19 Layer string `json:"layer,omitempty"`
20 Match string `json:"match,omitempty"`
21 Value string `json:"value,omitempty"`
22}
23
24// ParseJSON parses a JSON string into our AST representation
25func ParseJSON(data []byte) (ast.Node, error) {
26 var raw rawNode
27 if err := json.Unmarshal(data, &raw); err != nil {
28 return nil, fmt.Errorf("failed to parse JSON: %w", err)
29 }
30 return parseNode(raw)
31}
32
33// parseNode converts a raw node into an AST node
34func parseNode(raw rawNode) (ast.Node, error) {
35 switch raw.Type {
36 case "koral:token":
37 if raw.Wrap == nil {
38 return nil, fmt.Errorf("token node missing wrap field")
39 }
40 var wrapRaw rawNode
41 if err := json.Unmarshal(raw.Wrap, &wrapRaw); err != nil {
42 return nil, fmt.Errorf("failed to parse wrap: %w", err)
43 }
44 wrap, err := parseNode(wrapRaw)
45 if err != nil {
46 return nil, err
47 }
48 return &ast.Token{Wrap: wrap}, nil
49
50 case "koral:termGroup":
51 operands := make([]ast.Node, len(raw.Operands))
52 for i, op := range raw.Operands {
53 node, err := parseNode(op)
54 if err != nil {
55 return nil, err
56 }
57 operands[i] = node
58 }
59
60 relation := ast.AndRelation
61 if strings.HasSuffix(raw.Relation, "or") {
62 relation = ast.OrRelation
63 }
64
65 return &ast.TermGroup{
66 Operands: operands,
67 Relation: relation,
68 }, nil
69
70 case "koral:term":
71 match := ast.MatchEqual
72 if strings.HasSuffix(raw.Match, "ne") {
73 match = ast.MatchNotEqual
74 }
75
76 return &ast.Term{
77 Foundry: raw.Foundry,
78 Key: raw.Key,
79 Layer: raw.Layer,
80 Match: match,
81 Value: raw.Value,
82 }, nil
83
84 default:
85 return nil, fmt.Errorf("unknown node type: %s", raw.Type)
86 }
87}
88
89// SerializeToJSON converts an AST node back to JSON
90func SerializeToJSON(node ast.Node) ([]byte, error) {
91 raw := nodeToRaw(node)
92 return json.MarshalIndent(raw, "", " ")
93}
94
95// nodeToRaw converts an AST node to a raw node for JSON serialization
96func nodeToRaw(node ast.Node) rawNode {
97 switch n := node.(type) {
98 case *ast.Token:
99 return rawNode{
100 Type: "koral:token",
101 Wrap: json.RawMessage(nodeToRaw(n.Wrap).toJSON()),
102 }
103
104 case *ast.TermGroup:
105 operands := make([]rawNode, len(n.Operands))
106 for i, op := range n.Operands {
107 operands[i] = nodeToRaw(op)
108 }
109 return rawNode{
110 Type: "koral:termGroup",
111 Operands: operands,
112 Relation: "relation:" + string(n.Relation),
113 }
114
115 case *ast.Term:
116 return rawNode{
117 Type: "koral:term",
118 Foundry: n.Foundry,
119 Key: n.Key,
120 Layer: n.Layer,
121 Match: "match:" + string(n.Match),
122 Value: n.Value,
123 }
124
125 default:
126 return rawNode{}
127 }
128}
129
130// toJSON converts a raw node to JSON bytes
131func (r rawNode) toJSON() []byte {
132 data, _ := json.Marshal(r)
133 return data
134}