this repo has no description

Address feedback from PR #241 (#244)

I added a function called `Token.with_source` to simplify the
repeated logic in the source extent tests, but if it's unnecessary I can
easily revert those commits.

Edit: Linking the PR for easy, future reference: #241.

authored by

Abel Sen and committed by
GitHub
84a2bf6b 5aebe04b

+101 -134
+9 -18
scrapscript.py
··· 3 3 import argparse 4 4 import base64 5 5 import code 6 + import copy 6 7 import dataclasses 7 8 import enum 8 9 import functools ··· 15 16 import urllib.request 16 17 from dataclasses import dataclass 17 18 from enum import auto 18 - from functools import reduce 19 19 from types import ModuleType 20 20 from typing import Any, Callable, Dict, Generator, Iterator, Mapping, Optional, Set, Tuple, Union 21 21 ··· 58 58 @dataclass(eq=True) 59 59 class Token: 60 60 source_extent: SourceExtent = dataclasses.field(default_factory=SourceExtent, init=False, compare=False) 61 + 62 + def with_source(self, source_extent: SourceExtent) -> Token: 63 + self.source_extent = source_extent 64 + return self 61 65 62 66 63 67 @dataclass(eq=True) ··· 213 217 214 218 def make_token(self, cls: type, *args: Any) -> Token: 215 219 result: Token = cls(*args) 216 - 217 - # Set start of token's source extent 218 - result.source_extent.start.lineno = self.current_token_source_extent.start.lineno 219 - result.source_extent.start.colno = self.current_token_source_extent.start.colno 220 - result.source_extent.start.byteno = self.current_token_source_extent.start.byteno 221 - 222 - # Set end of token's source extent 223 - result.source_extent.end.colno = self.current_token_source_extent.end.colno 224 - result.source_extent.end.lineno = self.current_token_source_extent.end.lineno 225 - result.source_extent.end.byteno = self.current_token_source_extent.end.byteno 226 - 227 - return result 220 + return result.with_source(copy.deepcopy(self.current_token_source_extent)) 228 221 229 222 def read_tokens(self) -> Generator[Token, None, None]: 230 223 while (token := self.read_token()) and not isinstance(token, EOF): ··· 568 561 MatchCase, pipe_source_extent.coalesce(expr.source_extent), expr.arg, expr.body 569 562 ) 570 563 cases = [match_case] 564 + match_function_source_extent = match_case.source_extent 571 565 while True: 572 566 try: 573 567 if tokens.peek() != Operator("|"): ··· 582 576 MatchCase, pipe_source_extent.coalesce(expr.source_extent), expr.arg, expr.body 583 577 ) 584 578 cases.append(match_case) 585 - cases_source_extents = [case_branch.source_extent for case_branch in cases] 579 + match_function_source_extent = join_source_extents(match_function_source_extent, match_case.source_extent) 586 580 return make_source_annotated_object( 587 581 MatchFunction, 588 - reduce( 589 - join_source_extents, 590 - cases_source_extents, 591 - ), 582 + match_function_source_extent, 592 583 cases, 593 584 ) 594 585 elif isinstance(token, LeftParen):
+92 -116
scrapscript_tests.py
··· 1 - import base64 2 1 import unittest 3 2 import re 4 3 from typing import Optional ··· 1201 1200 self.assertEqual(ast, Apply(Apply(Var("f"), TRUE), FALSE)) 1202 1201 1203 1202 def test_parse_int_preserves_source_extent(self) -> None: 1204 - int_lit = IntLit(1) 1205 1203 source_extent = SourceExtent( 1206 1204 start=SourceLocation(lineno=1, colno=1, byteno=0), end=SourceLocation(lineno=1, colno=1, byteno=0) 1207 1205 ) 1208 - int_lit.source_extent = source_extent 1209 - int_ast = make_source_annotated_object(Int, source_extent, 1) 1210 - self.assertTrue(parse(Peekable(iter([int_lit]))).source_extent == int_ast.source_extent) 1206 + int_lit = IntLit(1).with_source(source_extent) 1207 + self.assertEqual(parse(Peekable(iter([int_lit]))).source_extent, source_extent) 1211 1208 1212 1209 def test_parse_float_preserves_source_extent(self) -> None: 1213 - float_lit = FloatLit(3.2) 1214 1210 source_extent = SourceExtent( 1215 1211 start=SourceLocation(lineno=1, colno=1, byteno=0), end=SourceLocation(lineno=1, colno=3, byteno=2) 1216 1212 ) 1217 - float_lit.source_extent = source_extent 1218 - float_ast = make_source_annotated_object(Float, source_extent, 3.2) 1219 - self.assertTrue(parse(Peekable(iter([float_lit]))).source_extent == float_ast.source_extent) 1213 + float_lit = FloatLit(3.2).with_source(source_extent) 1214 + self.assertEqual(parse(Peekable(iter([float_lit]))).source_extent, source_extent) 1220 1215 1221 1216 def test_parse_string_preserves_source_extent(self) -> None: 1222 - string_lit = StringLit("Hello") 1223 1217 source_extent = SourceExtent( 1224 1218 start=SourceLocation(lineno=1, colno=1, byteno=0), end=SourceLocation(lineno=1, colno=7, byteno=6) 1225 1219 ) 1226 - string_lit.source_extent = source_extent 1227 - string_ast = make_source_annotated_object(String, source_extent, "Hello") 1228 - self.assertTrue(parse(Peekable(iter([string_lit]))).source_extent == string_ast.source_extent) 1220 + string_lit = StringLit("Hello").with_source(source_extent) 1221 + self.assertEqual(parse(Peekable(iter([string_lit]))).source_extent, source_extent) 1229 1222 1230 1223 def test_parse_bytes_preserves_source_extent(self) -> None: 1231 - bytes_lit = BytesLit("QUJD", 64) 1232 1224 source_extent = SourceExtent( 1233 1225 start=SourceLocation(lineno=1, colno=1, byteno=0), end=SourceLocation(lineno=1, colno=9, byteno=8) 1234 1226 ) 1235 - bytes_lit.source_extent = source_extent 1236 - bytes_ast = make_source_annotated_object(Bytes, source_extent, base64.b64decode("QUJD")) 1237 - self.assertTrue(parse(Peekable(iter([bytes_lit]))).source_extent == bytes_ast.source_extent) 1227 + bytes_lit = BytesLit("QUJD", 64).with_source(source_extent) 1228 + self.assertEqual(parse(Peekable(iter([bytes_lit]))).source_extent, source_extent) 1238 1229 1239 1230 def test_parse_var_preserves_source_extent(self) -> None: 1240 - var = Name("x") 1241 1231 source_extent = SourceExtent( 1242 1232 start=SourceLocation(lineno=1, colno=1, byteno=0), end=SourceLocation(lineno=1, colno=1, byteno=0) 1243 1233 ) 1244 - var.source_extent = source_extent 1245 - var_ast = make_source_annotated_object(Var, source_extent, "x") 1246 - self.assertTrue(parse(Peekable(iter([var]))).source_extent == var_ast.source_extent) 1234 + var = Name("x").with_source(source_extent) 1235 + self.assertEqual(parse(Peekable(iter([var]))).source_extent, source_extent) 1247 1236 1248 1237 def test_parse_hole_preserves_source_extent(self) -> None: 1249 - left_paren = LeftParen() 1250 - left_paren.source_extent = SourceExtent( 1251 - start=SourceLocation(lineno=1, colno=1, byteno=0), end=SourceLocation(lineno=1, colno=1, byteno=0) 1252 - ) 1253 - right_paren = RightParen() 1254 - right_paren.source_extent = SourceExtent( 1255 - start=SourceLocation(lineno=1, colno=2, byteno=1), end=SourceLocation(lineno=1, colno=2, byteno=1) 1238 + left_paren = LeftParen().with_source( 1239 + SourceExtent( 1240 + start=SourceLocation(lineno=1, colno=1, byteno=0), end=SourceLocation(lineno=1, colno=1, byteno=0) 1241 + ) 1256 1242 ) 1257 - hole = make_source_annotated_object( 1258 - Hole, 1243 + right_paren = RightParen().with_source( 1259 1244 SourceExtent( 1260 - start=SourceLocation(lineno=1, colno=1, byteno=0), end=SourceLocation(lineno=1, colno=2, byteno=1) 1261 - ), 1245 + start=SourceLocation(lineno=1, colno=2, byteno=1), end=SourceLocation(lineno=1, colno=2, byteno=1) 1246 + ) 1262 1247 ) 1263 - self.assertTrue(parse(Peekable(iter([left_paren, right_paren]))).source_extent == hole.source_extent) 1248 + hole_source_extent = SourceExtent( 1249 + start=SourceLocation(lineno=1, colno=1, byteno=0), end=SourceLocation(lineno=1, colno=2, byteno=1) 1250 + ) 1251 + self.assertEqual(parse(Peekable(iter([left_paren, right_paren]))).source_extent, hole_source_extent) 1264 1252 1265 1253 def test_parenthesized_expression_preserves_source_extent(self) -> None: 1266 - left_paren = LeftParen() 1267 - left_paren.source_extent = SourceExtent( 1268 - start=SourceLocation(lineno=1, colno=1, byteno=0), end=SourceLocation(lineno=1, colno=1, byteno=0) 1254 + left_paren = LeftParen().with_source( 1255 + SourceExtent( 1256 + start=SourceLocation(lineno=1, colno=1, byteno=0), end=SourceLocation(lineno=1, colno=1, byteno=0) 1257 + ) 1269 1258 ) 1270 - int_lit = IntLit(1) 1271 - int_lit.source_extent = SourceExtent( 1272 - start=SourceLocation(lineno=1, colno=2, byteno=1), end=SourceLocation(lineno=1, colno=2, byteno=1) 1259 + int_lit = IntLit(1).with_source( 1260 + SourceExtent( 1261 + start=SourceLocation(lineno=1, colno=2, byteno=1), end=SourceLocation(lineno=1, colno=2, byteno=1) 1262 + ) 1273 1263 ) 1274 - right_paren = RightParen() 1275 - right_paren.source_extent = SourceExtent( 1276 - start=SourceLocation(lineno=1, colno=3, byteno=2), end=SourceLocation(lineno=1, colno=3, byteno=2) 1264 + right_paren = RightParen().with_source( 1265 + SourceExtent( 1266 + start=SourceLocation(lineno=1, colno=3, byteno=2), end=SourceLocation(lineno=1, colno=3, byteno=2) 1267 + ) 1277 1268 ) 1278 - parenthesized_int_lit = make_source_annotated_object( 1279 - Int, 1280 - SourceExtent( 1281 - start=SourceLocation(lineno=1, colno=1, byteno=0), end=SourceLocation(lineno=1, colno=3, byteno=2) 1282 - ), 1283 - 1, 1269 + parenthesized_int_lit_source_extent = SourceExtent( 1270 + start=SourceLocation(lineno=1, colno=1, byteno=0), end=SourceLocation(lineno=1, colno=3, byteno=2) 1284 1271 ) 1285 - self.assertTrue( 1286 - parse(Peekable(iter([left_paren, int_lit, right_paren]))).source_extent 1287 - == parenthesized_int_lit.source_extent 1272 + self.assertEqual( 1273 + parse(Peekable(iter([left_paren, int_lit, right_paren]))).source_extent, parenthesized_int_lit_source_extent 1288 1274 ) 1289 1275 1290 1276 def test_parse_spread_preserves_source_extent(self) -> None: 1291 - ellipsis = Operator("...") 1292 - ellipsis.source_extent = SourceExtent( 1293 - start=SourceLocation(lineno=1, colno=1, byteno=0), end=SourceLocation(lineno=1, colno=3, byteno=2) 1277 + ellipsis = Operator("...").with_source( 1278 + SourceExtent( 1279 + start=SourceLocation(lineno=1, colno=1, byteno=0), end=SourceLocation(lineno=1, colno=3, byteno=2) 1280 + ) 1294 1281 ) 1295 - name = Name("x") 1296 - name.source_extent = SourceExtent( 1297 - start=SourceLocation(lineno=1, colno=4, byteno=3), end=SourceLocation(lineno=1, colno=4, byteno=3) 1298 - ) 1299 - spread = make_source_annotated_object( 1300 - Spread, 1282 + name = Name("x").with_source( 1301 1283 SourceExtent( 1302 - start=SourceLocation(lineno=1, colno=1, byteno=0), end=SourceLocation(lineno=1, colno=4, byteno=3) 1303 - ), 1304 - "x", 1284 + start=SourceLocation(lineno=1, colno=4, byteno=3), end=SourceLocation(lineno=1, colno=4, byteno=3) 1285 + ) 1305 1286 ) 1306 - self.assertTrue(parse(Peekable(iter([ellipsis, name]))).source_extent == spread.source_extent) 1287 + spread_source_extent = SourceExtent( 1288 + start=SourceLocation(lineno=1, colno=1, byteno=0), end=SourceLocation(lineno=1, colno=4, byteno=3) 1289 + ) 1290 + self.assertEqual(parse(Peekable(iter([ellipsis, name]))).source_extent, spread_source_extent) 1307 1291 1308 1292 def test_parse_binop_preserves_source_extent(self) -> None: 1309 - first_addend = IntLit(1) 1310 - first_addend.source_extent = SourceExtent( 1311 - start=SourceLocation(lineno=1, colno=1, byteno=0), end=SourceLocation(lineno=1, colno=1, byteno=0) 1312 - ) 1313 - operator = Operator("+") 1314 - operator.source_extent = SourceExtent( 1315 - start=SourceLocation(lineno=1, colno=3, byteno=2), end=SourceLocation(lineno=1, colno=3, byteno=2) 1293 + first_addend = IntLit(1).with_source( 1294 + SourceExtent( 1295 + start=SourceLocation(lineno=1, colno=1, byteno=0), end=SourceLocation(lineno=1, colno=1, byteno=0) 1296 + ) 1316 1297 ) 1317 - second_addend = IntLit(2) 1318 - second_addend.source_extent = SourceExtent( 1319 - start=SourceLocation(lineno=2, colno=5, byteno=4), end=SourceLocation(lineno=2, colno=5, byteno=4) 1298 + operator = Operator("+").with_source( 1299 + SourceExtent( 1300 + start=SourceLocation(lineno=1, colno=3, byteno=2), end=SourceLocation(lineno=1, colno=3, byteno=2) 1301 + ) 1320 1302 ) 1321 - first_addend_ast = make_source_annotated_object(Int, first_addend.source_extent, 1) 1322 - operator_ast = BinopKind.ADD 1323 - second_addend_ast = make_source_annotated_object(Int, second_addend.source_extent, 2) 1324 - binop = make_source_annotated_object( 1325 - Binop, 1303 + second_addend = IntLit(2).with_source( 1326 1304 SourceExtent( 1327 - start=SourceLocation(lineno=1, colno=1, byteno=0), end=SourceLocation(lineno=2, colno=5, byteno=4) 1328 - ), 1329 - operator_ast, 1330 - first_addend_ast, 1331 - second_addend_ast, 1305 + start=SourceLocation(lineno=2, colno=5, byteno=4), end=SourceLocation(lineno=2, colno=5, byteno=4) 1306 + ) 1332 1307 ) 1333 - self.assertTrue( 1334 - parse(Peekable(iter([first_addend, operator, second_addend]))).source_extent == binop.source_extent 1308 + binop_source_extent = SourceExtent( 1309 + start=SourceLocation(lineno=1, colno=1, byteno=0), end=SourceLocation(lineno=2, colno=5, byteno=4) 1310 + ) 1311 + self.assertEqual( 1312 + parse(Peekable(iter([first_addend, operator, second_addend]))).source_extent, binop_source_extent 1335 1313 ) 1336 1314 1337 1315 def test_parse_list_preserves_source_extent(self) -> None: 1338 - left_bracket = LeftBracket() 1339 - left_bracket.source_extent = SourceExtent( 1340 - start=SourceLocation(lineno=1, colno=1, byteno=0), end=SourceLocation(lineno=1, colno=1, byteno=0) 1341 - ) 1342 - one = IntLit(1) 1343 - one.source_extent = SourceExtent( 1344 - start=SourceLocation(lineno=1, colno=2, byteno=1), end=SourceLocation(lineno=1, colno=2, byteno=1) 1316 + left_bracket = LeftBracket().with_source( 1317 + SourceExtent( 1318 + start=SourceLocation(lineno=1, colno=1, byteno=0), end=SourceLocation(lineno=1, colno=1, byteno=0) 1319 + ) 1345 1320 ) 1346 - comma = Operator(",") 1347 - comma.source_extent = SourceExtent( 1348 - start=SourceLocation(lineno=1, colno=3, byteno=2), end=SourceLocation(lineno=1, colno=3, byteno=2) 1321 + one = IntLit(1).with_source( 1322 + SourceExtent( 1323 + start=SourceLocation(lineno=1, colno=2, byteno=1), end=SourceLocation(lineno=1, colno=2, byteno=1) 1324 + ) 1349 1325 ) 1350 - two = IntLit(2) 1351 - two.source_extent = SourceExtent( 1352 - start=SourceLocation(lineno=1, colno=5, byteno=4), end=SourceLocation(lineno=1, colno=5, byteno=4) 1326 + comma = Operator(",").with_source( 1327 + SourceExtent( 1328 + start=SourceLocation(lineno=1, colno=3, byteno=2), end=SourceLocation(lineno=1, colno=3, byteno=2) 1329 + ) 1353 1330 ) 1354 - right_bracket = RightBracket() 1355 - right_bracket.source_extent = SourceExtent( 1356 - start=SourceLocation(lineno=1, colno=6, byteno=5), end=SourceLocation(lineno=1, colno=6, byteno=5) 1331 + two = IntLit(2).with_source( 1332 + SourceExtent( 1333 + start=SourceLocation(lineno=1, colno=5, byteno=4), end=SourceLocation(lineno=1, colno=5, byteno=4) 1334 + ) 1357 1335 ) 1358 - one_ast = make_source_annotated_object(Int, one.source_extent, 1) 1359 - two_ast = make_source_annotated_object(Int, two.source_extent, 2) 1360 - list_ast = make_source_annotated_object( 1361 - List, 1336 + right_bracket = RightBracket().with_source( 1362 1337 SourceExtent( 1363 - start=SourceLocation(lineno=1, colno=1, byteno=0), end=SourceLocation(lineno=1, colno=6, byteno=5) 1364 - ), 1365 - [one_ast, two_ast], 1338 + start=SourceLocation(lineno=1, colno=6, byteno=5), end=SourceLocation(lineno=1, colno=6, byteno=5) 1339 + ) 1366 1340 ) 1367 - self.assertTrue( 1368 - parse(Peekable(iter([left_bracket, one, comma, two, right_bracket]))).source_extent 1369 - == list_ast.source_extent 1341 + list_source_extent = SourceExtent( 1342 + start=SourceLocation(lineno=1, colno=1, byteno=0), end=SourceLocation(lineno=1, colno=6, byteno=5) 1343 + ) 1344 + self.assertEqual( 1345 + parse(Peekable(iter([left_bracket, one, comma, two, right_bracket]))).source_extent, list_source_extent 1370 1346 ) 1371 1347 1372 1348 ··· 2620 2596 match_function_three_source_extent, 2621 2597 ] 2622 2598 2623 - self.assertTrue(outer_function.source_extent == outer_function_source_extent) 2599 + self.assertEqual(outer_function.source_extent, outer_function_source_extent) 2624 2600 self.assertTrue( 2625 2601 all( 2626 2602 match_function.source_extent == source_extent ··· 2672 2648 start=SourceLocation(lineno=4, colno=34, byteno=84), end=SourceLocation(lineno=5, colno=79, byteno=205) 2673 2649 ) 2674 2650 2675 - self.assertTrue(outer_function.source_extent == outer_function_source_extent) 2676 - self.assertTrue(arg.source_extent == arg_source_extent) 2677 - self.assertTrue(func.source_extent == func_source_extent) 2651 + self.assertEqual(outer_function.source_extent, outer_function_source_extent) 2652 + self.assertEqual(arg.source_extent, arg_source_extent) 2653 + self.assertEqual(func.source_extent, func_source_extent) 2678 2654 2679 2655 2680 2656 class ClosureOptimizeTests(unittest.TestCase):