prefscript 1.1__tar.gz → 1.2__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.
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: prefscript
3
- Version: 1.1
3
+ Version: 1.2
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
@@ -12,15 +12,16 @@ Requires-Python: >=3.10
12
12
  Description-Content-Type: text/markdown
13
13
  License-File: LICENSE
14
14
  Requires-Dist: pytokr>=1.0
15
+ Dynamic: license-file
15
16
 
16
17
  # PReFScript:
17
18
  ## Partial Recursive Functions for Scripting
18
19
 
19
- Author: Jose L Balcazar, ORCID 0000-0003-4248-4528
20
+ Author: Jose Luis Balcazar, ORCID 0000-0003-4248-4528
20
21
 
21
22
  Project started: mid Germinal 2003.
22
23
 
23
- Current version: 1.1, late Thermidor 2024.
24
+ Current version: 1.2, mid Messidor 2026.
24
25
 
25
26
  Copyleft: MIT License (https://en.wikipedia.org/wiki/MIT_License)
26
27
 
@@ -54,7 +55,6 @@ Thus, you have available two main ways of programming in PReFScript.
54
55
 
55
56
  ### Installation and ways to use PReFScript functions
56
57
 
57
- See [doc.md](https://github.com/balqui/prefscript/blob/main/docs/doc.md)
58
- for all the details (somewhat incomplete as of today).
58
+ See [doc.md](https://github.com/balqui/prefscript/blob/main/docs/doc.md).
59
59
 
60
60
 
@@ -1,11 +1,11 @@
1
1
  # PReFScript:
2
2
  ## Partial Recursive Functions for Scripting
3
3
 
4
- Author: Jose L Balcazar, ORCID 0000-0003-4248-4528
4
+ Author: Jose Luis Balcazar, ORCID 0000-0003-4248-4528
5
5
 
6
6
  Project started: mid Germinal 2003.
7
7
 
8
- Current version: 1.1, late Thermidor 2024.
8
+ Current version: 1.2, mid Messidor 2026.
9
9
 
10
10
  Copyleft: MIT License (https://en.wikipedia.org/wiki/MIT_License)
11
11
 
@@ -39,7 +39,6 @@ Thus, you have available two main ways of programming in PReFScript.
39
39
 
40
40
  ### Installation and ways to use PReFScript functions
41
41
 
42
- See [doc.md](https://github.com/balqui/prefscript/blob/main/docs/doc.md)
43
- for all the details (somewhat incomplete as of today).
42
+ See [doc.md](https://github.com/balqui/prefscript/blob/main/docs/doc.md).
44
43
 
45
44
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "prefscript"
7
- version = "1.1"
7
+ version = "1.2"
8
8
  authors = [ { name = "José Luis Balcázar", email = "jose.luis.balcazar@upc.edu" }, ]
9
9
  description = "Partial Recursive Functions for Scripting"
10
10
  readme = "README.md"
@@ -1,5 +1,14 @@
1
1
  '''
2
+ Project started mid Germinal 2023:
3
+ PReFScript: A Partial Recursive Functions Lab
4
+
5
+ Ancillary module, early Thermidor 2024:
2
6
  Single-integer encoding and decoding of (printable) 7-bit ASCII strings
7
+ Currently employed for versions up to 1.2, this docstring expanded
8
+ by mid Messidor 2026 with no change to code.
9
+
10
+ Author: Jose L Balcazar, ORCID 0000-0003-4248-4528
11
+ Copyleft: MIT License (https://en.wikipedia.org/wiki/MIT_License)
3
12
  '''
4
13
 
5
14
  TWO_pow_7 = 1 << 7
@@ -0,0 +1,44 @@
1
+ '''
2
+ Project started mid Germinal 2003:
3
+ PReFScript: A Partial Recursive Functions Lab
4
+
5
+ Module version mid Messidor 2026:
6
+ fundata: class FunData storing all necessary information about
7
+ one function, includes as well ancillary algorithms mu and prim_rec
8
+ (file distribution slight refactoring on the monolithic design of Thermidor 2004)
9
+
10
+ Author: Jose L Balcazar, ORCID 0000-0003-4248-4528, april 2023 onwards
11
+ Copyleft: MIT License (https://en.wikipedia.org/wiki/MIT_License)
12
+
13
+ Each function in a script has: associated Gödel number, nickname,
14
+ comments, and code (string); also, the last operation used to
15
+ construct it. Then, in a separate dict at script level (and used
16
+ as namespace for eval calls), a runnable version of the code.
17
+
18
+ Nicknames are alphanum strings not starting with a number (no surprise).
19
+ '''
20
+
21
+ import cantorpairs as cp
22
+
23
+ __version__ = "1.2"
24
+
25
+ class FunData(dict):
26
+ 'Simple class for PReFScript functions data'
27
+
28
+ def __init__(self, nick = None, comment = None, how_def = None, def_on = None):
29
+ dict.__init__(self)
30
+ self["nick"] = nick # function name
31
+ self["comment"] = comment
32
+ self["how_def"] = how_def
33
+ self["def_on"] = def_on
34
+
35
+ def __str__(self):
36
+ return self["nick"] + "\n " + self["comment"]
37
+
38
+ def how_def(self):
39
+ if self["how_def"] == "basic":
40
+ return "basic"
41
+ return self["how_def"] + ": " + ' '.join(on_what for on_what in self["def_on"])
42
+
43
+
44
+ # ~ Should add unit testing here
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: prefscript
3
- Version: 1.1
3
+ Version: 1.2
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
@@ -12,15 +12,16 @@ Requires-Python: >=3.10
12
12
  Description-Content-Type: text/markdown
13
13
  License-File: LICENSE
14
14
  Requires-Dist: pytokr>=1.0
15
+ Dynamic: license-file
15
16
 
16
17
  # PReFScript:
17
18
  ## Partial Recursive Functions for Scripting
18
19
 
19
- Author: Jose L Balcazar, ORCID 0000-0003-4248-4528
20
+ Author: Jose Luis Balcazar, ORCID 0000-0003-4248-4528
20
21
 
21
22
  Project started: mid Germinal 2003.
22
23
 
23
- Current version: 1.1, late Thermidor 2024.
24
+ Current version: 1.2, mid Messidor 2026.
24
25
 
25
26
  Copyleft: MIT License (https://en.wikipedia.org/wiki/MIT_License)
26
27
 
@@ -54,7 +55,6 @@ Thus, you have available two main ways of programming in PReFScript.
54
55
 
55
56
  ### Installation and ways to use PReFScript functions
56
57
 
57
- See [doc.md](https://github.com/balqui/prefscript/blob/main/docs/doc.md)
58
- for all the details (somewhat incomplete as of today).
58
+ See [doc.md](https://github.com/balqui/prefscript/blob/main/docs/doc.md).
59
59
 
60
60
 
@@ -2,7 +2,9 @@ LICENSE
2
2
  README.md
3
3
  pyproject.toml
4
4
  src/ascii7io.py
5
+ src/fundata.py
5
6
  src/prefscript.py
7
+ src/v1parser.py
6
8
  src/cantorpairs/__init__.py
7
9
  src/cantorpairs/src/cantorpairs.py
8
10
  src/cantorpairs/src/cp_ex.py
@@ -11,6 +13,4 @@ src/prefscript.egg-info/SOURCES.txt
11
13
  src/prefscript.egg-info/dependency_links.txt
12
14
  src/prefscript.egg-info/entry_points.txt
13
15
  src/prefscript.egg-info/requires.txt
14
- src/prefscript.egg-info/top_level.txt
15
- tests/test.py
16
- tests/test_fact.py
16
+ src/prefscript.egg-info/top_level.txt
@@ -1,3 +1,5 @@
1
1
  ascii7io
2
2
  cantorpairs
3
+ fundata
3
4
  prefscript
5
+ v1parser
@@ -1,57 +1,39 @@
1
1
  '''
2
+ Project started mid Germinal 2023:
2
3
  PReFScript: A Partial Recursive Functions Lab
3
4
 
4
- Rather: Towards a Partial Recursive Functions lab.
5
+ Module version mid Messidor 2026:
6
+ prefscript with main class PReFScript and run entrypoint only
7
+ (file distribution slight refactoring on the monolithic design of Thermidor 2024)
5
8
 
6
- Author: Jose L Balcazar, ORCID 0000-0003-4248-4528, april 2023 onwards
9
+ Author: Jose L Balcazar, ORCID 0000-0003-4248-4528
7
10
  Copyleft: MIT License (https://en.wikipedia.org/wiki/MIT_License)
8
11
 
9
- Project started: mid Germinal 2003.
10
- Current version: 0.5, mid Thermidor 2024.
11
-
12
12
  A Python-based environment to explore and experiment with partial
13
13
  recursive functions; naturally doubles as a (purely functional)
14
14
  programming language, but it is not intended to be used as such.
15
15
 
16
- Each function in a script has: associated Gödel number, nickname,
17
- comments, and code (string); also, the last operation used to
18
- construct it. Then, in a separate dict (used as namespace for
16
+ Functions are stored in FunData instances.
17
+ Then, in a separate dict (used as namespace for
19
18
  eval calls), a runnable version of the code.
20
-
21
- Nicknames are alphanum strings not starting with a number (no surprise).
22
19
  '''
23
20
 
24
21
  from collections import defaultdict as ddict
25
- from re import compile as re_compile, finditer as re_finditer
26
- from ascii7io import int2str, str2int, int2raw_str # users are not expected to need int2raw_str
27
- import cantorpairs
28
- cp = cantorpairs
22
+ from ascii7io import int2str, str2int
23
+ import cantorpairs as cp
24
+
25
+ from v1parser import Parser, SyntErr
26
+ from fundata import FunData
29
27
 
30
- __version__ = "1.1"
28
+ __version__ = "1.2"
31
29
 
32
30
  # ~ In order to omit Gödel numbers too high, around 300 decimal digits,
33
31
  # ~ LIMIT_GNUM set to 2**1000 but computed much faster via bit shift
34
32
 
35
33
  LIMIT_GNUM = 2 << 999
36
34
 
37
- class FunData(dict):
38
- 'Simple class for PReFScript functions data'
39
-
40
- def __init__(self, nick = None, comment = None, how_def = None, def_on = None):
41
- dict.__init__(self)
42
- self["nick"] = nick # function name
43
- self["comment"] = comment
44
- self["how_def"] = how_def
45
- self["def_on"] = def_on
46
-
47
- def __str__(self):
48
- return self["nick"] + "\n " + self["comment"]
49
-
50
- def how_def(self):
51
- if self["how_def"] == "basic":
52
- return "basic"
53
- return self["how_def"] + ": " + ' '.join(on_what for on_what in self["def_on"])
54
-
35
+ # ~ Ancillary functions to implement mu-linear search and parameterized
36
+ # ~ and unparameterized primitive recursion.
55
37
 
56
38
  def mu(x, test):
57
39
  "ancillary linear search function for implementing mu-minimization"
@@ -75,62 +57,19 @@ def prim_rec(is_base, base, recurse):
75
57
  return lambda x: cp.pr_L(c_of_v(x))
76
58
 
77
59
 
78
- class Parser:
79
- '''Prepare an re-based parser to be used upon reading scripts
80
- The single Parser with single parse generator is likely to mess up
81
- the recursive imports, I bet it does not work yet.
82
- '''
83
-
84
- def __init__(self):
85
- "group names require Python >= 3.11"
86
- from re import compile as re_compile, finditer as re_finditer
87
- about = r"\s*\.about(?P<about>.*)\n" # arbitrary documentation
88
- pragma = r"\s*\.pragma\s+(?P<which>\w+):?\s+(?P<what>\w+)\s*" # compilation directives
89
- importing = r"\s*\.import\s+(?P<to_import>[\w._-]+)\s*" # additional external script
90
- a7str = r'''(?P<quote>['"])(?P<a7str>.*)(?P=quote)'''
91
- startdef = r"\d+\s+define\:\s*"
92
- group1_nick = r"(?P<nick>\w+)\s+"
93
- group2_comment = r"\[\s*(?P<comment>(\w|\s|[.,:;<>=)(?!/+*-])+)\]\s+"
94
- group4_how = r"(?P<how>pair|comp|mu|compair|primrec|ascii_const)\s+"
95
- group5_on_what = r"((?P<on_what>([a-zA-Z_]\w*\s+)+)|" + a7str + ")" # nick args required not to start with a number
96
- define = (startdef +
97
- group1_nick +
98
- group2_comment +
99
- group4_how +
100
- group5_on_what)
101
- self.the_parser = re_compile(define + '|' + about + '|' + pragma + '|' + importing)
102
-
103
- def parse(self, source):
104
- for thing in re_finditer(self.the_parser, source):
105
- "can one find out non-matched portions to message the user about?"
106
- things = thing.groupdict(default = '')
107
- if about := things['about']:
108
- yield 'about', about
109
- if which := things['which']:
110
- yield 'pragma', (which, things['what'])
111
- if to_import := things['to_import']:
112
- yield 'import', to_import
113
- if nick := things['nick']:
114
- if things['how'] == "ascii_const":
115
- on_what = [things['a7str']]
116
- else:
117
- on_what = things['on_what'].split()
118
- yield "define", FunData(nick, things['comment'], things['how'], on_what)
119
-
120
-
121
- class SyntErr:
122
- "handle syntactic errors in the script - VERY PRIMITIVE for the time being"
60
+ def par_prim_rec(is_base, base, recurse):
61
+ "primitive recursion with parameters - careful, names swapped from the course notes in Spanish"
123
62
 
124
- def __init__(self):
125
- from sys import stderr
126
- self.e = stderr
127
-
128
- def report(self, nonfatal = False, info = ''):
129
- "return value to be given to the valid field / alt: fatal here and nonvalid at script"
130
- p = 'Nonf' if nonfatal else 'F'
131
- print(p + 'atal error in PReFScript:', info, sep = '\n ', file = self.e)
132
- return nonfatal
63
+ def c_of_v(z):
64
+ "create the adequate course of values, not full anymore"
65
+ x = cp.pr_R(z)
66
+ sq = 0 # empty sequence
67
+ for y in range(x + 1):
68
+ new = base(z) if is_base(y) else recurse(cp.dp(z, sq))
69
+ sq = cp.dp(new, sq)
70
+ return sq
133
71
 
72
+ return lambda x: cp.pr_L(c_of_v(x))
134
73
 
135
74
 
136
75
  class PReFScript:
@@ -138,17 +77,17 @@ class PReFScript:
138
77
  def __init__(self, store_goedel_numbers = ""):
139
78
  '''
140
79
  Dicts for storing the functions:
141
- main for the function data,
80
+ nicks to retrieve FunData from nick,
142
81
  gnums for Gödel numbers,
143
82
  pycode for Python runnable code,
144
83
  key is always nick for all of them;
145
84
  include here the basic functions;
146
85
  their implementation assumes 'import cantorpairs as cp'
147
86
  '''
148
- self.valid = True # program is correct until proven wrong
149
- self.main = dict() # RENAME some day, as I am using also 'main' for the main function to be called
87
+ self.valid = True # program is correct until proven wrong
88
+ self.nicks = dict() # maps nick to FunData which includes nick
150
89
  self.strcode = dict()
151
- self.pycode = dict()
90
+ self.pycode = dict() # doubles as 'checked' set in former check_names
152
91
  self.gnums = dict()
153
92
  self.abouts = list()
154
93
  self.pragmas = ddict(str)
@@ -177,7 +116,7 @@ class PReFScript:
177
116
  data["def_on"] = tuple()
178
117
  if self.store_gnums:
179
118
  self.gnums[nick] = cp.dp(0, num)
180
- self.main[nick] = data
119
+ self.nicks[nick] = data
181
120
  self.strcode[nick] = code
182
121
  self.pycode[nick] = eval(code, globals() | self.pycode)
183
122
 
@@ -190,10 +129,10 @@ class PReFScript:
190
129
  Gödel number printed depending on self.store_gnums and how big it is
191
130
  '''
192
131
  def list_one(nick, w_code):
193
- print("\n" + str(self.main[nick]))
132
+ print("\n" + str(self.nicks[nick]))
194
133
  if w_code:
195
134
  'print how it is defined'
196
- print(" " + self.main[nick].how_def())
135
+ print(" " + self.nicks[nick].how_def())
197
136
  if w_code == 2:
198
137
  'print also the Python code in this case only'
199
138
  print(" " + self.strcode[nick])
@@ -208,21 +147,21 @@ class PReFScript:
208
147
  if what is not None:
209
148
  list_one(what, w_code)
210
149
  else:
211
- for nick in self.main:
150
+ for nick in self.nicks:
212
151
  list_one(nick, w_code)
213
152
 
214
153
 
215
154
  def define(self, new_funct):
216
155
  'here comes a new function to add to the collection'
217
156
 
218
- if (nick := new_funct['nick']) in self.main:
157
+ if (nick := new_funct['nick']) in self.nicks:
219
158
  'repeated nick, check for consistency'
220
- if (self.main[nick]["how_def"] != new_funct['how_def'] or
221
- self.main[nick]["def_on"] != new_funct['def_on']):
159
+ if (self.nicks[nick]["how_def"] != new_funct['how_def'] or
160
+ self.nicks[nick]["def_on"] != new_funct['def_on']):
222
161
  self.valid &= self.synt_err_handler.report(nonfatal = False,
223
162
  info = f"Repeated, inconsistent definitions for function '{nick}' found.")
224
163
  else:
225
- self.main[nick] = new_funct
164
+ self.nicks[nick] = new_funct
226
165
  on_what = new_funct['def_on']
227
166
 
228
167
  if new_funct['how_def'] == "comp":
@@ -286,6 +225,21 @@ class PReFScript:
286
225
  self.valid &= self.synt_err_handler.report(nonfatal = False,
287
226
  info = f"Gödel number for '{nick}' too large, omitted.")
288
227
 
228
+ elif new_funct['how_def'] == "parprimrec":
229
+ if not self.pragmas['extended']:
230
+ self.valid &= self.synt_err_handler.report(nonfatal = True,
231
+ info = "Use of parprimrec requires '.pragma extended: True', changed.")
232
+ self.pragmas['extended'] = 'True'
233
+ self.strcode[nick] = "par_prim_rec(" + on_what[0] + ", " + on_what[1] + ", " + on_what[2] + ")"
234
+ if (self.store_gnums and on_what[1] in self.gnums and on_what[2] in self.gnums):
235
+ gnum = cp.dp(5, cp.dp(int(on_what[0]),
236
+ cp.dp(self.gnums[on_what[1]], self.gnums[on_what[2]])))
237
+ if gnum < LIMIT_GNUM:
238
+ self.gnums[nick] = gnum
239
+ else:
240
+ self.valid &= self.synt_err_handler.report(nonfatal = False,
241
+ info = f"Gödel number for '{nick}' too large, omitted.")
242
+
289
243
  else:
290
244
  "ascii_const, as no other 'how' captured by parser - kept out of the Goedel numbering for the time being"
291
245
  if not self.pragmas['extended']:
@@ -293,17 +247,18 @@ class PReFScript:
293
247
  info = "Use of ascii constants requires '.pragma extended: True', changed.")
294
248
  self.pragmas['extended'] = 'True'
295
249
  self.strcode[nick] = "lambda x: str2int( '" + on_what[0] + "' )"
250
+ # ~ self.pycode[nick] = eval(self.strcode[nick])
296
251
 
297
- self.pycode[nick] = eval(self.strcode[nick], globals() | self.pycode)
252
+ # ~ if new_funct['how_def'] != "ascii_const":
253
+ # ~ self.pycode[nick] = eval(self.strcode[nick], globals() | self.pycode)
298
254
 
299
255
 
300
256
  def to_python(self, what):
301
257
  'returns the Python-runnable version of the function'
302
258
  if what not in self.pycode:
303
- self.valid &= self.synt_err_handler.report(nonfatal = False,
304
- info = f"No Python code for function '{what}' found.")
305
- return None
306
- return self.pycode[what]
259
+ self.gen_py(what)
260
+ if self.valid:
261
+ return self.pycode[what]
307
262
 
308
263
 
309
264
  def find_script_in_file(self, filename, main):
@@ -319,12 +274,14 @@ class PReFScript:
319
274
  info = f"Imported script {filename} not found.")
320
275
 
321
276
 
322
- def load(self, filename, main = True):
277
+ def load(self, filename, main = False):
323
278
  'load in definitions from .prfs file(s) - use .import to recurse into further loading'
324
- if filename.endswith('.prfs'):
325
- self.valid &= self.synt_err_handler.report(nonfatal = True,
326
- info = f"File name {filename} NOT expected to include the '.prfs' extension.")
327
- else:
279
+ # ~ if filename.endswith('.prfs'):
280
+ # ~ self.valid &= self.synt_err_handler.report(nonfatal = True,
281
+ # ~ info = f"File name {filename} NOT expected to include the '.prfs' extension.")
282
+ # ~ else:
283
+ # ~ filename += '.prfs'
284
+ if not filename.endswith('.prfs'):
328
285
  filename += '.prfs'
329
286
  script = self.find_script_in_file(filename, main)
330
287
  if not script:
@@ -337,10 +294,17 @@ class PReFScript:
337
294
  "pragmas in main file are stored"
338
295
  self.pragmas[what[0]] = what[1]
339
296
  elif what[0] == 'extended' and what[1] == 'True':
340
- "pragmas in imported files are ignored except extended when set to True"
341
- if self.pragmas['extended'] != 'True':
342
- self.valid &= self.synt_err_handler.report(nonfatal = True,
343
- info = f"Warning: the .pragma extended declaration found in {filename} affects globally.")
297
+ '''
298
+ pragmas in imported files are ignored except extended when set to True -
299
+ v1.2: now this is done with no warning, while v1.1 would warn about it,
300
+ but it was ugly to get the warning when calling PReFScript.load from
301
+ inside the interpreter, also the message is not that useful and the
302
+ current plan is that for 2.0 onwards "extended" will be the default
303
+ and expressed in a different way
304
+ '''
305
+ # ~ if self.pragmas['extended'] != 'True':
306
+ # ~ self.valid &= self.synt_err_handler.report(nonfatal = True,
307
+ # ~ info = f"Warning: the .pragma extended declaration found in {filename} affects globally.")
344
308
  self.pragmas[what[0]] = what[1]
345
309
  if label == 'about':
346
310
  self.abouts.append('about ' + filename + ': ' + what)
@@ -371,23 +335,45 @@ class PReFScript:
371
335
  self.define(FunData(nick.strip(), comment.strip(), how.strip(), tuple(on_what.split())))
372
336
 
373
337
 
374
- def check_names(self):
375
- "checks that all function names needed to run main have been defined"
338
+ def gen_py(self, name, need = 'pragma main'):
339
+ if name not in self.pycode:
340
+ "make sure never to loop on it"
341
+ self.pycode[name] = "None"
342
+ if name in self.nicks:
343
+ if self.nicks[name]['how_def'] != "ascii_const":
344
+ "the def_on part of an ascii_const is a mere string already handled"
345
+ for nname in self.nicks[name]['def_on']:
346
+ "we need first the recursive calls"
347
+ self.gen_py(nname, name)
348
+ self.pycode[name] = eval(self.strcode[name], globals() | self.pycode)
349
+ else:
350
+ "newly found undefined name"
351
+ self.valid &= self.synt_err_handler.report(nonfatal = False,
352
+ info = f"Function '{name}' not found but needed by {need}.")
353
+ elif self.pycode[name] == "None":
354
+ "already attempted, make sure not to fall in a definition loop"
355
+ self.valid &= self.synt_err_handler.report(nonfatal = False,
356
+ info = f"Function '{name}' belongs to a disallowed definition loop.")
376
357
 
377
- def check_name(self, name, need = 'pragma main'):
378
- if name not in checked:
379
- checked.add(name)
380
- if name in self.main:
381
- if self.main[name]['how_def'] != "ascii_const":
382
- for nname in self.main[name]['def_on']:
383
- check_name(self, nname, f"'{name}'")
384
- else:
385
- "newly found undefined name"
386
- self.valid &= self.synt_err_handler.report(nonfatal = False,
387
- info = f"Function '{name}' not found but needed by {need}.")
388
358
 
389
- checked = set()
390
- check_name(self, self.pragmas['main'])
359
+ # ~ Process moved to gen_py
360
+ # ~ def check_names(self):
361
+ # ~ "checks that all function names needed to run main have been defined"
362
+
363
+ # ~ def check_name(self, name, need = 'pragma main'):
364
+ # ~ if name not in checked:
365
+ # ~ checked.add(name)
366
+ # ~ if name in self.nicks:
367
+ # ~ if self.nicks[name]['how_def'] != "ascii_const":
368
+ # ~ for nname in self.nicks[name]['def_on']:
369
+ # ~ check_name(self, nname, f"'{name}'")
370
+ # ~ else:
371
+ # ~ "newly found undefined name"
372
+ # ~ self.valid &= self.synt_err_handler.report(nonfatal = False,
373
+ # ~ info = f"Function '{name}' not found but needed by {need}.")
374
+
375
+ # ~ checked = set()
376
+ # ~ check_name(self, self.pragmas['main'])
391
377
 
392
378
 
393
379
  def run():
@@ -405,9 +391,9 @@ def run():
405
391
  action = "version", version = f'{__version__}')
406
392
  args = aparser.parse_args()
407
393
  f = PReFScript()
408
- f.load(args.filename)
394
+ f.load(args.filename, main = True)
409
395
  if f.valid:
410
- f.check_names()
396
+ f.gen_py(f.pragmas['main'])
411
397
  if f.valid:
412
398
  'run it on data from stdin according to input/output/main pragmas'
413
399
  if args.about:
@@ -425,7 +411,7 @@ def run():
425
411
  if f.pragmas["input"] in ('', "int"):
426
412
  arg = int(input())
427
413
  elif f.pragmas["input"] == "none":
428
- arg = 666 # for one
414
+ arg = 42 # for one
429
415
  elif f.pragmas["input"] == "intseq":
430
416
  arg = cp.tup_i(map(int, loop()))
431
417
 
@@ -0,0 +1,76 @@
1
+ '''
2
+ Project started mid Germinal 2003:
3
+ PReFScript: A Partial Recursive Functions Lab
4
+
5
+ Module version mid Messidor 2026:
6
+ v1parser: re-based parser for versions up to 1.2
7
+ (file distribution slight refactoring on the monolithic design of Thermidor 2004)
8
+
9
+ Author: Jose L Balcazar, ORCID 0000-0003-4248-4528, april 2023 onwards
10
+ Copyleft: MIT License (https://en.wikipedia.org/wiki/MIT_License)
11
+ '''
12
+
13
+ from re import compile as re_compile, finditer as re_finditer
14
+
15
+ from fundata import FunData
16
+
17
+ __version__ = "1.2"
18
+
19
+ class Parser:
20
+ '''Prepare an re-based parser to be used upon reading scripts
21
+ The single Parser with single parse generator is likely to mess up
22
+ the recursive imports, I bet it does not work yet.
23
+ '''
24
+
25
+ def __init__(self):
26
+ "group names require Python >= 3.11"
27
+ from re import compile as re_compile, finditer as re_finditer
28
+ about = r"\s*\.about(?P<about>.*)\n" # arbitrary documentation
29
+ pragma = r"\s*\.pragma\s+(?P<which>\w+):?\s+(?P<what>\w+)\s*" # compilation directives
30
+ importing = r"\s*\.import\s+(?P<to_import>[\w._-]+)\s*" # additional external script
31
+ a7str = r'''(?P<quote>['"])(?P<a7str>.*)(?P=quote)'''
32
+ startdef = r"\d+\s+define\:\s*"
33
+ group1_nick = r"(?P<nick>\w+)\s+"
34
+ group2_comment = r"\[\s*(?P<comment>(\w|\s|[.,:;<>=)(?!/+*-])+)\]\s+"
35
+ group4_how = r"(?P<how>pair|comp|mu|compair|primrec|ascii_const|parprimrec)\s+"
36
+ group5_on_what = r"((?P<on_what>([a-zA-Z_]\w*\s+)+)|" + a7str + ")" # nick args required not to start with a number
37
+ define = (startdef +
38
+ group1_nick +
39
+ group2_comment +
40
+ group4_how +
41
+ group5_on_what)
42
+ self.the_parser = re_compile(define + '|' + about + '|' + pragma + '|' + importing)
43
+
44
+ def parse(self, source):
45
+ for thing in re_finditer(self.the_parser, source):
46
+ "can one find out non-matched portions to message the user about?"
47
+ things = thing.groupdict(default = '')
48
+ if about := things['about']:
49
+ yield 'about', about
50
+ if which := things['which']:
51
+ yield 'pragma', (which, things['what'])
52
+ if to_import := things['to_import']:
53
+ yield 'import', to_import
54
+ if nick := things['nick']:
55
+ if things['how'] == "ascii_const":
56
+ on_what = [things['a7str']]
57
+ else:
58
+ on_what = things['on_what'].split()
59
+ yield "define", FunData(nick, things['comment'], things['how'], on_what)
60
+
61
+
62
+ class SyntErr:
63
+ "handle syntactic errors in the script - VERY PRIMITIVE for the time being"
64
+
65
+ def __init__(self):
66
+ from sys import stderr
67
+ self.e = stderr
68
+
69
+ def report(self, nonfatal = False, info = ''):
70
+ "return value to be given to the valid field / alt: fatal here and nonvalid at script"
71
+ p = 'Nonf' if nonfatal else 'F'
72
+ print(p + 'atal error in PReFScript:', info, sep = '\n ', file = self.e)
73
+ return nonfatal
74
+
75
+
76
+ # ~ Should add unit testing here
@@ -1,17 +0,0 @@
1
- # ~ import scaff.cantorpairs as cp
2
- # ~ from prefscript import PReFScript
3
- from prefscript import PReFScript, cp
4
- my_fs = PReFScript()
5
- # ~ my_fs = PReFScript("Store Gödel numbers")
6
- my_fs.load("script_sign.prfs")
7
- my_fs.list(w_code = 1)
8
- my_fs.load("script_proj.prfs")
9
- my_fs.load("script_bool.prfs")
10
- my_fs.load("script_compar.prfs")
11
- my_fs.load("script_division.prfs")
12
- my_fs.list()
13
- d = my_fs.to_python("div")
14
- print(d(cp.dp(14, 5)))
15
- print(d(cp.dp(15, 5)))
16
- my_fs.list("swap", w_code = 1)
17
- my_fs.list("sign", w_code = 2)
@@ -1,20 +0,0 @@
1
- from time import process_time
2
- from prefscript import PReFScript
3
- import scaff.cantorpairs as cp
4
-
5
- ff = PReFScript()
6
- ff.load("fact_00.prfs")
7
- f = ff.to_python("fact")
8
-
9
- def t(n):
10
- try:
11
- start = process_time()
12
- r = f(n)
13
- tm = process_time() - start
14
- except:
15
- print(f"Stopped; time: {1000*(process_time() - start):3.6f} ms")
16
- print(f"Outcome: {r}; time: {1000*(tm):3.6f} ms")
17
-
18
- t(int(input("n: ")))
19
-
20
-
File without changes
File without changes