owl-basic 0.6.0__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.
- owl_basic-0.6.0/LICENSE +21 -0
- owl_basic-0.6.0/PKG-INFO +37 -0
- owl_basic-0.6.0/README.md +13 -0
- owl_basic-0.6.0/THIRD-PARTY-NOTICES.md +57 -0
- owl_basic-0.6.0/pyproject.toml +76 -0
- owl_basic-0.6.0/setup.cfg +4 -0
- owl_basic-0.6.0/src/owl_basic/__init__.py +3 -0
- owl_basic-0.6.0/src/owl_basic/algorithms.py +29 -0
- owl_basic-0.6.0/src/owl_basic/ast_utils.py +204 -0
- owl_basic-0.6.0/src/owl_basic/basic_visitor.py +55 -0
- owl_basic-0.6.0/src/owl_basic/cfg_vertex.py +65 -0
- owl_basic-0.6.0/src/owl_basic/codegen/__init__.py +0 -0
- owl_basic-0.6.0/src/owl_basic/codegen/clr/__init__.py +0 -0
- owl_basic-0.6.0/src/owl_basic/codegen/clr/cil_visitor.py +1296 -0
- owl_basic-0.6.0/src/owl_basic/codegen/clr/cts.py +56 -0
- owl_basic-0.6.0/src/owl_basic/codegen/clr/emitters.py +94 -0
- owl_basic-0.6.0/src/owl_basic/codegen/clr/generate.py +539 -0
- owl_basic-0.6.0/src/owl_basic/correlation_visitor.py +119 -0
- owl_basic-0.6.0/src/owl_basic/data_visitor.py +62 -0
- owl_basic-0.6.0/src/owl_basic/decoder.py +339 -0
- owl_basic-0.6.0/src/owl_basic/errors.py +22 -0
- owl_basic-0.6.0/src/owl_basic/flow/__init__.py +17 -0
- owl_basic-0.6.0/src/owl_basic/flow/basic_block.py +34 -0
- owl_basic-0.6.0/src/owl_basic/flow/basic_block_identifier.py +66 -0
- owl_basic-0.6.0/src/owl_basic/flow/basic_block_orderer.py +29 -0
- owl_basic-0.6.0/src/owl_basic/flow/connectors.py +19 -0
- owl_basic-0.6.0/src/owl_basic/flow/convert_sub_visitor.py +28 -0
- owl_basic-0.6.0/src/owl_basic/flow/entry_point_locator.py +55 -0
- owl_basic-0.6.0/src/owl_basic/flow/entry_point_visitor.py +48 -0
- owl_basic-0.6.0/src/owl_basic/flow/flow_analysis.py +56 -0
- owl_basic-0.6.0/src/owl_basic/flow/flow_graph_creator.py +14 -0
- owl_basic-0.6.0/src/owl_basic/flow/flowgraph_visitor.py +178 -0
- owl_basic-0.6.0/src/owl_basic/flow/longjump_converter.py +20 -0
- owl_basic-0.6.0/src/owl_basic/flow/longjump_visitor.py +53 -0
- owl_basic-0.6.0/src/owl_basic/flow/subroutine_converter.py +38 -0
- owl_basic-0.6.0/src/owl_basic/flow/traversal.py +110 -0
- owl_basic-0.6.0/src/owl_basic/gml_visitor.py +151 -0
- owl_basic-0.6.0/src/owl_basic/line_mapper.py +43 -0
- owl_basic-0.6.0/src/owl_basic/line_number_visitor.py +65 -0
- owl_basic-0.6.0/src/owl_basic/main.py +381 -0
- owl_basic-0.6.0/src/owl_basic/node.py +21 -0
- owl_basic-0.6.0/src/owl_basic/options.py +22 -0
- owl_basic-0.6.0/src/owl_basic/owltyping/__init__.py +1 -0
- owl_basic-0.6.0/src/owl_basic/owltyping/function_type_inferer.py +50 -0
- owl_basic-0.6.0/src/owl_basic/owltyping/hindley_milner.py +524 -0
- owl_basic-0.6.0/src/owl_basic/owltyping/set_function_type_visitor.py +25 -0
- owl_basic-0.6.0/src/owl_basic/owltyping/type_system.py +220 -0
- owl_basic-0.6.0/src/owl_basic/owltyping/typecheck.py +60 -0
- owl_basic-0.6.0/src/owl_basic/owltyping/typecheck_visitor.py +471 -0
- owl_basic-0.6.0/src/owl_basic/parent_visitor.py +37 -0
- owl_basic-0.6.0/src/owl_basic/process.py +36 -0
- owl_basic-0.6.0/src/owl_basic/separation_visitor.py +98 -0
- owl_basic-0.6.0/src/owl_basic/sigil.py +30 -0
- owl_basic-0.6.0/src/owl_basic/simplify_visitor.py +204 -0
- owl_basic-0.6.0/src/owl_basic/singleton.py +127 -0
- owl_basic-0.6.0/src/owl_basic/source_debugging.py +124 -0
- owl_basic-0.6.0/src/owl_basic/symbol_table_visitor.py +220 -0
- owl_basic-0.6.0/src/owl_basic/symbol_tables.py +195 -0
- owl_basic-0.6.0/src/owl_basic/syntax/__init__.py +0 -0
- owl_basic-0.6.0/src/owl_basic/syntax/ast.py +1081 -0
- owl_basic-0.6.0/src/owl_basic/syntax/ast_meta.py +228 -0
- owl_basic-0.6.0/src/owl_basic/syntax/grammar.py +1972 -0
- owl_basic-0.6.0/src/owl_basic/syntax/lexer.py +943 -0
- owl_basic-0.6.0/src/owl_basic/syntax/parser.py +77 -0
- owl_basic-0.6.0/src/owl_basic/utility.py +26 -0
- owl_basic-0.6.0/src/owl_basic/visitor.py +43 -0
- owl_basic-0.6.0/src/owl_basic/xml_blocks.py +137 -0
- owl_basic-0.6.0/src/owl_basic/xml_visitor.py +101 -0
- owl_basic-0.6.0/src/owl_basic.egg-info/PKG-INFO +37 -0
- owl_basic-0.6.0/src/owl_basic.egg-info/SOURCES.txt +73 -0
- owl_basic-0.6.0/src/owl_basic.egg-info/dependency_links.txt +1 -0
- owl_basic-0.6.0/src/owl_basic.egg-info/entry_points.txt +2 -0
- owl_basic-0.6.0/src/owl_basic.egg-info/requires.txt +1 -0
- owl_basic-0.6.0/src/owl_basic.egg-info/top_level.txt +1 -0
- owl_basic-0.6.0/tests/test_parse_corpus.py +57 -0
owl_basic-0.6.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2007-2026 Robert Smallshire and OWL BASIC contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
owl_basic-0.6.0/PKG-INFO
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: owl-basic
|
|
3
|
+
Version: 0.6.0
|
|
4
|
+
Summary: A BBC BASIC compiler for the .NET CLR, with pluggable code-generation backends.
|
|
5
|
+
Author-email: Robert Smallshire <rob@sixty-north.com>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Repository, https://github.com/rob-smallshire/owl-basic
|
|
8
|
+
Project-URL: Issues, https://github.com/rob-smallshire/owl-basic/issues
|
|
9
|
+
Classifier: Development Status :: 2 - Pre-Alpha
|
|
10
|
+
Classifier: Environment :: Console
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: Operating System :: OS Independent
|
|
13
|
+
Classifier: Programming Language :: Python
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
17
|
+
Classifier: Topic :: Software Development :: Compilers
|
|
18
|
+
Requires-Python: >=3.14
|
|
19
|
+
Description-Content-Type: text/markdown
|
|
20
|
+
License-File: LICENSE
|
|
21
|
+
License-File: THIRD-PARTY-NOTICES.md
|
|
22
|
+
Requires-Dist: ply>=3.11
|
|
23
|
+
Dynamic: license-file
|
|
24
|
+
|
|
25
|
+
A BBC BASIC compiler for the .NET CLR and Mono, written in IronPython and C#.
|
|
26
|
+
|
|
27
|
+
What it does
|
|
28
|
+
============
|
|
29
|
+
|
|
30
|
+
Allows you to write BBC BASIC code and run it with a similar performance profile to C#.
|
|
31
|
+
|
|
32
|
+
Is it finished?
|
|
33
|
+
===============
|
|
34
|
+
|
|
35
|
+
No. OWL BASIC compiles some simple programs and some complex commercial programs,
|
|
36
|
+
including Acornsoft's Sphinx adventure. There are still many features to be added, bugs
|
|
37
|
+
to be fixed and improvements to be made.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
A BBC BASIC compiler for the .NET CLR and Mono, written in IronPython and C#.
|
|
2
|
+
|
|
3
|
+
What it does
|
|
4
|
+
============
|
|
5
|
+
|
|
6
|
+
Allows you to write BBC BASIC code and run it with a similar performance profile to C#.
|
|
7
|
+
|
|
8
|
+
Is it finished?
|
|
9
|
+
===============
|
|
10
|
+
|
|
11
|
+
No. OWL BASIC compiles some simple programs and some complex commercial programs,
|
|
12
|
+
including Acornsoft's Sphinx adventure. There are still many features to be added, bugs
|
|
13
|
+
to be fixed and improvements to be made.
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# Third-Party Notices
|
|
2
|
+
|
|
3
|
+
OWL BASIC is licensed under the MIT License (see `LICENSE`). It additionally
|
|
4
|
+
incorporates, or derives from, third-party material whose attribution and
|
|
5
|
+
licensing terms are preserved below. Nothing here imposes copyleft; each item
|
|
6
|
+
is compatible with OWL BASIC's permissive licensing, subject to the credit
|
|
7
|
+
being retained.
|
|
8
|
+
|
|
9
|
+
## BBC BASIC detokenizer — `src/owl_basic/decoder.py`
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
(c) 2007 Matt Godbolt.
|
|
13
|
+
Updated 2008 Ian Smallshire.
|
|
14
|
+
Original: http://xania.org/200711/bbc-basic-v-format
|
|
15
|
+
"Use however you like, as long as you put credit where credit's due."
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
The detokenizer that converts tokenized BBC BASIC programs to plain text
|
|
19
|
+
originates with Matt Godbolt and was extended by Ian Smallshire (and later
|
|
20
|
+
Robert Smallshire). It is used here under its stated terms, which require that
|
|
21
|
+
credit be preserved. Some of the token-table information was, per the original
|
|
22
|
+
header, obtained from RISC OS Open source code (see below).
|
|
23
|
+
|
|
24
|
+
## Singleton metaclass — `src/owl_basic/singleton.py`
|
|
25
|
+
|
|
26
|
+
By Gary Robinson (grobinson@transpose.com). Explicitly placed in the **public
|
|
27
|
+
domain** ("No rights reserved"). See
|
|
28
|
+
http://www.garyrobinson.net/2004/03/python_singleto.html — no obligations.
|
|
29
|
+
|
|
30
|
+
## RISC OS Open
|
|
31
|
+
|
|
32
|
+
Interface and factual information used by the compiler and runtime — BBC BASIC
|
|
33
|
+
token values, and SWI / VDU variable numbers in the OwlRuntime runtime library
|
|
34
|
+
— was informed by RISC OS Open material (https://www.riscosopen.org/), much of
|
|
35
|
+
which is published under the Apache License 2.0 / Castle shared-source terms.
|
|
36
|
+
These items are interface facts rather than copied code.
|
|
37
|
+
|
|
38
|
+
## Hindley–Milner type inference — `src/owl_basic/owltyping/hindley_milner.py`
|
|
39
|
+
|
|
40
|
+
A Python implementation by Robert Smallshire, based on the Scala code by Andrew
|
|
41
|
+
Forrest, the Perl code by Nikita Borisov, and the paper "Basic Polymorphic
|
|
42
|
+
Typechecking" by Luca Cardelli. This module is currently unused; if it is
|
|
43
|
+
retained in the compiler, the licensing of the upstream example code should be
|
|
44
|
+
confirmed (or the module replaced with a clean-room implementation).
|
|
45
|
+
|
|
46
|
+
## Acorn system font — `OwlRuntime/OwlRuntime/platform/riscos/AcornFont.cs`
|
|
47
|
+
|
|
48
|
+
The 8×8 bitmap glyph data reproduces the appearance of the Acorn / BBC system
|
|
49
|
+
font for VDU emulation. Bitmap font data of this kind derives from Acorn's
|
|
50
|
+
original ROM font. This affects only the .NET (CIL) backend's runtime library,
|
|
51
|
+
not the compiler. It may be retained with this provenance noted, or replaced
|
|
52
|
+
with a freely-licensed equivalent.
|
|
53
|
+
|
|
54
|
+
## PLY (Python Lex-Yacc)
|
|
55
|
+
|
|
56
|
+
Used as a normal dependency (not vendored). PLY is distributed under the BSD
|
|
57
|
+
License. See https://github.com/dabeaz/ply.
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "owl-basic"
|
|
7
|
+
dynamic = ["version"]
|
|
8
|
+
authors = [
|
|
9
|
+
{ name = "Robert Smallshire", email = "rob@sixty-north.com" },
|
|
10
|
+
]
|
|
11
|
+
description = "A BBC BASIC compiler for the .NET CLR, with pluggable code-generation backends."
|
|
12
|
+
readme = "README.md"
|
|
13
|
+
license = "MIT"
|
|
14
|
+
license-files = ["LICENSE", "THIRD-PARTY-NOTICES.md"]
|
|
15
|
+
requires-python = ">=3.14"
|
|
16
|
+
classifiers = [
|
|
17
|
+
"Development Status :: 2 - Pre-Alpha",
|
|
18
|
+
"Environment :: Console",
|
|
19
|
+
"Intended Audience :: Developers",
|
|
20
|
+
"Operating System :: OS Independent",
|
|
21
|
+
"Programming Language :: Python",
|
|
22
|
+
"Programming Language :: Python :: 3",
|
|
23
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
24
|
+
"Programming Language :: Python :: 3.14",
|
|
25
|
+
"Topic :: Software Development :: Compilers",
|
|
26
|
+
]
|
|
27
|
+
dependencies = [
|
|
28
|
+
"ply>=3.11",
|
|
29
|
+
]
|
|
30
|
+
|
|
31
|
+
[project.urls]
|
|
32
|
+
Repository = "https://github.com/rob-smallshire/owl-basic"
|
|
33
|
+
Issues = "https://github.com/rob-smallshire/owl-basic/issues"
|
|
34
|
+
|
|
35
|
+
[project.scripts]
|
|
36
|
+
owl-basic = "owl_basic.main:main"
|
|
37
|
+
|
|
38
|
+
[tool.setuptools]
|
|
39
|
+
package-dir = { "" = "src" }
|
|
40
|
+
|
|
41
|
+
[tool.setuptools.dynamic]
|
|
42
|
+
version = { attr = "owl_basic.__version__" }
|
|
43
|
+
|
|
44
|
+
[tool.setuptools.packages.find]
|
|
45
|
+
where = ["src"]
|
|
46
|
+
|
|
47
|
+
[tool.pytest.ini_options]
|
|
48
|
+
testpaths = ["tests"]
|
|
49
|
+
python_files = ["test_*.py"]
|
|
50
|
+
|
|
51
|
+
[dependency-groups]
|
|
52
|
+
test = [
|
|
53
|
+
"pytest>=8",
|
|
54
|
+
"approvaltests>=14",
|
|
55
|
+
]
|
|
56
|
+
dev = [
|
|
57
|
+
"bump-my-version>=0.28",
|
|
58
|
+
{ include-group = "test" },
|
|
59
|
+
]
|
|
60
|
+
|
|
61
|
+
[tool.bumpversion]
|
|
62
|
+
# Single source of truth for the version is owl_basic.__version__, which
|
|
63
|
+
# pyproject reads dynamically. `bump-my-version bump {patch,minor,major}`
|
|
64
|
+
# rewrites it, commits, and tags v{new_version}; pushing that tag triggers
|
|
65
|
+
# release.yml.
|
|
66
|
+
current_version = "0.6.0"
|
|
67
|
+
parse = "(?P<major>\\d+)\\.(?P<minor>\\d+)\\.(?P<patch>\\d+)"
|
|
68
|
+
serialize = ["{major}.{minor}.{patch}"]
|
|
69
|
+
commit = true
|
|
70
|
+
tag = true
|
|
71
|
+
message = "Bump version: {current_version} → {new_version}"
|
|
72
|
+
tag_name = "v{new_version}"
|
|
73
|
+
tag_message = "Bump version: {current_version} → {new_version}"
|
|
74
|
+
files = [
|
|
75
|
+
{ filename = "src/owl_basic/__init__.py" },
|
|
76
|
+
]
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
def all_equal(vals):
|
|
2
|
+
'''
|
|
3
|
+
Check if all elements of a list are equal.
|
|
4
|
+
:param vals: a sequence of items
|
|
5
|
+
'''
|
|
6
|
+
if vals:
|
|
7
|
+
i = iter(vals)
|
|
8
|
+
first = i.next()
|
|
9
|
+
for item in i:
|
|
10
|
+
if first != item:
|
|
11
|
+
return False
|
|
12
|
+
return True
|
|
13
|
+
|
|
14
|
+
def representative(s):
|
|
15
|
+
'''
|
|
16
|
+
Return an arbitrary value from the set s
|
|
17
|
+
:param s: A set
|
|
18
|
+
:returns: A representative value from s
|
|
19
|
+
'''
|
|
20
|
+
return iter(s).next()
|
|
21
|
+
|
|
22
|
+
def all_indices(string, sub, listindex=[], offset=0):
|
|
23
|
+
# call as l = allindices(string, sub)
|
|
24
|
+
# http://code.activestate.com/recipes/499314-find-all-indices-of-a-substring-in-a-given-string/
|
|
25
|
+
i = string.find(sub, offset)
|
|
26
|
+
while i >= 0:
|
|
27
|
+
listindex.append(i)
|
|
28
|
+
i = string.find(sub, i + 1)
|
|
29
|
+
return listindex
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from owl_basic import errors
|
|
3
|
+
from owl_basic.utility import camelCaseToUnderscores
|
|
4
|
+
|
|
5
|
+
def elideNode(node, liftFormalTypes=False):
|
|
6
|
+
"""
|
|
7
|
+
Removes a node from the AST, assigning the contents of its only attribute
|
|
8
|
+
attribute to the owning attribute, thereby simplifying the AST structure. If
|
|
9
|
+
liftFormalTypes is true, the formal type of the child is propagates to the
|
|
10
|
+
new owner of the data.
|
|
11
|
+
"""
|
|
12
|
+
# TODO: Refactor! D.R.Y.
|
|
13
|
+
assert len(node.child_infos) == 1
|
|
14
|
+
#print node
|
|
15
|
+
#print node.child_infos
|
|
16
|
+
if isinstance(node.child_infos.values()[0], list):
|
|
17
|
+
prop = node.child_infos.keys()[0] # TODO: Rename list_property
|
|
18
|
+
#print prop
|
|
19
|
+
|
|
20
|
+
for item in getattr(node, prop):
|
|
21
|
+
if item is not None:
|
|
22
|
+
item.parent = node.parent
|
|
23
|
+
item.parent_property = node.parent_property
|
|
24
|
+
# Note: item.parent_index remains unchanged
|
|
25
|
+
else:
|
|
26
|
+
prop = node.child_infos.keys()[0]
|
|
27
|
+
assert not isinstance(prop, list)
|
|
28
|
+
item = getattr(node, prop)
|
|
29
|
+
if item is not None:
|
|
30
|
+
item.parent = node.parent
|
|
31
|
+
item.parent_property = node.parent_property
|
|
32
|
+
# Note: item.parent_index remains unchanged
|
|
33
|
+
assert hasattr(node.parent, node.parent_property)
|
|
34
|
+
if liftFormalTypes:
|
|
35
|
+
node.parent.child_infos[camelCaseToUnderscores(node.parent_property)] = node.child_infos[prop]
|
|
36
|
+
node.parent.setProperty(getattr(node, prop), node.parent_property)
|
|
37
|
+
|
|
38
|
+
def findFollowingStatement(statement):
|
|
39
|
+
"""
|
|
40
|
+
Given a statement, locates the following statement or None
|
|
41
|
+
"""
|
|
42
|
+
if statement.parent is None:
|
|
43
|
+
return None
|
|
44
|
+
|
|
45
|
+
if statement.parent_index is None:
|
|
46
|
+
return None
|
|
47
|
+
|
|
48
|
+
parent_list = getattr(statement.parent, statement.parent_property)
|
|
49
|
+
|
|
50
|
+
if isinstance(parent_list, list):
|
|
51
|
+
logging.debug("statement.parent_index = %s", statement.parent_index)
|
|
52
|
+
if statement.parent_index < (len(parent_list) - 1):
|
|
53
|
+
return parent_list[statement.parent_index + 1]
|
|
54
|
+
|
|
55
|
+
return findFollowingStatement(statement.parent)
|
|
56
|
+
|
|
57
|
+
def findRoot(node):
|
|
58
|
+
"""
|
|
59
|
+
Given an AST node find the root node of the AST.
|
|
60
|
+
"""
|
|
61
|
+
n = node
|
|
62
|
+
while n.parent is not None:
|
|
63
|
+
n = n.parent
|
|
64
|
+
return n
|
|
65
|
+
|
|
66
|
+
def findNode(node, predicate):
|
|
67
|
+
"""
|
|
68
|
+
Given an AST node, search up the tree until a node matching the
|
|
69
|
+
predicate function is found. Returns the Node or None
|
|
70
|
+
"""
|
|
71
|
+
n = node
|
|
72
|
+
while n is not None:
|
|
73
|
+
if predicate(n):
|
|
74
|
+
return n
|
|
75
|
+
n = n.parent
|
|
76
|
+
return None
|
|
77
|
+
|
|
78
|
+
def insertStatementBefore(statement, target):
|
|
79
|
+
"""
|
|
80
|
+
Insert target before statement in the AST, and correct the AST and CFG references to match
|
|
81
|
+
"""
|
|
82
|
+
# TODO: Does this need to correct incoming GOTOs or is that handled by adjusting the AST edges
|
|
83
|
+
|
|
84
|
+
if statement.parent is None:
|
|
85
|
+
errors.fatalError("Cannot insert statement before %s at line %s" % (statement, statement.lineNum))
|
|
86
|
+
|
|
87
|
+
parent_list = getattr(statement.parent, statement.parent_property)
|
|
88
|
+
|
|
89
|
+
if isinstance(parent_list, list):
|
|
90
|
+
parent_list.insert(statement.parent_index, target)
|
|
91
|
+
target.parent = statement.parent
|
|
92
|
+
target.parent_property = statement.parent_property
|
|
93
|
+
target.parent_index = statement.parent_index
|
|
94
|
+
statement.parent_index += 1
|
|
95
|
+
|
|
96
|
+
else:
|
|
97
|
+
errors.fatalError("Cannot insert statement into non-list %s at line %s" % (statement, statement.lineNum))
|
|
98
|
+
return
|
|
99
|
+
|
|
100
|
+
# Reconnect CFG
|
|
101
|
+
for prior_stmt in statement.inEdges:
|
|
102
|
+
assert statement in prior_stmt.outEdges
|
|
103
|
+
prior_stmt.outEdges.remove(statement)
|
|
104
|
+
prior_stmt.outEdges.add(target)
|
|
105
|
+
target.inEdges.add(prior_stmt)
|
|
106
|
+
|
|
107
|
+
statement.clearInEdges()
|
|
108
|
+
statement.addInEdge(target)
|
|
109
|
+
|
|
110
|
+
target.clearOutEdges()
|
|
111
|
+
target.addOutEdge(statement)
|
|
112
|
+
|
|
113
|
+
def insertStatementAfter(statement, target):
|
|
114
|
+
"""
|
|
115
|
+
Insert target after statement in the AST, and correct the AST and CFG references to match
|
|
116
|
+
"""
|
|
117
|
+
# TODO: Does this need to correct incoming GOTOs or is that handled by adjusting the AST edges
|
|
118
|
+
|
|
119
|
+
if statement.parent is None:
|
|
120
|
+
errors.fatalError("Cannot insert statement before %s at line %s" % (statement, statement.lineNum))
|
|
121
|
+
|
|
122
|
+
parent_list = getattr(statement.parent, statement.parent_property)
|
|
123
|
+
|
|
124
|
+
if isinstance(parent_list, list):
|
|
125
|
+
target_index = statement.parent_index + 1
|
|
126
|
+
parent_list.insert(target_index, target)
|
|
127
|
+
target.parent = statement.parent
|
|
128
|
+
target.parent_property = statement.parent_property
|
|
129
|
+
target.parent_index = target_index
|
|
130
|
+
|
|
131
|
+
else:
|
|
132
|
+
errors.fatalError("Cannot insert statement into non-list %s at line %s" % (statement, statement.lineNum))
|
|
133
|
+
return
|
|
134
|
+
|
|
135
|
+
# Reconnect CFG
|
|
136
|
+
for next_stmt in statement.outEdges:
|
|
137
|
+
assert statement in next_stmt.inEdges
|
|
138
|
+
next_statement.inEdges.remove(statement)
|
|
139
|
+
next_statement.inEdges.add(target)
|
|
140
|
+
target.outEdges.add(next_stmt)
|
|
141
|
+
|
|
142
|
+
statement.clearOutEdges()
|
|
143
|
+
statement.addOutEdge(target)
|
|
144
|
+
|
|
145
|
+
target.clearInEdges()
|
|
146
|
+
target.addInEdge(statement)
|
|
147
|
+
|
|
148
|
+
def removeStatement(statement):
|
|
149
|
+
"""
|
|
150
|
+
Remove the statement from the AST
|
|
151
|
+
"""
|
|
152
|
+
if statement.parent is None:
|
|
153
|
+
errors.fatalError("Cannot remove statement %s at line %s" % (statement, statement.lineNum))
|
|
154
|
+
|
|
155
|
+
# Remove from the parent list
|
|
156
|
+
parent_list = getattr(statement.parent, statement.parent_property)
|
|
157
|
+
parent_list.remove(statement)
|
|
158
|
+
|
|
159
|
+
# Reconnect CFG
|
|
160
|
+
for prior_stmt in statement.inEdges:
|
|
161
|
+
assert statement in prior_stmt.outEdges
|
|
162
|
+
prior_stmt.outEdges.remove(statement)
|
|
163
|
+
prior_stmt.outEdges.update(statement.outEdges)
|
|
164
|
+
|
|
165
|
+
for next_stmt in statement.outEdges:
|
|
166
|
+
assert statement in next_stmt.inEdges
|
|
167
|
+
next_stmt.inEdges.remove(statement)
|
|
168
|
+
next_stmt.inEdges.update(statement.inEdges)
|
|
169
|
+
|
|
170
|
+
statement.clearInEdges()
|
|
171
|
+
statement.clearOutEdges()
|
|
172
|
+
|
|
173
|
+
def replaceStatement(old, new):
|
|
174
|
+
'''
|
|
175
|
+
Replace old with new in the AST and CFG
|
|
176
|
+
'''
|
|
177
|
+
insertStatementBefore(old, new)
|
|
178
|
+
removeStatement(old)
|
|
179
|
+
|
|
180
|
+
def deParentNode(node):
|
|
181
|
+
'''
|
|
182
|
+
Disconnect a node from its parent
|
|
183
|
+
:returns: The node
|
|
184
|
+
'''
|
|
185
|
+
raise "Not implemented"
|
|
186
|
+
|
|
187
|
+
def parentNode(node, parent, parent_property):
|
|
188
|
+
'''
|
|
189
|
+
Parent a node the the given property
|
|
190
|
+
'''
|
|
191
|
+
raise "Not implemented"
|
|
192
|
+
|
|
193
|
+
def reParentnode(node, new_parent, parent_property=None):
|
|
194
|
+
'''
|
|
195
|
+
:param node: The node to be reparented
|
|
196
|
+
:param new_parent: The new parent for node
|
|
197
|
+
:paraent_property: The property of the parent to which the node will be attached. If not
|
|
198
|
+
supplied this will use the parent_property as the original parent.
|
|
199
|
+
'''
|
|
200
|
+
if parent_property is None:
|
|
201
|
+
parent_property = node.parent_property
|
|
202
|
+
|
|
203
|
+
deParentNode(node)
|
|
204
|
+
parentNode(node, new_parent, parent_property)
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
from owl_basic.visitor import Visitor
|
|
2
|
+
|
|
3
|
+
class BasicVisitor(Visitor):
|
|
4
|
+
"""
|
|
5
|
+
AST visitor for converting the AST into back into OWL BASIC.
|
|
6
|
+
"""
|
|
7
|
+
def __init__(self):
|
|
8
|
+
pass
|
|
9
|
+
|
|
10
|
+
def visitLiteralInteger(self, integer):
|
|
11
|
+
sys.stdout.write(str(integer.value))
|
|
12
|
+
|
|
13
|
+
def visitCircle(self, circle):
|
|
14
|
+
sys.stdout.write("CIRCLE ")
|
|
15
|
+
if circle.fill:
|
|
16
|
+
sys.stdout.write("FILL ")
|
|
17
|
+
self.visit(circle.xCoord)
|
|
18
|
+
sys.stdout.write(", ")
|
|
19
|
+
self.visit(circle.yCoord)
|
|
20
|
+
sys.stdout.write(", ")
|
|
21
|
+
self.visit(circle.radius)
|
|
22
|
+
sys.stdout.write('\n')
|
|
23
|
+
|
|
24
|
+
def visitMidStrFunc(self, mid_str_func):
|
|
25
|
+
sys.stdout.write("MID$(")
|
|
26
|
+
self.visit(mid_str_func.source)
|
|
27
|
+
sys.stdout.write(", ")
|
|
28
|
+
self.visit(mid_str_func.position)
|
|
29
|
+
if mid_str_func.length is not None:
|
|
30
|
+
sys.stdout.write(", ")
|
|
31
|
+
self.visit(mid_str_func.length)
|
|
32
|
+
sys.stdout.write(")")
|
|
33
|
+
|
|
34
|
+
def visitTrueFunc(self, true_func):
|
|
35
|
+
sys.stdout.write("TRUE ")
|
|
36
|
+
|
|
37
|
+
def visitAcsFunc(self, acs_func):
|
|
38
|
+
sys.stdout.write("ACS ")
|
|
39
|
+
|
|
40
|
+
def visitAdvalFunc(self, adval_func):
|
|
41
|
+
sys.stdout.write("ADVAL ")
|
|
42
|
+
sys.stdout.write(adval_func.factor)
|
|
43
|
+
|
|
44
|
+
def visitAsnFunc(self, Asn_func):
|
|
45
|
+
sys.stdout.write("ASN ")
|
|
46
|
+
|
|
47
|
+
def visitAtnFunc(self, atn_func):
|
|
48
|
+
sys.stdout.write("ATN ")
|
|
49
|
+
|
|
50
|
+
def visitStrStringFunc(self, str_string_func):
|
|
51
|
+
sys.stdout.write("STR$")
|
|
52
|
+
if str_string_func.base == 16:
|
|
53
|
+
sys.stdout.write("~")
|
|
54
|
+
self.visit(str_string_func.factor)
|
|
55
|
+
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# Control Flow Graph Node
|
|
2
|
+
|
|
3
|
+
class CfgVertex(object):
|
|
4
|
+
__counter = 0
|
|
5
|
+
|
|
6
|
+
def __init__(self):
|
|
7
|
+
self.__in_edges = set()
|
|
8
|
+
self.__out_edges = set()
|
|
9
|
+
self.__come_from_gosub_edges = set()
|
|
10
|
+
self.__loop_back_edges = set()
|
|
11
|
+
self.__loop_from_edges = set()
|
|
12
|
+
self.__entry_points = set()
|
|
13
|
+
|
|
14
|
+
CfgVertex.__counter += 1
|
|
15
|
+
self.__id = CfgVertex.__counter
|
|
16
|
+
|
|
17
|
+
self.block = None
|
|
18
|
+
|
|
19
|
+
id = property(lambda self: self.__id)
|
|
20
|
+
inEdges = property(lambda self: self.__in_edges)
|
|
21
|
+
outEdges = property(lambda self: self.__out_edges)
|
|
22
|
+
comeFromGosubEdges = property(lambda self: self.__come_from_gosub_edges)
|
|
23
|
+
loopBackEdges = property(lambda self: self.__loop_back_edges)
|
|
24
|
+
loopFromEdges = property(lambda self: self.__loop_from_edges)
|
|
25
|
+
entryPoints = property(lambda self: self.__entry_points)
|
|
26
|
+
|
|
27
|
+
def clearInEdges(self):
|
|
28
|
+
self.__in_edges = set()
|
|
29
|
+
|
|
30
|
+
def clearOutEdges(self):
|
|
31
|
+
self.__out_edges = set()
|
|
32
|
+
|
|
33
|
+
def clearComeFromGosubEdges(self):
|
|
34
|
+
self.__come_from_gosub_edges = set()
|
|
35
|
+
|
|
36
|
+
def clearLoopBackEdges(self):
|
|
37
|
+
self.__loop_back_edges = set()
|
|
38
|
+
|
|
39
|
+
def clearLoopFromEdges(self):
|
|
40
|
+
self.__loop_from_edges = set()
|
|
41
|
+
|
|
42
|
+
def clearEntryPoints(self):
|
|
43
|
+
self.__entry_points.clear()
|
|
44
|
+
|
|
45
|
+
def addInEdge(self, from_vertex):
|
|
46
|
+
self.inEdges.add(from_vertex)
|
|
47
|
+
|
|
48
|
+
def addOutEdge(self, to_vertex):
|
|
49
|
+
self.outEdges.add(to_vertex)
|
|
50
|
+
|
|
51
|
+
def addComeFromGosubEdge(self, from_vertex):
|
|
52
|
+
self.comeFromGosubEdges.add(from_vertex)
|
|
53
|
+
|
|
54
|
+
def addLoopBackEdge(self, to_vertex):
|
|
55
|
+
self.loopBackEdges.add(to_vertex)
|
|
56
|
+
|
|
57
|
+
def addLoopFromEdge(self, to_vertex):
|
|
58
|
+
self.loopFromEdges.add(to_vertex)
|
|
59
|
+
|
|
60
|
+
def addEntryPoint(self, name):
|
|
61
|
+
self.entryPoints.add(name)
|
|
62
|
+
|
|
63
|
+
inDegree = property(lambda self: len(self.inEdges) + len(self.comeFromGosubEdges) + len(self.loopFromEdges))
|
|
64
|
+
outDegree = property(lambda self: len(self.outEdges) + len(self.loopBackEdges))
|
|
65
|
+
|
|
File without changes
|
|
File without changes
|