prefscript 1.2__tar.gz → 2.0.5__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. {prefscript-1.2 → prefscript-2.0.5}/PKG-INFO +30 -17
  2. prefscript-2.0.5/README.md +57 -0
  3. {prefscript-1.2 → prefscript-2.0.5}/pyproject.toml +22 -7
  4. prefscript-2.0.5/src/prefscript/__init__.py +2 -0
  5. prefscript-2.0.5/src/prefscript/basicfun.py +72 -0
  6. prefscript-2.0.5/src/prefscript/cantorpairs/__init__.py +2 -0
  7. {prefscript-1.2/src/cantorpairs/src → prefscript-2.0.5/src/prefscript/cantorpairs}/cp_ex.py +5 -1
  8. prefscript-2.0.5/src/prefscript/cantorpairs/cp_ex_alt.py +48 -0
  9. prefscript-2.0.5/src/prefscript/cantorpairs/src/cantorpairs/__init__.py +2 -0
  10. prefscript-1.2/src/cantorpairs/src/cantorpairs.py → prefscript-2.0.5/src/prefscript/cantorpairs/src/cantorpairs/cantorpairs_src.py +27 -32
  11. prefscript-2.0.5/src/prefscript/cantorpairs/src/cantorpairs/ensure.py +29 -0
  12. prefscript-2.0.5/src/prefscript/codegen.py +187 -0
  13. prefscript-2.0.5/src/prefscript/examples/00.prfs +1 -0
  14. prefscript-2.0.5/src/prefscript/examples/01_k_0.prfs +5 -0
  15. prefscript-2.0.5/src/prefscript/examples/02_k_2.prfs +5 -0
  16. prefscript-2.0.5/src/prefscript/examples/03_sq.prfs +5 -0
  17. prefscript-2.0.5/src/prefscript/examples/03_sq_standalone.prfs +7 -0
  18. prefscript-2.0.5/src/prefscript/examples/04_eq.prfs +4 -0
  19. prefscript-2.0.5/src/prefscript/examples/05_hw.prfs +5 -0
  20. prefscript-2.0.5/src/prefscript/examples/06_add_rec.prfs +30 -0
  21. prefscript-2.0.5/src/prefscript/fundata.py +74 -0
  22. prefscript-2.0.5/src/prefscript/gnums.py +265 -0
  23. prefscript-2.0.5/src/prefscript/parser.py +48 -0
  24. prefscript-2.0.5/src/prefscript/praprepro.py +47 -0
  25. prefscript-2.0.5/src/prefscript/prefscript.py +140 -0
  26. prefscript-2.0.5/src/prefscript/pytokr/src/pytokr/__init__.py +153 -0
  27. prefscript-2.0.5/src/prefscript/script.py +148 -0
  28. prefscript-2.0.5/src/prefscript/stdprfs/std.prfs +81 -0
  29. {prefscript-1.2 → prefscript-2.0.5}/src/prefscript.egg-info/PKG-INFO +30 -17
  30. prefscript-2.0.5/src/prefscript.egg-info/SOURCES.txt +35 -0
  31. prefscript-2.0.5/src/prefscript.egg-info/entry_points.txt +2 -0
  32. prefscript-2.0.5/src/prefscript.egg-info/requires.txt +1 -0
  33. prefscript-2.0.5/src/prefscript.egg-info/top_level.txt +1 -0
  34. prefscript-1.2/README.md +0 -44
  35. prefscript-1.2/src/cantorpairs/__init__.py +0 -1
  36. prefscript-1.2/src/fundata.py +0 -44
  37. prefscript-1.2/src/prefscript.egg-info/SOURCES.txt +0 -16
  38. prefscript-1.2/src/prefscript.egg-info/entry_points.txt +0 -2
  39. prefscript-1.2/src/prefscript.egg-info/requires.txt +0 -1
  40. prefscript-1.2/src/prefscript.egg-info/top_level.txt +0 -5
  41. prefscript-1.2/src/prefscript.py +0 -423
  42. prefscript-1.2/src/v1parser.py +0 -76
  43. {prefscript-1.2 → prefscript-2.0.5}/LICENSE +0 -0
  44. {prefscript-1.2 → prefscript-2.0.5}/setup.cfg +0 -0
  45. {prefscript-1.2/src → prefscript-2.0.5/src/prefscript}/ascii7io.py +0 -0
  46. {prefscript-1.2 → prefscript-2.0.5}/src/prefscript.egg-info/dependency_links.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: prefscript
3
- Version: 1.2
3
+ Version: 2.0.5
4
4
  Summary: Partial Recursive Functions for Scripting
5
5
  Author-email: José Luis Balcázar <jose.luis.balcazar@upc.edu>
6
6
  Project-URL: Homepage, https://github.com/balqui/prefscript
@@ -8,10 +8,10 @@ Project-URL: Bug Tracker, https://github.com/balqui/prefscript/issues
8
8
  Classifier: Programming Language :: Python :: 3
9
9
  Classifier: License :: OSI Approved :: MIT License
10
10
  Classifier: Operating System :: OS Independent
11
- Requires-Python: >=3.10
11
+ Requires-Python: >=3.12
12
12
  Description-Content-Type: text/markdown
13
13
  License-File: LICENSE
14
- Requires-Dist: pytokr>=1.0
14
+ Requires-Dist: lark
15
15
  Dynamic: license-file
16
16
 
17
17
  # PReFScript:
@@ -21,23 +21,28 @@ Author: Jose Luis Balcazar, ORCID 0000-0003-4248-4528
21
21
 
22
22
  Project started: mid Germinal 2003.
23
23
 
24
- Current version: 1.2, mid Messidor 2026.
25
-
26
24
  Copyleft: MIT License (https://en.wikipedia.org/wiki/MIT_License)
27
25
 
28
26
  A Python-based environment to explore and experiment with partial
29
27
  recursive functions; naturally doubles as a (purely functional)
30
28
  programming language, but it is not intended to be used much as such.
31
29
 
30
+ Current version: 2.0.5, late Fructidor 2026. Previous version 1.2
31
+ of mid Messidor 2026 is *incompatible*.
32
+
32
33
  ### Scripts
33
34
 
34
- In PReFScript, a script is a sequence of functions defined in terms of each
35
- other and of a few basic functions via the partial recursion rules
36
- of composition and minimization. All functions are from the
37
- natural numbers into the natural numbers and may be undefined
38
- for some inputs. In order to handle tuples or sequences of natural
39
- numbers, a Cantor-like encoding is used.
40
- The always available basic functions include:
35
+ In PReFScript, a script is a sequence of functions defined
36
+ in terms of each other and of a few basic functions via the
37
+ partial recursion rules of composition and minimization.
38
+ All functions are from the natural numbers into the natural
39
+ numbers and may be undefined for some inputs.
40
+
41
+ In order to handle tuples or sequences of natural numbers,
42
+ a Cantor-like encoding is used;
43
+ see <https://github.com/balqui/cantorpairs/blob/main/README.md>.
44
+
45
+ Specifically, the always available basic functions include:
41
46
  `k_1`, the constant 1 function;
42
47
  `id`, the identity function;
43
48
  addition and multiplication, `add` and `mul` respectively,
@@ -48,13 +53,21 @@ pair `<x.y>` and computes `max(0, x - y)` so that we always stay
48
53
  within the natural numbers; and two functions related to projections
49
54
  of Cantor-encoded sequences.
50
55
 
51
- Scripts are maintained in objects of the class PReFScript,
52
- that can be imported into your own Python program.
53
- Alternatively, a stand-alone interpreter is also provided.
54
- Thus, you have available two main ways of programming in PReFScript.
55
-
56
56
  ### Installation and ways to use PReFScript functions
57
57
 
58
+ The usual `pip`-based process should work. Differently from
59
+ previous versions, all functionality in 2.0.* is fully compatible
60
+ with a `pipx` installation. You may need to specify `--upgrade`
61
+ flags, depending on your previous installation. LLMs say that
62
+ `uv` should work as well.
63
+
64
+ The current version installs a stand-alone interpreter.
58
65
  See [doc.md](https://github.com/balqui/prefscript/blob/main/docs/doc.md).
59
66
 
67
+ *The following applied to the previous version 1.2*:
68
+ Scripts were maintained in objects of the class PReFScript,
69
+ that could be imported into your own Python program.
70
+ Thus, you had available two main ways of programming in
71
+ PReFScript. All this does not apply anymore to versions 2.0.*.
72
+
60
73
 
@@ -0,0 +1,57 @@
1
+ # PReFScript:
2
+ ## Partial Recursive Functions for Scripting
3
+
4
+ Author: Jose Luis Balcazar, ORCID 0000-0003-4248-4528
5
+
6
+ Project started: mid Germinal 2003.
7
+
8
+ Copyleft: MIT License (https://en.wikipedia.org/wiki/MIT_License)
9
+
10
+ A Python-based environment to explore and experiment with partial
11
+ recursive functions; naturally doubles as a (purely functional)
12
+ programming language, but it is not intended to be used much as such.
13
+
14
+ Current version: 2.0.5, late Fructidor 2026. Previous version 1.2
15
+ of mid Messidor 2026 is *incompatible*.
16
+
17
+ ### Scripts
18
+
19
+ In PReFScript, a script is a sequence of functions defined
20
+ in terms of each other and of a few basic functions via the
21
+ partial recursion rules of composition and minimization.
22
+ All functions are from the natural numbers into the natural
23
+ numbers and may be undefined for some inputs.
24
+
25
+ In order to handle tuples or sequences of natural numbers,
26
+ a Cantor-like encoding is used;
27
+ see <https://github.com/balqui/cantorpairs/blob/main/README.md>.
28
+
29
+ Specifically, the always available basic functions include:
30
+ `k_1`, the constant 1 function;
31
+ `id`, the identity function;
32
+ addition and multiplication, `add` and `mul` respectively,
33
+ that interpret the single number received as the Cantor encoding
34
+ of a pair `<x.y>` and compute the corresponding operation on `x` and
35
+ `y`; modified difference `diff` that receives likewise a Cantor-encoded
36
+ pair `<x.y>` and computes `max(0, x - y)` so that we always stay
37
+ within the natural numbers; and two functions related to projections
38
+ of Cantor-encoded sequences.
39
+
40
+ ### Installation and ways to use PReFScript functions
41
+
42
+ The usual `pip`-based process should work. Differently from
43
+ previous versions, all functionality in 2.0.* is fully compatible
44
+ with a `pipx` installation. You may need to specify `--upgrade`
45
+ flags, depending on your previous installation. LLMs say that
46
+ `uv` should work as well.
47
+
48
+ The current version installs a stand-alone interpreter.
49
+ See [doc.md](https://github.com/balqui/prefscript/blob/main/docs/doc.md).
50
+
51
+ *The following applied to the previous version 1.2*:
52
+ Scripts were maintained in objects of the class PReFScript,
53
+ that could be imported into your own Python program.
54
+ Thus, you had available two main ways of programming in
55
+ PReFScript. All this does not apply anymore to versions 2.0.*.
56
+
57
+
@@ -1,24 +1,39 @@
1
1
  [build-system]
2
- requires = ["setuptools >= 61.0"]
2
+ requires = ["setuptools>=68.0"]
3
3
  build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "prefscript"
7
- version = "1.2"
8
- authors = [ { name = "José Luis Balcázar", email = "jose.luis.balcazar@upc.edu" }, ]
7
+ version = "2.0.5"
8
+ authors = [
9
+ { name = "José Luis Balcázar", email = "jose.luis.balcazar@upc.edu" }
10
+ ]
9
11
  description = "Partial Recursive Functions for Scripting"
10
12
  readme = "README.md"
11
- requires-python = ">=3.10"
13
+ requires-python = ">=3.12"
12
14
  classifiers = [
13
15
  "Programming Language :: Python :: 3",
14
16
  "License :: OSI Approved :: MIT License",
15
17
  "Operating System :: OS Independent",
16
- ]
17
- dependencies = [ "pytokr>=1.0" ]
18
+ ]
19
+
20
+ dependencies = [
21
+ "lark",
22
+ ]
18
23
 
19
24
  [project.urls]
20
25
  "Homepage" = "https://github.com/balqui/prefscript"
21
26
  "Bug Tracker" = "https://github.com/balqui/prefscript/issues"
22
27
 
23
28
  [project.scripts]
24
- prefscript = "prefscript:run"
29
+ prefscript = "prefscript.prefscript:main"
30
+
31
+ [tool.setuptools.packages.find]
32
+ where = ["src"]
33
+
34
+ [tool.setuptools.package-data]
35
+ prefscript = [
36
+ "stdprfs/*.prfs",
37
+ "examples/*.prfs",
38
+ ]
39
+
@@ -0,0 +1,2 @@
1
+
2
+ # ~ from prefscript.prefscript import __version__
@@ -0,0 +1,72 @@
1
+ '''
2
+ Project started mid Germinal 2003:
3
+ PReFScript: A Partial Recursive Functions Lab
4
+
5
+ Module version early Thermidor 2026:
6
+ basicfun: class BasicFun to have everything that concerns the list
7
+ of basic functions in a single place. A dict of FunData.
8
+
9
+ Author: Jose L Balcazar, ORCID 0000-0003-4248-4528
10
+ Copyleft: MIT License (https://en.wikipedia.org/wiki/MIT_License)
11
+ '''
12
+
13
+ from . import cantorpairs as cp
14
+ from .fundata import FunData
15
+
16
+ class BasicFun(dict):
17
+ '''
18
+ Dictionary with the info required for each basic function.
19
+ '''
20
+ def __init__(self):
21
+ dict.__init__(self)
22
+
23
+ self["k_1"] = FunData(
24
+ "k_1",
25
+ "The constant 1 function",
26
+ "basic", tuple(),
27
+ "lambda x: 1", cp.dp(0, 0))
28
+
29
+ self["id"] = FunData(
30
+ "id",
31
+ "The identity function",
32
+ "basic", tuple(),
33
+ "lambda x: x", cp.dp(0, 1))
34
+
35
+ self["s_tup"] = FunData(
36
+ "s_tup",
37
+ "Single-argument version of suffix tuple",
38
+ "basic", tuple(),
39
+ "lambda x: cp.s_tup(cp.pr_L(x), cp.pr_R(x))", cp.dp(0, 2))
40
+
41
+ self["proj"] = FunData(
42
+ "proj",
43
+ "Single-argument version of projection",
44
+ "basic", tuple(),
45
+ "lambda x: cp.pr(cp.pr_L(x), cp.pr_R(x))", cp.dp(0, 3))
46
+
47
+ self["add"] = FunData(
48
+ "add",
49
+ "Addition x+y of the two components of input <x.y>",
50
+ "basic", tuple(),
51
+ "lambda x: cp.pr_L(x) + cp.pr_R(x)", cp.dp(0, 4))
52
+
53
+ self["mul"] = FunData(
54
+ "mul",
55
+ "Multiplication x*y of the two components of input <x.y>",
56
+ "basic", tuple(),
57
+ "lambda x: cp.pr_L(x) * cp.pr_R(x)", cp.dp(0, 5))
58
+
59
+ self["diff"] = FunData(
60
+ "diff",
61
+ "Modified difference max(0, x-y) of the two components of input <x.y>",
62
+ "basic", tuple(),
63
+ "lambda x: max(0, cp.pr_L(x) - cp.pr_R(x))", cp.dp(0, 6))
64
+
65
+ def showgnums(self):
66
+ for f in sorted(self, key = lambda x: cp.pr_R(self[x].index)):
67
+ i = cp.pr_R(self[f].index)
68
+ print(f"{i}: {self[f].fname}, {self[f].docst}, Goedel number <0.{i}> = {self[f].index}")
69
+
70
+ if __name__ == "__main__":
71
+ BasicFun().showgnums()
72
+
@@ -0,0 +1,2 @@
1
+ from .src.cantorpairs.cantorpairs_src import __version__, dp, pr_L, pr_R, tup_e, tup_i, s_tup, pr, seq
2
+ from .src.cantorpairs.ensure import Ensure, ensure
@@ -7,7 +7,7 @@ Ancillary functions for the Partial Recursive Functions lab.
7
7
  Examples of usage of pairing and tupling.
8
8
  '''
9
9
 
10
- import cantorpairs as cp
10
+ import src.cantorpairs as cp
11
11
 
12
12
  for i in range(4):
13
13
  for j in range(4):
@@ -35,4 +35,8 @@ while t:
35
35
  print(t, cp.pr_L(t))
36
36
  t = cp.pr_R(t)
37
37
 
38
+ cp.Ensure().that('a' == 'a', "'a' is OK")
39
+ z = 54321
40
+ print(f"Sequence {z} is {cp.seq(z)}")
41
+ cp.Ensure().that('a' == 'b', "'a' is not 'b'")
38
42
 
@@ -0,0 +1,48 @@
1
+ '''
2
+ Author: Jose L Balcazar, ORCID 0000-0003-4248-4528, april 2023 onwards
3
+ Copyleft: MIT License (https://en.wikipedia.org/wiki/MIT_License)
4
+
5
+ Ancillary functions for the Partial Recursive Functions lab.
6
+
7
+ Examples of usage of pairing and tupling.
8
+
9
+ MOVE THIS FILE ONE LEVEL UP IN THE FILE TREE BEFORE RUNNING.
10
+
11
+ Adjacent file cp_ex.py has the right import to run here.
12
+ '''
13
+
14
+ import cantorpairs as cp
15
+
16
+ for i in range(4):
17
+ for j in range(4):
18
+ print(i, j, cp.dp(i, j))
19
+
20
+ for i in range(90, 100):
21
+ print(cp.pr_L(i), cp.pr_R(i), cp.dp(cp.pr_L(i), cp.pr_R(i)), i)
22
+
23
+ t = cp.tup_e(4, 7, 56, 101)
24
+ for i in range(5):
25
+ 'last call is actually out of range'
26
+ print(cp.pr(t, i))
27
+
28
+ st = cp.s_tup(t, 2)
29
+ print(st)
30
+ for i in range(3):
31
+ print(cp.pr(st, i))
32
+
33
+ while t:
34
+ print(t, cp.pr_L(t))
35
+ t = cp.pr_R(t)
36
+
37
+ t = cp.tup_i(range(8, 16))
38
+ while t:
39
+ print(t, cp.pr_L(t))
40
+ t = cp.pr_R(t)
41
+
42
+ cp.Ensure().that('a' == 'a', "'a' is OK")
43
+ z = 54321
44
+ print(f"Sequence {z} is {cp.seq(z)}")
45
+
46
+ # ~ cp.Ensure().that('a' == 'b', "'a' is not 'b'")
47
+
48
+ cp.ensure.that(1 == 2, "no kidding...")
@@ -0,0 +1,2 @@
1
+ from .cantorpairs_src import __version__, dp, pr_L, pr_R, tup_e, tup_i, s_tup, pr, seq
2
+ from .ensure import Ensure
@@ -1,5 +1,10 @@
1
1
  '''
2
- Author: Jose L Balcazar, ORCID 0000-0003-4248-4528, april 2023 onwards
2
+ Project started: mid Germinal 2023.
3
+ Current version: 1.2, late Fructidor 2026.
4
+ Not pip-installable as of today.
5
+ See README at `https://github.com/balqui/cantorpairs`.
6
+
7
+ Author: Jose L Balcazar, ORCID 0000-0003-4248-4528
3
8
  Copyleft: MIT License (https://en.wikipedia.org/wiki/MIT_License)
4
9
 
5
10
  Ancillary functions for PReFScript, the Partial Recursive Functions lab.
@@ -9,9 +14,7 @@ adapted from `https://en.wikipedia.org/wiki/Pairing_function`
9
14
  The dotted pair is a bijection between `NxN` and `N-{0}`:
10
15
  the natural number zero is used as "nil".
11
16
 
12
- Project started: mid Germinal 2003.
13
- Current version: 0.2, early Thermidor 2024.
14
- Not pip-installable as of today. See README at `https://github.com/balqui/cantorpairs`
17
+ See files cp_ex*.py for usage examples.
15
18
 
16
19
  After each push, the following extra incantation is most likely
17
20
  necessary in the local copy of the git repo for `prefscript`:
@@ -19,41 +22,18 @@ necessary in the local copy of the git repo for `prefscript`:
19
22
  '''
20
23
 
21
24
  from functools import cache
22
- from math import isqrt
25
+ from math import isqrt # instead of math.sqrt
23
26
 
24
- __version__ = "0.3"
27
+ __version__ = "1.2"
25
28
 
26
29
  @cache
27
30
  def _isqrt(n):
28
- return isqrt(n)
29
-
30
- # ~ def _isqrt(n):
31
- # ~ '''
32
- # ~ int square root via binary search, own program
33
- # ~ because math.sqrt fails with big numbers, e.g. the
34
- # ~ decoding of dp(10, 10^17) comes out wrong.
35
- # ~ '''
36
- # ~ def rr(n, k):
37
- # ~ """
38
- # ~ Pre: k <= sqrt(n)
39
- # ~ Post: a <= sqrt(n) < b and b - a = k
40
- # ~ """
41
- # ~ if 4*k*k > n:
42
- # ~ return k, 2*k
43
- # ~ a, b = rr(n, 2*k)
44
- # ~ m = (a + b)//2 # m = a + k
45
- # ~ if m*m <= n:
46
- # ~ return m, b
47
- # ~ else:
48
- # ~ return a, m
49
- # ~ assert n >= 0
50
- # ~ if n == 0:
51
- # ~ return 0
52
- # ~ return rr(n, 1)[0]
31
+ "Formerly used to switch between various sqrt programs"
32
+ return isqrt(n)
53
33
 
54
34
  @cache
55
35
  def _unpair(z):
56
- "local sq root instead of math.sqrt"
36
+ "uses local sq root"
57
37
  assert z > 0
58
38
  w = (_isqrt(8*(z - 1) + 1) - 1)//2
59
39
  t = (w*w + w)//2
@@ -115,3 +95,18 @@ def pr(t, k):
115
95
  returns zero (meaning end of tuple) if k is too large
116
96
  '''
117
97
  return pr_L(s_tup(t, k))
98
+
99
+ def proj(t, k):
100
+ '''
101
+ projection function, alternative name
102
+ '''
103
+ return pr(t, k)
104
+
105
+ def seq(z):
106
+ "list form of the sequence encoded by z"
107
+ ls = list()
108
+ while z != 0:
109
+ ls.append(pr_L(z))
110
+ z = pr_R(z)
111
+ return ls
112
+
@@ -0,0 +1,29 @@
1
+ '''
2
+ Project started: mid Germinal 2023.
3
+ This module started: early Fructidor 2026.
4
+ Current version: 1.0.
5
+ Not pip-installable as of today.
6
+ See README at `https://github.com/balqui/cantorpairs`
7
+
8
+ Author: Jose L Balcazar, ORCID 0000-0003-4248-4528
9
+ Copyleft: MIT License (https://en.wikipedia.org/wiki/MIT_License)
10
+
11
+ Ancillary functions for PReFScript, the Partial Recursive Functions lab.
12
+
13
+ Implements a variant of "assert" that is not disabled from the command line.
14
+ See files cp_ex*.py for usage examples.
15
+
16
+ After each push, the following extra incantation is most likely
17
+ necessary in the local copy of the git repo for `prefscript`:
18
+ `git submodule update --remote`
19
+ '''
20
+
21
+ class Ensure:
22
+
23
+ class Failed(Exception): pass
24
+
25
+ def that(cls, assertion, message):
26
+ if not assertion:
27
+ raise cls.Failed(message)
28
+
29
+ ensure = Ensure()
@@ -0,0 +1,187 @@
1
+ '''
2
+ Project started mid Germinal 2003:
3
+ PReFScript: A Partial Recursive Functions Lab
4
+
5
+ Module version early Fructidor 2026:
6
+ Lark-based code generator, makes the script for PReFScript 2.0 onwards.
7
+
8
+ Author: Jose L Balcazar, ORCID 0000-0003-4248-4528
9
+ Copyleft: MIT License (https://en.wikipedia.org/wiki/MIT_
10
+ '''
11
+
12
+ from lark import Transformer, v_args
13
+ from pathlib import Path # for handling imported files
14
+
15
+ from .cantorpairs import ensure
16
+ from .fundata import FunData
17
+ from .parser import prfsparser
18
+ from .script import PReFScript # for the recursive calls on imports
19
+
20
+ # A handful of ancillary functions
21
+
22
+ def funfactgen():
23
+ "function name factory generator, get names by calling funfact"
24
+ i = 69
25
+ while True:
26
+ yield f"___{i}"
27
+ i += 1
28
+
29
+ funfact = funfactgen().__next__
30
+
31
+ def seemsfactgen(nm):
32
+ return nm.startswith('___') and nm[3:].isdigit()
33
+
34
+ FILENAMES = set() # main and imported in order to
35
+ # avoid import cycles - a bit ugly,
36
+ # consider designing some other way
37
+
38
+
39
+ @v_args(inline=True)
40
+ class ScriptMaker(Transformer):
41
+ '''
42
+ Instances of transformers traverse the AST in postorder.
43
+ They need one method for each sort of tree node, that is,
44
+ grammar label; these methods receive the transformed
45
+ subtrees and must return the transformed current node.
46
+
47
+ The v_args decorator allows the methods in the Transformer
48
+ instance to avoid the "children" tuple and refer directly
49
+ to the subtree funspec's.
50
+
51
+ ScriptMaker objects contain a local PReFScript that is
52
+ "in construction": they transform each AST 'funspec' node into
53
+ a FunData which gets added to the script, returning its name.
54
+ Imports are handled via recursive calls on a fresh script that
55
+ gets added to the script under construction afterwards.
56
+
57
+ The 'program' simply returns the finally constructed script.
58
+
59
+ Instead of inheriting the name, we set up surrogates and
60
+ leave for later the name change if convenient.
61
+ '''
62
+
63
+ def __init__(self, script, filename, import_folder = None, imported = False):
64
+ "filename must be an already resolved Path()"
65
+ super().__init__(self)
66
+ self.script = script
67
+ self.imported = imported
68
+ if import_folder is not None:
69
+ self.import_folder = Path(import_folder)
70
+ else:
71
+ self.import_folder = None
72
+ self.filename = filename
73
+ FILENAMES.add(self.filename)
74
+
75
+ def ascii_const(self, strconst):
76
+ nm = funfact()
77
+ fdat = FunData(nm, howdf = "ascii_const", defon = (strconst,))
78
+ self.script.define(fdat)
79
+ return nm
80
+
81
+ def single(self, cname):
82
+ nm = cname.value
83
+ ensure.that(not seemsfactgen(nm), f"Error: name {nm} is disallowed.")
84
+ if nm not in self.script:
85
+ self.script.define(FunData(nm))
86
+ return nm
87
+
88
+ def parenth(self, same):
89
+ return same
90
+
91
+ def comp(self, left, right):
92
+ nm = funfact()
93
+ fdat = FunData(nm, howdf = "comp", defon = (left, right))
94
+ self.script.define(fdat)
95
+ return nm
96
+
97
+ def pair(self, left, right):
98
+ nm = funfact()
99
+ fdat = FunData(nm, howdf = "pair", defon = (left, right))
100
+ self.script.define(fdat)
101
+ return nm
102
+
103
+ def mu(self, test):
104
+ nm = funfact()
105
+ fdat = FunData(nm, howdf = "mu", defon = (test,))
106
+ self.script.define(fdat)
107
+ return nm
108
+
109
+ def rec(self, recurse, base, is_base):
110
+ nm = funfact()
111
+ fdat = FunData(nm, howdf = "rec", defon = (recurse, base, is_base))
112
+ self.script.define(fdat)
113
+ return nm
114
+
115
+ def program(self, *imports_and_defuns):
116
+ return self.script
117
+
118
+ def docstring(self, *docstrings):
119
+ "They are tokens, but somehow each can be handled as string"
120
+ return ' '.join(ds.strip('"') for ds in docstrings)
121
+
122
+ def defun(self, cname, docstring, alias):
123
+ "First two cases after skipping main are functions already in the script"
124
+ nm = cname.value
125
+ if nm == "main" and self.imported:
126
+ "silently ignore it"
127
+ return ''
128
+ if seemsfactgen(alias):
129
+ "name to override"
130
+ fspec = self.script[alias]
131
+ if docstring:
132
+ ensure.that(not fspec.docst,
133
+ f"Unexpectedly found already a previous docstring in {nm}.")
134
+ fspec.docst = docstring
135
+ fspec.fname = nm
136
+ self.script.remove(alias)
137
+ elif nm in self.script:
138
+ "pending name to be completed"
139
+ ensure.that(self.script[nm].howdf == "pending",
140
+ f"Seems that you have two defs of {self.script[nm]}.")
141
+ self.script.remove(nm) # o/w defining it will fail
142
+ fspec = FunData(nm, docst = docstring,
143
+ howdf = "alias", defon = (alias,))
144
+ else:
145
+ fspec = FunData(nm, docst = docstring,
146
+ howdf = "alias", defon = (alias,))
147
+ self.script.define(fspec)
148
+ return nm
149
+
150
+ def importing(self, filename):
151
+
152
+ def attempt(candidate, filename, cnt):
153
+ "try candidate folder, careful with std.prfs"
154
+ path = (candidate / filename).resolve()
155
+ if path.exists():
156
+ ensure.that(filename != "std.prfs" or cnt == 0,
157
+ "Presence of a nonstandard std.prfs file in " +
158
+ f"path {path} is disallowed.")
159
+ return path
160
+
161
+ filename = filename.strip('"')
162
+ if not filename.endswith(".prfs"):
163
+ filename += ".prfs"
164
+
165
+ import_folders = list()
166
+ if self.import_folder is not None:
167
+ import_folders.append(self.import_folder)
168
+ import_folders.append(self.filename.parent)
169
+ import_folders.append(Path(__file__).parent / "stdprfs")
170
+
171
+ importpath = None
172
+ cnt = len(import_folders)
173
+ for candidate in import_folders:
174
+ "ordered search for the imported file"
175
+ cnt -= 1
176
+ importpath = attempt(candidate, filename, cnt)
177
+ if importpath is not None:
178
+ break
179
+ ensure.that(importpath is not None,
180
+ f"Did not find {filename} to import.")
181
+ if importpath not in FILENAMES:
182
+ FILENAMES.add(importpath)
183
+ local_ast = prfsparser(open(importpath).read())
184
+ local_scrmk = ScriptMaker(PReFScript(), importpath, imported = True)
185
+ local_scr = local_scrmk.transform(local_ast)
186
+ self.script |= local_scr
187
+ return ''
@@ -0,0 +1 @@
1
+ main: id
@@ -0,0 +1,5 @@
1
+ main: k_0
2
+ k_0: comp diff pair k_1 k_1
3
+
4
+
5
+
@@ -0,0 +1,5 @@
1
+ main: k_2
2
+ k_2: comp add pair k_1 k_1
3
+
4
+
5
+
@@ -0,0 +1,5 @@
1
+ main: sq
2
+ dupl:
3
+ "make two copies of input"
4
+ pair id id
5
+ sq: "multiply them" comp mul dupl
@@ -0,0 +1,7 @@
1
+ #! /home/balqui/.local/bin/prefscript
2
+
3
+ main: sq
4
+ dupl:
5
+ "make two copies of input"
6
+ pair id id
7
+ sq: "multiply them" comp mul dupl