11import json
22from pathlib import Path
3+ from typing import Any , Optional
34
5+ import strictyaml
46import yaml
57from pydantic import ValidationError
68
7- from .pdl_ast import LocationType , PDLException , Program
8- from .pdl_location_utils import get_line_map
9+ from .pdl_ast import (
10+ Block ,
11+ BlocksType ,
12+ CallBlock ,
13+ DataBlock ,
14+ FunctionBlock ,
15+ LastOfBlock ,
16+ LocationType ,
17+ ModelBlock ,
18+ PDLException ,
19+ Program ,
20+ YamlSource ,
21+ )
22+ from .pdl_ast_utils import is_block_list
23+ from .pdl_location_utils import append , get_line_map
924from .pdl_schema_error_analyzer import analyze_errors
1025
1126
@@ -25,6 +40,7 @@ def parse_str(pdl_str: str, file_name: str = "") -> tuple[Program, LocationType]
2540 loc = LocationType (path = [], file = file_name , table = line_table )
2641 try :
2742 prog = Program .model_validate (prog_yaml )
43+ set_program_location (prog , pdl_str )
2844 except ValidationError as exc :
2945 pdl_schema_file = Path (__file__ ).parent / "pdl-schema.json"
3046 with open (pdl_schema_file , "r" , encoding = "utf-8" ) as schema_fp :
@@ -35,3 +51,119 @@ def parse_str(pdl_str: str, file_name: str = "") -> tuple[Program, LocationType]
3551 errors = ["The file do not respect the schema." ]
3652 raise PDLParseError (errors ) from exc
3753 return prog , loc
54+
55+
56+ def set_program_location (prog : Program , pdl_str : str , file_name : str = "" ):
57+ loc = strictyaml .dirty_load (pdl_str )
58+ set_location (prog .root , loc )
59+
60+
61+ def set_location (
62+ pdl : Any ,
63+ loc : YamlSource ,
64+ ):
65+ if hasattr (pdl , "_pdl_yaml_src" ):
66+ pdl ._pdl_yaml_src = loc
67+ if isinstance (loc .data , dict ):
68+ for x , v in loc .items ():
69+ if hasattr (pdl , x .data ):
70+ set_location (getattr (pdl , x .data ), v )
71+ elif isinstance (pdl , list ) and isinstance (loc .data , list ):
72+ for data_i , loc_i in zip (pdl , loc ):
73+ set_location (data_i , loc_i )
74+
75+
76+ # def set_program_location(prog: Program, pdl_str: str, file_name: str = ""):
77+ # line_table = get_line_map(pdl_str)
78+ # loc = LocationType(path=[], file=file_name, table=line_table)
79+ # return Program(set_blocks_location(prog.root, loc))
80+
81+ # def set_blocks_location(
82+ # blocks: BlocksType,
83+ # loc: YAML,
84+ # ):
85+ # if is_block_list(blocks):
86+ # return [set_block_location(block, append(loc, f"[{i}]")) for i, block in enumerate(blocks)]
87+ # return set_block_location(blocks, loc)
88+
89+
90+ # def set_block_location(
91+ # block: BlocksType,
92+ # loc: LocationType,
93+ # ):
94+ # if not isinstance(block, Block):
95+ # return DataBlock(data=block, location=loc)
96+ # block = block.model_copy(update={"location": loc})
97+ # defs_loc = append(loc, "defs")
98+ # block.defs = {x: set_block_location(b, append(defs_loc, x)) for x, b in block.defs }
99+ # if block.parser is not None:
100+ # block.parser = set_parser_location(block.parser)
101+ # if block.fallback is not None:
102+ # block.fallback = set_block_location(block.fallback, append(loc, "fallback"))
103+ # match block:
104+ # case FunctionBlock():
105+ # block.returns = set_blocks_location(block.returns, append(loc, "return"))
106+ # case CallBlock():
107+ # block.args = {x: set_expr_location(expr) for x, expr in block.args.items()}
108+ # case ModelBlock():
109+ # if block.input is not None:
110+ # iter_blocks(f, block.input)
111+ # case CodeBlock():
112+ # iter_blocks(f, block.code)
113+ # case GetBlock():
114+ # pass
115+ # case DataBlock():
116+ # pass
117+ # case TextBlock():
118+ # iter_blocks(f, block.text)
119+ # case LastOfBlock():
120+ # iter_blocks(f, block.lastOf)
121+ # case ArrayBlock():
122+ # iter_blocks(f, block.array)
123+ # case ObjectBlock():
124+ # if isinstance(block.object, dict):
125+ # body = list(block.object.values())
126+ # else:
127+ # body = block.object
128+ # iter_blocks(f, body)
129+ # case MessageBlock():
130+ # iter_blocks(f, block.content)
131+ # case IfBlock():
132+ # iter_blocks(f, block.then)
133+ # if block.elses is not None:
134+ # iter_blocks(f, block.elses)
135+ # case RepeatBlock():
136+ # iter_blocks(f, block.repeat)
137+ # if block.trace is not None:
138+ # for trace in block.trace:
139+ # iter_blocks(f, trace)
140+ # case RepeatUntilBlock():
141+ # iter_blocks(f, block.repeat)
142+ # if block.trace is not None:
143+ # for trace in block.trace:
144+ # iter_blocks(f, trace)
145+ # case ForBlock():
146+ # iter_blocks(f, block.repeat)
147+ # if block.trace is not None:
148+ # for trace in block.trace:
149+ # iter_blocks(f, trace)
150+ # case ErrorBlock():
151+ # iter_blocks(f, block.program)
152+ # case ReadBlock():
153+ # pass
154+ # case IncludeBlock():
155+ # if block.trace is not None:
156+ # iter_blocks(f, block.trace)
157+ # case EmptyBlock():
158+ # pass
159+ # case _:
160+ # assert (
161+ # False
162+ # ), f"Internal error (missing case iter_block_children({type(block)}))"
163+ # match (block.parser):
164+ # case "json" | "yaml" | RegexParser():
165+ # pass
166+ # case PdlParser():
167+ # iter_blocks(f, block.parser.pdl)
168+ # if block.fallback is not None:
169+ # iter_blocks(f, block.fallback)
0 commit comments