Initial Commit
This commit is contained in:
commit
2182395310
28 changed files with 1522 additions and 0 deletions
242
.gitignore
vendored
Normal file
242
.gitignore
vendored
Normal file
|
@ -0,0 +1,242 @@
|
||||||
|
# Byte-compiled / optimized / DLL files
|
||||||
|
__pycache__/
|
||||||
|
*.py[cod]
|
||||||
|
*$py.class
|
||||||
|
|
||||||
|
# C extensions
|
||||||
|
*.so
|
||||||
|
|
||||||
|
# Distribution / packaging
|
||||||
|
.Python
|
||||||
|
build/
|
||||||
|
develop-eggs/
|
||||||
|
dist/
|
||||||
|
downloads/
|
||||||
|
eggs/
|
||||||
|
.eggs/
|
||||||
|
lib/
|
||||||
|
lib64/
|
||||||
|
parts/
|
||||||
|
sdist/
|
||||||
|
var/
|
||||||
|
wheels/
|
||||||
|
share/python-wheels/
|
||||||
|
*.egg-info/
|
||||||
|
.installed.cfg
|
||||||
|
*.egg
|
||||||
|
MANIFEST
|
||||||
|
|
||||||
|
# PyInstaller
|
||||||
|
# Usually these files are written by a python script from a template
|
||||||
|
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||||
|
*.manifest
|
||||||
|
*.spec
|
||||||
|
|
||||||
|
# Installer logs
|
||||||
|
pip-log.txt
|
||||||
|
pip-delete-this-directory.txt
|
||||||
|
|
||||||
|
# Unit test / coverage reports
|
||||||
|
htmlcov/
|
||||||
|
.tox/
|
||||||
|
.nox/
|
||||||
|
.coverage
|
||||||
|
.coverage.*
|
||||||
|
.cache
|
||||||
|
nosetests.xml
|
||||||
|
coverage.xml
|
||||||
|
*.cover
|
||||||
|
*.py,cover
|
||||||
|
.hypothesis/
|
||||||
|
.pytest_cache/
|
||||||
|
cover/
|
||||||
|
|
||||||
|
# Translations
|
||||||
|
*.mo
|
||||||
|
*.pot
|
||||||
|
|
||||||
|
# Django stuff:
|
||||||
|
*.log
|
||||||
|
local_settings.py
|
||||||
|
db.sqlite3
|
||||||
|
db.sqlite3-journal
|
||||||
|
|
||||||
|
# Flask stuff:
|
||||||
|
instance/
|
||||||
|
.webassets-cache
|
||||||
|
|
||||||
|
# Scrapy stuff:
|
||||||
|
.scrapy
|
||||||
|
|
||||||
|
# Sphinx documentation
|
||||||
|
docs/_build/
|
||||||
|
|
||||||
|
# PyBuilder
|
||||||
|
.pybuilder/
|
||||||
|
target/
|
||||||
|
|
||||||
|
# Jupyter Notebook
|
||||||
|
.ipynb_checkpoints
|
||||||
|
|
||||||
|
# IPython
|
||||||
|
profile_default/
|
||||||
|
ipython_config.py
|
||||||
|
|
||||||
|
# pyenv
|
||||||
|
# For a library or package, you might want to ignore these files since the code is
|
||||||
|
# intended to run in multiple environments; otherwise, check them in:
|
||||||
|
# .python-version
|
||||||
|
|
||||||
|
# pipenv
|
||||||
|
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
||||||
|
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
||||||
|
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
||||||
|
# install all needed dependencies.
|
||||||
|
#Pipfile.lock
|
||||||
|
|
||||||
|
# poetry
|
||||||
|
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
||||||
|
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
||||||
|
# commonly ignored for libraries.
|
||||||
|
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
||||||
|
#poetry.lock
|
||||||
|
|
||||||
|
# pdm
|
||||||
|
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
||||||
|
#pdm.lock
|
||||||
|
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
|
||||||
|
# in version control.
|
||||||
|
# https://pdm.fming.dev/#use-with-ide
|
||||||
|
.pdm.toml
|
||||||
|
|
||||||
|
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
||||||
|
__pypackages__/
|
||||||
|
|
||||||
|
# Celery stuff
|
||||||
|
celerybeat-schedule
|
||||||
|
celerybeat.pid
|
||||||
|
|
||||||
|
# SageMath parsed files
|
||||||
|
*.sage.py
|
||||||
|
|
||||||
|
# Environments
|
||||||
|
.env
|
||||||
|
.venv
|
||||||
|
env/
|
||||||
|
venv/
|
||||||
|
ENV/
|
||||||
|
env.bak/
|
||||||
|
venv.bak/
|
||||||
|
|
||||||
|
# Spyder project settings
|
||||||
|
.spyderproject
|
||||||
|
.spyproject
|
||||||
|
|
||||||
|
# Rope project settings
|
||||||
|
.ropeproject
|
||||||
|
|
||||||
|
# mkdocs documentation
|
||||||
|
/site
|
||||||
|
|
||||||
|
# mypy
|
||||||
|
.mypy_cache/
|
||||||
|
.dmypy.json
|
||||||
|
dmypy.json
|
||||||
|
|
||||||
|
# Pyre type checker
|
||||||
|
.pyre/
|
||||||
|
|
||||||
|
# pytype static type analyzer
|
||||||
|
.pytype/
|
||||||
|
|
||||||
|
# Cython debug symbols
|
||||||
|
cython_debug/
|
||||||
|
|
||||||
|
debug/
|
||||||
|
|
||||||
|
# PyCharm
|
||||||
|
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
||||||
|
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
||||||
|
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
||||||
|
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
||||||
|
#.idea/
|
||||||
|
|
||||||
|
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
|
||||||
|
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
|
||||||
|
|
||||||
|
# User-specific stuff
|
||||||
|
.idea/**/workspace.xml
|
||||||
|
.idea/**/tasks.xml
|
||||||
|
.idea/**/usage.statistics.xml
|
||||||
|
.idea/**/dictionaries
|
||||||
|
.idea/**/shelf
|
||||||
|
|
||||||
|
# AWS User-specific
|
||||||
|
.idea/**/aws.xml
|
||||||
|
|
||||||
|
# Generated files
|
||||||
|
.idea/**/contentModel.xml
|
||||||
|
|
||||||
|
# Sensitive or high-churn files
|
||||||
|
.idea/**/dataSources/
|
||||||
|
.idea/**/dataSources.ids
|
||||||
|
.idea/**/dataSources.local.xml
|
||||||
|
.idea/**/sqlDataSources.xml
|
||||||
|
.idea/**/dynamic.xml
|
||||||
|
.idea/**/uiDesigner.xml
|
||||||
|
.idea/**/dbnavigator.xml
|
||||||
|
|
||||||
|
# Gradle
|
||||||
|
.idea/**/gradle.xml
|
||||||
|
.idea/**/libraries
|
||||||
|
|
||||||
|
# Gradle and Maven with auto-import
|
||||||
|
# When using Gradle or Maven with auto-import, you should exclude module files,
|
||||||
|
# since they will be recreated, and may cause churn. Uncomment if using
|
||||||
|
# auto-import.
|
||||||
|
# .idea/artifacts
|
||||||
|
# .idea/compiler.xml
|
||||||
|
# .idea/jarRepositories.xml
|
||||||
|
# .idea/modules.xml
|
||||||
|
# .idea/*.iml
|
||||||
|
# .idea/modules
|
||||||
|
# *.iml
|
||||||
|
# *.ipr
|
||||||
|
|
||||||
|
# CMake
|
||||||
|
cmake-build-*/
|
||||||
|
|
||||||
|
# Mongo Explorer plugin
|
||||||
|
.idea/**/mongoSettings.xml
|
||||||
|
|
||||||
|
# File-based project format
|
||||||
|
*.iws
|
||||||
|
|
||||||
|
# IntelliJ
|
||||||
|
out/
|
||||||
|
|
||||||
|
# mpeltonen/sbt-idea plugin
|
||||||
|
.idea_modules/
|
||||||
|
|
||||||
|
# JIRA plugin
|
||||||
|
atlassian-ide-plugin.xml
|
||||||
|
|
||||||
|
# Cursive Clojure plugin
|
||||||
|
.idea/replstate.xml
|
||||||
|
|
||||||
|
# SonarLint plugin
|
||||||
|
.idea/sonarlint/
|
||||||
|
|
||||||
|
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||||
|
com_crashlytics_export_strings.xml
|
||||||
|
crashlytics.properties
|
||||||
|
crashlytics-build.properties
|
||||||
|
fabric.properties
|
||||||
|
|
||||||
|
# Editor-based Rest Client
|
||||||
|
.idea/httpRequests
|
||||||
|
|
||||||
|
# Android studio 3.1+ serialized cache file
|
||||||
|
.idea/caches/build_file_checksums.ser
|
||||||
|
|
||||||
|
ast_parser/test/.tmp
|
29
README.md
Normal file
29
README.md
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
# Gazprea Fuzzer
|
||||||
|
|
||||||
|
This is a hecking fuzzer. It does the thing.
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
- Python 3.11
|
||||||
|
- NumPy
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
```
|
||||||
|
usage: python -m gazprea_fuzzer.py [-h] [-b SIZE] [--seed SEED] <config_file>
|
||||||
|
|
||||||
|
Procedurally generate a test case for Gazprea
|
||||||
|
|
||||||
|
positional arguments:
|
||||||
|
config path to your configuration file
|
||||||
|
name name of the test case to generate (name.in, name.ins, name.out)
|
||||||
|
|
||||||
|
optional arguments:
|
||||||
|
-h, --help show the help message and exit
|
||||||
|
-b, --batch SIZE generate SIZE cases (fuzzer/input/nameX.in, /instream/..., /outputs/...)
|
||||||
|
--seed SEED rng seed
|
||||||
|
```
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
See the [default config file](config.yaml) for all possible options and their default values
|
||||||
|
|
0
__init__.py
Normal file
0
__init__.py
Normal file
0
ast_generator/__init__.py
Normal file
0
ast_generator/__init__.py
Normal file
338
ast_generator/ast_generator.py
Normal file
338
ast_generator/ast_generator.py
Normal file
|
@ -0,0 +1,338 @@
|
||||||
|
import json
|
||||||
|
import random
|
||||||
|
|
||||||
|
from fuzzingbook.Grammars import is_valid_grammar, convert_ebnf_grammar, Grammar
|
||||||
|
from isla.solver import ISLaSolver
|
||||||
|
|
||||||
|
# from gazprea_ast_grammar import GAZPREA_TOP_LEVEL
|
||||||
|
# import gazprea_ast_grammar
|
||||||
|
from ast_parser.ast_parser import AstParser
|
||||||
|
|
||||||
|
import xml.etree.ElementTree as ET
|
||||||
|
|
||||||
|
GAZ_VOID_TYPE = 'void'
|
||||||
|
|
||||||
|
VOID_TYPE = 'void'
|
||||||
|
GAZ_BLOCK_TAG = 'block'
|
||||||
|
GAZ_RHS_TAG = 'lhs'
|
||||||
|
GAZ_RHS_TAG = 'rhs'
|
||||||
|
GAZ_RETURN_KEY = "return_type"
|
||||||
|
VAR_NAMES = ['alsdjf', 'asldfjlks', 'qowiuut', 'qoiur', 'qwioue', 'qoyiyut', 'llkjfg', 'kdjkdjf', 'asdjkfeey',
|
||||||
|
'jdhjfjheee']
|
||||||
|
ROUTINE_NAMES = ['bees', 'beans', 'hell']
|
||||||
|
GAZ_INT_OPS = ['*', '+', '-', '/', '%']
|
||||||
|
GAZ_TYPES = ['int']
|
||||||
|
GAZ_FLOAT_KEY = 'float'
|
||||||
|
GAZ_INT_KEY = 'int'
|
||||||
|
GAZ_FUNCTION_TAG = 'function'
|
||||||
|
GAZ_PROCEDURE_TAG = 'procedure'
|
||||||
|
GAZ_OPERATOR_TAG = "operator"
|
||||||
|
GAZ_LIT_TAG = "literal"
|
||||||
|
GAZ_VAR_TAG = "variable"
|
||||||
|
GAZ_OP_KEY = "op"
|
||||||
|
GAZ_NAME_KEY = "name"
|
||||||
|
GAZ_QUALIFIER_KEY = "mut"
|
||||||
|
GAZ_VAL_KEY = "value"
|
||||||
|
GAZ_TY_KEY = "type"
|
||||||
|
ANY_TYPE = "any"
|
||||||
|
|
||||||
|
|
||||||
|
def find_variables(AST):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def set_variables(variable_names, variables):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def set_routines(routine_names, routines):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def type_check(AST, routines, variables):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class AstGenerator:
|
||||||
|
|
||||||
|
def __init__(self, grammar: Grammar, params: json):
|
||||||
|
self.void_probability = 20
|
||||||
|
self.int_low = -2 ** 30
|
||||||
|
self.int_high = 2 ** 32 - 1
|
||||||
|
self.valid_var_names = VAR_NAMES
|
||||||
|
self.max_number_of_vars = 10
|
||||||
|
self.valid_routine_names = ROUTINE_NAMES
|
||||||
|
self.max_number_of_routines = 3
|
||||||
|
self.qualifier_probability = False
|
||||||
|
self.var_qualifier_probability = None
|
||||||
|
self.const_qualifier_probability = None
|
||||||
|
for key, value in params.items():
|
||||||
|
setattr(self, key, value)
|
||||||
|
|
||||||
|
if self.var_qualifier_probability is not None and self.const_qualifier_probability is not None:
|
||||||
|
self.qualifier_probability = True
|
||||||
|
self.ast_list = []
|
||||||
|
self.functions = []
|
||||||
|
assert (is_valid_grammar(grammar))
|
||||||
|
self.grammar = grammar
|
||||||
|
|
||||||
|
def fix_missing_locations(self, AST: str) -> str:
|
||||||
|
variable_names = self.get_variable_list()
|
||||||
|
routine_names = self.get_routine_list()
|
||||||
|
|
||||||
|
routines = find_routines(AST)
|
||||||
|
variables = find_variables(AST)
|
||||||
|
|
||||||
|
set_variables(variable_names, variables) # insert types and values
|
||||||
|
set_routines(routine_names, routines) # insert types
|
||||||
|
type_check(AST, routines, variables)
|
||||||
|
|
||||||
|
|
||||||
|
def test_samples(self, grammar: Grammar, iterations: int = 10, start_symbol=None, log: bool = True):
|
||||||
|
g = convert_ebnf_grammar(grammar)
|
||||||
|
solver = ISLaSolver(g, start_symbol=start_symbol, max_number_free_instantiations=iterations)
|
||||||
|
for i in range(iterations):
|
||||||
|
tree_str = str(solver.solve())
|
||||||
|
print(tree_str)
|
||||||
|
# tree = eval(tree_str)
|
||||||
|
# print(tree)
|
||||||
|
# tree = self.fix_missing_locations(tree)
|
||||||
|
# ast = AstParser(tree, from_xml=True)
|
||||||
|
# if log:
|
||||||
|
# ast.unparse()
|
||||||
|
# code = ast.input
|
||||||
|
# print(f'{code:40} # {tree_str}')
|
||||||
|
|
||||||
|
def get_variable_list(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def populate_operator(self, operator: ET.Element, op, type):
|
||||||
|
operator.set(GAZ_OP_KEY, op)
|
||||||
|
operator.set(GAZ_TY_KEY, type)
|
||||||
|
for node in operator:
|
||||||
|
node = self.populate(node, type)
|
||||||
|
|
||||||
|
return operator
|
||||||
|
|
||||||
|
def populate_stream(self, stream: ET.Element, type):
|
||||||
|
stream.set(GAZ_TY_KEY, type)
|
||||||
|
for node in stream:
|
||||||
|
node = self.populate(node, ANY_TYPE)
|
||||||
|
|
||||||
|
return stream
|
||||||
|
|
||||||
|
def populate_literal(self, literal: ET.Element, type, value):
|
||||||
|
literal.set(GAZ_TY_KEY, type)
|
||||||
|
literal.set(GAZ_VAL_KEY, value)
|
||||||
|
return literal
|
||||||
|
|
||||||
|
def populate_variable(self, variable: ET.Element, qualifier, type, name):
|
||||||
|
variable.set(GAZ_QUALIFIER_KEY, qualifier)
|
||||||
|
variable.set(GAZ_TY_KEY, type)
|
||||||
|
variable.set(GAZ_NAME_KEY, name)
|
||||||
|
return variable
|
||||||
|
|
||||||
|
def populate_routine(self, routine: ET.Element, type, name):
|
||||||
|
routine.set(GAZ_RETURN_KEY, type)
|
||||||
|
if routine.get("name") != "main":
|
||||||
|
routine.set(GAZ_NAME_KEY, name)
|
||||||
|
|
||||||
|
if routine.tag == GAZ_PROCEDURE_TAG and type != VOID_TYPE:
|
||||||
|
routine.find("block").append(self.generate_return(type))
|
||||||
|
|
||||||
|
for block in routine:
|
||||||
|
for node in block:
|
||||||
|
if node.tag != "return":
|
||||||
|
node =self.populate(node, ANY_TYPE)
|
||||||
|
else:
|
||||||
|
node.set("type", type)
|
||||||
|
|
||||||
|
return routine
|
||||||
|
|
||||||
|
def populate_block(self, element):
|
||||||
|
for node in element:
|
||||||
|
return self.populate(node, ANY_TYPE)
|
||||||
|
|
||||||
|
def populate_xhs(self, side: ET.Element, type):
|
||||||
|
for node in side:
|
||||||
|
return self.populate(node, type)
|
||||||
|
|
||||||
|
def populate_ast(self, ast: ET.Element):
|
||||||
|
populated = self.generate_block()
|
||||||
|
for node in ast:
|
||||||
|
populated.append(self.populate(node, ANY_TYPE))
|
||||||
|
|
||||||
|
return populated
|
||||||
|
|
||||||
|
# def populate_assignment(self, name, type):
|
||||||
|
|
||||||
|
def populate(self, element: ET.Element, type: str):
|
||||||
|
if type == ANY_TYPE:
|
||||||
|
type = GAZ_TYPES[random.randint(0, len(GAZ_TYPES) - 1)]
|
||||||
|
|
||||||
|
if element.tag == GAZ_VAR_TAG:
|
||||||
|
return self.populate_variable(element, self.get_qualifier(), type, self.get_name(GAZ_VAR_TAG))
|
||||||
|
elif element.tag == GAZ_LIT_TAG:
|
||||||
|
return self.populate_literal(element, type, self.get_value(type))
|
||||||
|
elif element.tag == GAZ_OPERATOR_TAG:
|
||||||
|
return self.populate_operator(element, self.get_op(type), type)
|
||||||
|
elif element.tag == GAZ_FUNCTION_TAG:
|
||||||
|
return self.populate_routine(element, type, self.get_name(element.tag))
|
||||||
|
elif element.tag == GAZ_PROCEDURE_TAG:
|
||||||
|
type = self.void(type)
|
||||||
|
return self.populate_routine(element, type, self.get_name(element.tag))
|
||||||
|
elif element.tag in [GAZ_RHS_TAG, GAZ_RHS_TAG]:
|
||||||
|
return self.populate_xhs(element, type)
|
||||||
|
elif element.tag == GAZ_BLOCK_TAG:
|
||||||
|
return self.populate_block(element)
|
||||||
|
|
||||||
|
def get_qualifier(self):
|
||||||
|
var_weight: int = 80
|
||||||
|
const_weight: int = 20
|
||||||
|
if self.qualifier_probability:
|
||||||
|
var_weight = self.var_qualifier_probability
|
||||||
|
const_weight = self.const_qualifier_probability
|
||||||
|
|
||||||
|
a = random.randint(0, var_weight + const_weight)
|
||||||
|
if a in range(0, var_weight):
|
||||||
|
return 'var'
|
||||||
|
elif a in range(var_weight, var_weight + const_weight):
|
||||||
|
return 'const'
|
||||||
|
else:
|
||||||
|
raise ValueError("Internal Error, please report the stack trace to me")
|
||||||
|
|
||||||
|
def get_value(self, type):
|
||||||
|
if type == GAZ_INT_KEY:
|
||||||
|
return random.randint(self.int_low, self.int_high)
|
||||||
|
else:
|
||||||
|
raise TypeError("Unimplemented generator for type: " + type)
|
||||||
|
|
||||||
|
def get_name(self, name_type):
|
||||||
|
if name_type == GAZ_VAR_TAG:
|
||||||
|
return VAR_NAMES[random.randint(0, self.max_number_of_vars - 1)]
|
||||||
|
elif name_type in [GAZ_PROCEDURE_TAG, GAZ_FUNCTION_TAG]:
|
||||||
|
r_name = ROUTINE_NAMES[random.randint(0, len(ROUTINE_NAMES) - 1)]
|
||||||
|
self.functions.append(r_name)
|
||||||
|
return r_name
|
||||||
|
|
||||||
|
def get_op(self, type):
|
||||||
|
if type == GAZ_INT_KEY:
|
||||||
|
# TODO make this a parameter for peiple to change
|
||||||
|
return GAZ_INT_OPS[random.randint(0, len(GAZ_INT_OPS) - 1)]
|
||||||
|
else:
|
||||||
|
raise TypeError("Unimplemented type: " + type)
|
||||||
|
|
||||||
|
def _generate(self, element: str or None) -> ET.Element:
|
||||||
|
initial_grammar = convert_ebnf_grammar(self.grammar)
|
||||||
|
solver = ISLaSolver(initial_grammar, start_symbol=element)
|
||||||
|
ast_str = str(solver.solve())
|
||||||
|
|
||||||
|
print(ast_str)
|
||||||
|
elem = ET.fromstring(ast_str)
|
||||||
|
return elem
|
||||||
|
|
||||||
|
def generate_ast(self) -> ET.Element:
|
||||||
|
return self._generate(None)
|
||||||
|
|
||||||
|
|
||||||
|
def generate_return(self, type) -> ET.Element:
|
||||||
|
elem = self._generate('<return>')
|
||||||
|
elem.set(GAZ_TY_KEY, type)
|
||||||
|
|
||||||
|
return elem
|
||||||
|
|
||||||
|
def generate_literal(self) -> ET.Element:
|
||||||
|
return self._generate('<literal>')
|
||||||
|
|
||||||
|
def generate_variable(self) -> ET.Element:
|
||||||
|
return self._generate('<variable>')
|
||||||
|
|
||||||
|
def generate_operator(self) -> ET.Element:
|
||||||
|
return self._generate('<operator>')
|
||||||
|
|
||||||
|
def generate_block(self) -> ET.Element:
|
||||||
|
return self._generate('<block>')
|
||||||
|
|
||||||
|
def generate_routine(self) -> ET.Element:
|
||||||
|
return self._generate('<routine>')
|
||||||
|
|
||||||
|
def generate_main_routine(self) -> ET.Element:
|
||||||
|
return self._generate('<main_routine>')
|
||||||
|
|
||||||
|
def generate_declaration(self) -> ET.Element:
|
||||||
|
return self._generate('<declaration>')
|
||||||
|
|
||||||
|
def generate_stream(self) -> ET.Element:
|
||||||
|
return self._generate('<stream>')
|
||||||
|
|
||||||
|
def void(self, type):
|
||||||
|
b = random.randint(0, 100)
|
||||||
|
if b < self.void_probability:
|
||||||
|
return GAZ_VOID_TYPE
|
||||||
|
else:
|
||||||
|
return type
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class AstElement:
|
||||||
|
|
||||||
|
def __init__(self, xml: ET.Element):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class RoutineCall(AstElement):
|
||||||
|
|
||||||
|
def __init__(self, xml: ET.Element, dependents=None, type=None):
|
||||||
|
"""
|
||||||
|
@brief initialise a routine call object
|
||||||
|
:param xml:
|
||||||
|
:param dependents:
|
||||||
|
"""
|
||||||
|
super().__init__(xml)
|
||||||
|
if dependents is None:
|
||||||
|
dependents = []
|
||||||
|
else:
|
||||||
|
self.dependents = dependents
|
||||||
|
self.xml = xml
|
||||||
|
self.type = type
|
||||||
|
|
||||||
|
|
||||||
|
class Operator(AstElement):
|
||||||
|
|
||||||
|
def __init__(self, xml: ET.Element, params: json):
|
||||||
|
super().__init__(xml)
|
||||||
|
for key, value in params.items():
|
||||||
|
setattr(self, key, value)
|
||||||
|
|
||||||
|
|
||||||
|
def find_routines(AST: str):
|
||||||
|
"""
|
||||||
|
@brief find all of the routine and call elements in the ast
|
||||||
|
|
||||||
|
@param AST: the AST to analyse
|
||||||
|
@return the list of routine elements
|
||||||
|
"""
|
||||||
|
xml = ET.fromstring(AST)
|
||||||
|
result = list[RoutineCall]
|
||||||
|
for node in xml:
|
||||||
|
if node.tag in [GAZ_PROCEDURE_TAG, GAZ_FUNCTION_TAG]:
|
||||||
|
routine = RoutineCall(node)
|
||||||
|
result.append(routine)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
pass
|
||||||
|
# ast_gen = AstGenerator(GAZPREA_TOP_LEVEL, json.loads("{}"))
|
||||||
|
# out: ET.Element = ast_gen.generate_return("int")
|
||||||
|
# print(out)
|
||||||
|
|
||||||
|
|
||||||
|
# gen = AstGenerator("{}")
|
||||||
|
# assert is_valid_grammar(gazprea_ast_grammar.GAZPREA_TOP_LEVEL)
|
||||||
|
#
|
||||||
|
# gen.test_samples(gazprea_ast_grammar.GAZPREA_TOP_LEVEL, iterations=100)
|
||||||
|
#
|
||||||
|
# initial_grammar = convert_ebnf_grammar(gazprea_ast_grammar.GAZPREA_TOP_LEVEL)
|
||||||
|
# solver = ISLaSolver(initial_grammar)
|
||||||
|
# constants_tree_str = str(solver.solve())
|
||||||
|
# print(constants_tree_str)
|
62
ast_generator/gazprea_ast_grammar.py
Normal file
62
ast_generator/gazprea_ast_grammar.py
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
from fuzzingbook.Grammars import Grammar, is_valid_grammar, convert_ebnf_grammar
|
||||||
|
from isla.solver import ISLaSolver
|
||||||
|
|
||||||
|
GAZPREA_TOP_LEVEL: Grammar = {
|
||||||
|
# Top level elements
|
||||||
|
'<start>': ['<topBlock>'],
|
||||||
|
'<topBlock>': ['<XML_OPEN_TAG>block<XML_CLOSE_TAG><routine_list><main_routine><routine_list><XML_OPEN_SLASH>block<XML_CLOSE_TAG>'],
|
||||||
|
# TODO constants
|
||||||
|
|
||||||
|
# Routines
|
||||||
|
'<routine>': ['<function>', '<procedure>'], # TODO forward_declaration
|
||||||
|
'<function>': [
|
||||||
|
'<XML_OPEN_TAG>function name="_NAME_" return_type="_TYPE_" args="_ARGS_"<XML_CLOSE_TAG><return_block><XML_OPEN_SLASH>function<XML_CLOSE_TAG>'],
|
||||||
|
'<procedure>': [
|
||||||
|
'<XML_OPEN_TAG>procedure name="_NAME_" return_type="_TYPE_" args="_ARGS_"<XML_CLOSE_TAG><block><XML_OPEN_SLASH>procedure<XML_CLOSE_TAG>'],
|
||||||
|
'<main_routine>': [
|
||||||
|
'<XML_OPEN_TAG>procedure name="main" return_type="int" args="()"<XML_CLOSE_TAG><return_block><XML_OPEN_SLASH>procedure<XML_CLOSE_TAG>'],
|
||||||
|
'<routine_list>': ['<routine><routine_list><routine>', '<routine>'],
|
||||||
|
|
||||||
|
# Blocks
|
||||||
|
'<block>': ['<XML_OPEN_TAG>block<XML_CLOSE_TAG><statement_list><XML_OPEN_SLASH>block<XML_CLOSE_TAG>'],
|
||||||
|
'<return_block>': ['<XML_OPEN_TAG>block<XML_CLOSE_TAG><statement_list><return><XML_OPEN_SLASH>block<XML_CLOSE_TAG>'],
|
||||||
|
'<statement>': [
|
||||||
|
'<declaration>',
|
||||||
|
'<stream>',
|
||||||
|
# '<call>',
|
||||||
|
# '<return>', # TODO if/else, loop
|
||||||
|
],
|
||||||
|
'<statement_list>': ['<statement><statement_list><statement>', '<statement>'],
|
||||||
|
|
||||||
|
# Things that belong on their own lines
|
||||||
|
'<declaration>': ['<XML_OPEN_TAG>declaration<XML_CLOSE_TAG><variable><rhs><XML_OPEN_SLASH>declaration<XML_CLOSE_TAG>'],
|
||||||
|
'<stream>': ['<out_stream>'], #, '<in_stream>'],
|
||||||
|
'<return>': ['<XML_OPEN_TAG>return<XML_CLOSE_TAG><has_value><XML_OPEN_SLASH>return<XML_CLOSE_TAG>'],
|
||||||
|
|
||||||
|
'<out_stream>': ['<XML_OPEN_TAG>stream type="std_output"<XML_CLOSE_TAG><has_value><XML_OPEN_SLASH>stream<XML_CLOSE_TAG>'],
|
||||||
|
# '<in_stream>': ['<XML_OPEN_TAG>stream type="std_input"<XML_CLOSE_TAG><has_value><XML_OPEN_SLASH>stream<XML_CLOSE_TAG>'],
|
||||||
|
|
||||||
|
# Things that are part of lines
|
||||||
|
'<has_value>': ['<variable>', '<literal>', '<operator>'],
|
||||||
|
'<lhs>': ['<XML_OPEN_TAG>lhs<XML_CLOSE_TAG><has_value><XML_OPEN_SLASH>lhs<XML_CLOSE_TAG>'],
|
||||||
|
'<rhs>': ['<XML_OPEN_TAG>rhs<XML_CLOSE_TAG><has_value><XML_OPEN_SLASH>rhs<XML_CLOSE_TAG>'],
|
||||||
|
|
||||||
|
# Things that have values
|
||||||
|
'<operator>': ['<XML_OPEN_TAG>operator<XML_CLOSE_TAG><lhs><rhs><XML_OPEN_SLASH>operator<XML_CLOSE_TAG>'],
|
||||||
|
'<variable>': ['<XML_OPEN_TAG>variable mut="_MODIFIER_" type="_TYPE_" name="_NAME_"<XML_SLASH_TAG>'],
|
||||||
|
'<literal>': ['<XML_OPEN_TAG>literal type="_TYPE_" value="_VALUE_"<XML_SLASH_TAG>'],
|
||||||
|
|
||||||
|
# Helper rules
|
||||||
|
'<XML_OPEN_TAG>': ['<'],
|
||||||
|
'<XML_CLOSE_TAG>': ['>'],
|
||||||
|
'<XML_SLASH_TAG>': ['/>'],
|
||||||
|
'<XML_OPEN_SLASH>': ['</'],
|
||||||
|
}
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
assert is_valid_grammar(GAZPREA_TOP_LEVEL)
|
||||||
|
|
||||||
|
initial_grammar = convert_ebnf_grammar(GAZPREA_TOP_LEVEL)
|
||||||
|
solver = ISLaSolver(initial_grammar)
|
||||||
|
constants_tree_str = str(solver.solve())
|
||||||
|
print(constants_tree_str)
|
0
ast_generator/test/__init__.py
Normal file
0
ast_generator/test/__init__.py
Normal file
193
ast_generator/test/test_ast_generator.py
Normal file
193
ast_generator/test/test_ast_generator.py
Normal file
|
@ -0,0 +1,193 @@
|
||||||
|
import unittest
|
||||||
|
import xml.etree.ElementTree as ET
|
||||||
|
|
||||||
|
from ast_generator.ast_generator import *
|
||||||
|
from ast_generator.gazprea_ast_grammar import *
|
||||||
|
|
||||||
|
|
||||||
|
class TestGeneration(unittest.TestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.ast_gen = AstGenerator(GAZPREA_TOP_LEVEL, json.loads("{}"))
|
||||||
|
|
||||||
|
def test_generate_literal(self):
|
||||||
|
out: ET.Element = self.ast_gen.generate_literal()
|
||||||
|
|
||||||
|
self.assertIsNotNone(out.get("type"))
|
||||||
|
|
||||||
|
def test_generate_variable(self):
|
||||||
|
out: ET.Element = self.ast_gen.generate_variable()
|
||||||
|
|
||||||
|
self.assertIsNotNone(out.get("type"))
|
||||||
|
self.assertIsNotNone(out.get("name"))
|
||||||
|
|
||||||
|
def test_generate_declaration(self):
|
||||||
|
out: ET.Element = self.ast_gen.generate_declaration()
|
||||||
|
|
||||||
|
self.assertIsNotNone(out.find("variable"))
|
||||||
|
self.assertIsNotNone(out.find("rhs"))
|
||||||
|
|
||||||
|
def test_generate_operation(self):
|
||||||
|
out: ET.Element = self.ast_gen.generate_operator()
|
||||||
|
|
||||||
|
self.assertIsNotNone(out.find("lhs"))
|
||||||
|
self.assertIsNotNone(out.find("rhs"))
|
||||||
|
|
||||||
|
def test_generate_stream(self):
|
||||||
|
out: ET.Element = self.ast_gen.generate_stream()
|
||||||
|
|
||||||
|
self.assertIsNotNone(out.get("type"))
|
||||||
|
|
||||||
|
def test_generate_routine(self):
|
||||||
|
out: ET.Element = self.ast_gen.generate_routine()
|
||||||
|
|
||||||
|
self.assertIsNotNone(out.find("block"))
|
||||||
|
|
||||||
|
def test_generate_block(self):
|
||||||
|
out: ET.Element = self.ast_gen.generate_block()
|
||||||
|
|
||||||
|
self.assertIsNotNone(out)
|
||||||
|
|
||||||
|
def test_generate_main(self):
|
||||||
|
out: ET.Element = self.ast_gen.generate_main_routine()
|
||||||
|
|
||||||
|
self.assertIsNotNone(out)
|
||||||
|
self.assertEqual("main", out.get("name"))
|
||||||
|
self.assertEqual("int", out.get("return_type"))
|
||||||
|
|
||||||
|
def test_generate_ast(self):
|
||||||
|
out: ET.Element = self.ast_gen.generate_ast()
|
||||||
|
|
||||||
|
self.assertIsNotNone(out)
|
||||||
|
|
||||||
|
has_main = False
|
||||||
|
for child in out:
|
||||||
|
if child.get("name") == "main":
|
||||||
|
has_main = True
|
||||||
|
break
|
||||||
|
|
||||||
|
self.assertTrue(has_main)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class TestRoutines(unittest.TestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.ast_gen = AstGenerator(GAZPREA_TOP_LEVEL, json.loads("{}"))
|
||||||
|
|
||||||
|
def test_populate_function(self):
|
||||||
|
with open("xml/routine_1.xml", 'r') as i:
|
||||||
|
input_elemnet = ET.fromstring(i.read())
|
||||||
|
out: ET.Element = self.ast_gen.populate_routine(input_elemnet, 'int', 'blahaj')
|
||||||
|
|
||||||
|
self.assertEqual('int', out.get("return_type"))
|
||||||
|
self.assertEqual('int', out.find("block").find("return").get("type"))
|
||||||
|
|
||||||
|
def test_generate_return(self):
|
||||||
|
out: ET.Element = self.ast_gen.generate_return("int")
|
||||||
|
|
||||||
|
self.assertEqual('int', out.get("type"))
|
||||||
|
|
||||||
|
def test_populate_typed_procedure(self):
|
||||||
|
with open("xml/routine_2.xml", 'r') as i:
|
||||||
|
input_elemnet = ET.fromstring(i.read())
|
||||||
|
out: ET.Element = self.ast_gen.populate_routine(input_elemnet, 'int', 'blahaj')
|
||||||
|
|
||||||
|
self.assertEqual('int', out.get("return_type"))
|
||||||
|
self.assertEqual('int', out.find("block").find("return").get("type"))
|
||||||
|
|
||||||
|
def test_populate_void_procedure(self):
|
||||||
|
with open("xml/routine_3.xml", 'r') as i:
|
||||||
|
input_elemnet = ET.fromstring(i.read())
|
||||||
|
out: ET.Element = self.ast_gen.populate_routine(input_elemnet, 'void', 'blahaj')
|
||||||
|
|
||||||
|
self.assertEqual('void', out.get("return_type"))
|
||||||
|
self.assertIsNone(out.find("block").find("return"))
|
||||||
|
|
||||||
|
def test_populate_void_procedure_with_return(self):
|
||||||
|
with open("xml/routine_2.xml", 'r') as i:
|
||||||
|
input_elemnet = ET.fromstring(i.read())
|
||||||
|
out: ET.Element = self.ast_gen.populate_routine(input_elemnet, 'void', 'blahaj')
|
||||||
|
|
||||||
|
self.assertEqual('void', out.get("return_type"))
|
||||||
|
self.assertIsNotNone(out.find("block").find("return").get("type"))
|
||||||
|
self.assertEqual('void', out.find("block").find("return").get("type"))
|
||||||
|
|
||||||
|
|
||||||
|
def test_populate_nonvoid_procedure_without_return(self):
|
||||||
|
with open("xml/routine_3.xml", 'r') as i:
|
||||||
|
input_elemnet = ET.fromstring(i.read())
|
||||||
|
out: ET.Element = self.ast_gen.populate_routine(input_elemnet, 'int', 'blahaj')
|
||||||
|
|
||||||
|
self.assertEqual('int', out.get("return_type"))
|
||||||
|
self.assertIsNotNone(out.find("block").find("return"))
|
||||||
|
self.assertEqual('int', out.find("block").find("return").get("type"))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# def test_populate_assignment(self):
|
||||||
|
# pass
|
||||||
|
#
|
||||||
|
# def test_populate_top_block(self):
|
||||||
|
# pass
|
||||||
|
|
||||||
|
|
||||||
|
# def test_populate_call(self):
|
||||||
|
# pass
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class TestValues(unittest.TestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.ast_gen = AstGenerator(GAZPREA_TOP_LEVEL ,json.loads("{}"))
|
||||||
|
|
||||||
|
def test_populate_int(self):
|
||||||
|
with open("xml/literal_1.xml", 'r') as i:
|
||||||
|
input = i.read()
|
||||||
|
input_element = ET.fromstring(input)
|
||||||
|
out: ET.Element = self.ast_gen.populate_literal(input_element, "int", 42)
|
||||||
|
|
||||||
|
self.assertEqual("int", out.get("type"))
|
||||||
|
self.assertEqual("42", str(out.get("value")))
|
||||||
|
|
||||||
|
def test_populate_var(self):
|
||||||
|
with open("xml/variable_1.xml", 'r') as i:
|
||||||
|
input = i.read()
|
||||||
|
input_element = ET.fromstring(input)
|
||||||
|
out: ET.Element = self.ast_gen.populate_variable(input_element, "var", "float", "bean")
|
||||||
|
|
||||||
|
self.assertEqual("var", out.get("mut"))
|
||||||
|
self.assertEqual("float", out.get("type"))
|
||||||
|
self.assertEqual("bean", out.get("name"))
|
||||||
|
|
||||||
|
def test_populate_operator(self):
|
||||||
|
with open("xml/operator_1.xml", 'r') as i:
|
||||||
|
input = i.read()
|
||||||
|
input_element = ET.fromstring(input)
|
||||||
|
out: ET.Element = self.ast_gen.populate_operator(input_element, '*', 'int')
|
||||||
|
inner_var = out.find("type")
|
||||||
|
|
||||||
|
self.assertEqual("int", out.get("type"))
|
||||||
|
self.assertEqual("*", out.get("op"))
|
||||||
|
self.assertEqual("int", out.find("lhs").find("variable").get("type"))
|
||||||
|
self.assertEqual("int", out.find("rhs").find("literal").get("type"))
|
||||||
|
|
||||||
|
def test_populate_stream(self):
|
||||||
|
with open("xml/stream_1.xml", 'r') as i:
|
||||||
|
input_element = ET.fromstring(i.read())
|
||||||
|
out: ET.Element = self.ast_gen.populate_stream(input_element, "std_output")
|
||||||
|
|
||||||
|
self.assertEqual("std_output", out.get("type"))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
54
ast_generator/test/test_generator_integration.py
Normal file
54
ast_generator/test/test_generator_integration.py
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
|
||||||
|
class TestGenConcatenation(unittest.TestCase):
|
||||||
|
|
||||||
|
def test_operator_nesting(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def test_recursive_population_of_vars(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def test_recursive_population_of_literals(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def test_recursive_block_population(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def test_routine_population(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def test_full_population(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class TestAutoGeneration(unittest.TestCase):
|
||||||
|
|
||||||
|
def routines_call_routines(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def test_routines_use_globals(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def test_variable_reuse(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def test_max_nesting_depth(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def test_max_conditionals_loops(self):
|
||||||
|
pass # test the parameter limiting the maximum number of loops and conditionals per routine
|
||||||
|
|
||||||
|
|
||||||
|
def test_recursive_calls(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def test_max_range_length(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
1
ast_generator/test/xml/literal_1.xml
Normal file
1
ast_generator/test/xml/literal_1.xml
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<literal type="%_TYPE_%" value="%_VALUE_%" />
|
8
ast_generator/test/xml/operator_1.xml
Normal file
8
ast_generator/test/xml/operator_1.xml
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
<operator op="*" type="int">
|
||||||
|
<lhs>
|
||||||
|
<variable mut="var" type="int" name="a"/>
|
||||||
|
</lhs>
|
||||||
|
<rhs>
|
||||||
|
<literal type="int" value="42" />
|
||||||
|
</rhs>
|
||||||
|
</operator>
|
33
ast_generator/test/xml/routine_1.xml
Normal file
33
ast_generator/test/xml/routine_1.xml
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
<function name="%_NAME_%" ref_name="_vvtmcyclqx" return_type="%_TYPE_%" args="()" >
|
||||||
|
<block>
|
||||||
|
<declaration>
|
||||||
|
<variable mut="var" type="int" name="b" ref_name="_tsfjvbryrsxdtso"/>
|
||||||
|
<rhs>
|
||||||
|
<function name="art" ref_name="_hssvswwxpt" >
|
||||||
|
</function>
|
||||||
|
</rhs>
|
||||||
|
</declaration>
|
||||||
|
|
||||||
|
<declaration>
|
||||||
|
<variable mut="var" type="int" name="a" ref_name="_pseeixbzvvhuygw"/>
|
||||||
|
<rhs>
|
||||||
|
<literal type="int" value="1" />
|
||||||
|
</rhs>
|
||||||
|
</declaration>
|
||||||
|
|
||||||
|
<stream type="std_output">
|
||||||
|
<operator op="*" type="unset">
|
||||||
|
<lhs>
|
||||||
|
<variable mut="var" type="int" name="a" ref_name="_pseeixbzvvhuygw"/>
|
||||||
|
</lhs>
|
||||||
|
<rhs>
|
||||||
|
<literal type="int" value="42" />
|
||||||
|
</rhs>
|
||||||
|
</operator>
|
||||||
|
</stream>
|
||||||
|
|
||||||
|
<return>
|
||||||
|
<literal type="%_TYPE_%" value="%_VALUE_%" />
|
||||||
|
</return>
|
||||||
|
</block>
|
||||||
|
</function>
|
33
ast_generator/test/xml/routine_2.xml
Normal file
33
ast_generator/test/xml/routine_2.xml
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
<procedure name="%_NAME_%" ref_name="_vvtmcyclqx" return_type="%_TYPE_%" args="()" >
|
||||||
|
<block>
|
||||||
|
<declaration>
|
||||||
|
<variable mut="var" type="int" name="b" ref_name="_tsfjvbryrsxdtso"/>
|
||||||
|
<rhs>
|
||||||
|
<function name="art" ref_name="_hssvswwxpt" >
|
||||||
|
</function>
|
||||||
|
</rhs>
|
||||||
|
</declaration>
|
||||||
|
|
||||||
|
<declaration>
|
||||||
|
<variable mut="var" type="int" name="a" ref_name="_pseeixbzvvhuygw"/>
|
||||||
|
<rhs>
|
||||||
|
<literal type="int" value="1" />
|
||||||
|
</rhs>
|
||||||
|
</declaration>
|
||||||
|
|
||||||
|
<stream type="std_output">
|
||||||
|
<operator op="*" type="unset">
|
||||||
|
<lhs>
|
||||||
|
<variable mut="var" type="int" name="a" ref_name="_pseeixbzvvhuygw"/>
|
||||||
|
</lhs>
|
||||||
|
<rhs>
|
||||||
|
<literal type="int" value="42" />
|
||||||
|
</rhs>
|
||||||
|
</operator>
|
||||||
|
</stream>
|
||||||
|
|
||||||
|
<return>
|
||||||
|
<literal type="%_TYPE_%" value="%_VALUE_%" />
|
||||||
|
</return>
|
||||||
|
</block>
|
||||||
|
</procedure>
|
29
ast_generator/test/xml/routine_3.xml
Normal file
29
ast_generator/test/xml/routine_3.xml
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
<procedure name="%_NAME_%" ref_name="_vvtmcyclqx" return_type="%_TYPE_%" args="()" >
|
||||||
|
<block>
|
||||||
|
<declaration>
|
||||||
|
<variable mut="var" type="int" name="b" ref_name="_tsfjvbryrsxdtso"/>
|
||||||
|
<rhs>
|
||||||
|
<function name="art" ref_name="_hssvswwxpt" >
|
||||||
|
</function>
|
||||||
|
</rhs>
|
||||||
|
</declaration>
|
||||||
|
|
||||||
|
<declaration>
|
||||||
|
<variable mut="var" type="int" name="a" ref_name="_pseeixbzvvhuygw"/>
|
||||||
|
<rhs>
|
||||||
|
<literal type="int" value="1" />
|
||||||
|
</rhs>
|
||||||
|
</declaration>
|
||||||
|
|
||||||
|
<stream type="std_output">
|
||||||
|
<operator op="*" type="unset">
|
||||||
|
<lhs>
|
||||||
|
<variable mut="var" type="int" name="a" ref_name="_pseeixbzvvhuygw"/>
|
||||||
|
</lhs>
|
||||||
|
<rhs>
|
||||||
|
<literal type="int" value="42" />
|
||||||
|
</rhs>
|
||||||
|
</operator>
|
||||||
|
</stream>
|
||||||
|
</block>
|
||||||
|
</procedure>
|
10
ast_generator/test/xml/stream_1.xml
Normal file
10
ast_generator/test/xml/stream_1.xml
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
<stream type="std_output">
|
||||||
|
<operator op="*" type="unset">
|
||||||
|
<lhs>
|
||||||
|
<variable mut="var" type="int" name="a" ref_name="_pseeixbzvvhuygw"/>
|
||||||
|
</lhs>
|
||||||
|
<rhs>
|
||||||
|
<literal type="int" value="42" />
|
||||||
|
</rhs>
|
||||||
|
</operator>
|
||||||
|
</stream>
|
1
ast_generator/test/xml/variable_1.xml
Normal file
1
ast_generator/test/xml/variable_1.xml
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<variable mut="%_MUT_%" type="%_TYPE_%" name="%_NAME_%"/>
|
0
ast_parser/__init__.py
Normal file
0
ast_parser/__init__.py
Normal file
165
ast_parser/ast_parser.py
Normal file
165
ast_parser/ast_parser.py
Normal file
|
@ -0,0 +1,165 @@
|
||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
import xml.etree.ElementTree as ET
|
||||||
|
|
||||||
|
|
||||||
|
def to_gazprea_type(ty: str):
|
||||||
|
if ty == "int":
|
||||||
|
return "integer"
|
||||||
|
elif ty == "bool":
|
||||||
|
return "boolean"
|
||||||
|
elif ty == "string":
|
||||||
|
return "string"
|
||||||
|
elif ty == 'void':
|
||||||
|
return 'void'
|
||||||
|
else:
|
||||||
|
raise Exception("Unknown type: " + ty)
|
||||||
|
|
||||||
|
|
||||||
|
class AstParser:
|
||||||
|
def __init__(self, input: str or ET.Element, from_xml: bool = False):
|
||||||
|
if from_xml:
|
||||||
|
self.xml = input
|
||||||
|
self.input = None
|
||||||
|
else:
|
||||||
|
self.input = input
|
||||||
|
self.xml = None
|
||||||
|
|
||||||
|
self.indentation = 0
|
||||||
|
|
||||||
|
|
||||||
|
def parse(self):
|
||||||
|
if os.path.isdir("/home/stormblessed/Code/gazprea_fuzzer_v0.2/ast_parser/test/.tmp"):
|
||||||
|
os.system("rm -rf /home/stormblessed/Code/gazprea_fuzzer_v0.2/ast_parser/test/.tmp")
|
||||||
|
os.mkdir("/home/stormblessed/Code/gazprea_fuzzer_v0.2/ast_parser/test/.tmp")
|
||||||
|
else:
|
||||||
|
os.mkdir("/home/stormblessed/Code/gazprea_fuzzer_v0.2/ast_parser/test/.tmp")
|
||||||
|
with open("/home/stormblessed/Code/gazprea_fuzzer_v0.2/ast_parser/test/.tmp/input.in", "x") as f:
|
||||||
|
f.write(self.input)
|
||||||
|
os.system("/home/stormblessed/.local/bin/gazc "
|
||||||
|
"/home/stormblessed/Code/gazprea_fuzzer_v0.2/ast_parser/test/.tmp/input.in "
|
||||||
|
"/home/stormblessed/Code/gazprea_fuzzer_v0.2/ast_parser/test/.tmp/output.out "
|
||||||
|
"/home/stormblessed/Code/gazprea_fuzzer_v0.2/ast_parser/test/.tmp/xml.xml")
|
||||||
|
self.xml = ET.parse(".tmp/xml.xml")
|
||||||
|
|
||||||
|
def unparse(self):
|
||||||
|
"""
|
||||||
|
@brief unparses the xml into valid gazprea code
|
||||||
|
|
||||||
|
:return: a string of valid gazprea code
|
||||||
|
"""
|
||||||
|
self.input = ""
|
||||||
|
for node in self.xml:
|
||||||
|
self._unparse_node(node)
|
||||||
|
|
||||||
|
def _unparse_node(self, node):
|
||||||
|
if node.tag not in ["variable", "rhs", "lhs", "literal", "operator"]:
|
||||||
|
self.input += " " * self.indentation
|
||||||
|
|
||||||
|
if node.tag == "block":
|
||||||
|
self._block_unparse(node)
|
||||||
|
elif node.tag == "declaration":
|
||||||
|
self._declaration_unparse(node)
|
||||||
|
elif node.tag == "return":
|
||||||
|
self._return_unparse(node)
|
||||||
|
elif node.tag == "operator":
|
||||||
|
self._operator_unparse(node)
|
||||||
|
elif node.tag == "stream":
|
||||||
|
self._stream_unparse(node)
|
||||||
|
elif node.tag == "literal":
|
||||||
|
self._literal_unparse(node)
|
||||||
|
elif node.tag == "procedure" or node.tag == "function":
|
||||||
|
self._routine_unparse(node)
|
||||||
|
elif node.tag == "variable":
|
||||||
|
self._variable_unparse(node)
|
||||||
|
elif node.tag == "rhs" or node.tag == "lhs":
|
||||||
|
self._xhs_unparse(node)
|
||||||
|
elif node.tag == "literal":
|
||||||
|
self._literal_unparse(node)
|
||||||
|
else:
|
||||||
|
raise Exception("Unknown tag: " + node.tag)
|
||||||
|
|
||||||
|
def _block_unparse(self, node):
|
||||||
|
self.input += "{\n"
|
||||||
|
self.indentation += 4
|
||||||
|
for child in node:
|
||||||
|
self._unparse_node(child)
|
||||||
|
self.indentation -= 4
|
||||||
|
self.input += "}\n\n"
|
||||||
|
|
||||||
|
def _declaration_unparse(self, node):
|
||||||
|
variable = node.find("variable")
|
||||||
|
rhs = node.find("rhs")
|
||||||
|
self._variable_unparse(variable, True)
|
||||||
|
self.input += "="
|
||||||
|
self._unparse_node(rhs)
|
||||||
|
self.input += ";\n"
|
||||||
|
|
||||||
|
def _variable_unparse(self, node, is_declaration = False):
|
||||||
|
if is_declaration:
|
||||||
|
mut = node.get("mut")
|
||||||
|
type = to_gazprea_type(node.get("type"))
|
||||||
|
name = node.get("name")
|
||||||
|
|
||||||
|
self.input += "{} {} {} ".format(mut, type, name)
|
||||||
|
else:
|
||||||
|
self.input += " {} ".format(node.get("name"))
|
||||||
|
|
||||||
|
def _stream_unparse(self, node):
|
||||||
|
for child in node:
|
||||||
|
self._unparse_node(child)
|
||||||
|
|
||||||
|
self.input += "-> {};\n".format(node.get("type"))
|
||||||
|
|
||||||
|
def _literal_unparse(self, node):
|
||||||
|
self.input += " {} ".format(node.get("value"))
|
||||||
|
|
||||||
|
def _xhs_unparse(self, node):
|
||||||
|
for child in node:
|
||||||
|
self._unparse_node(child)
|
||||||
|
|
||||||
|
def _operator_unparse(self, node):
|
||||||
|
self._xhs_unparse(node.find("lhs"))
|
||||||
|
self.input += "{}".format(node.get("op"))
|
||||||
|
self._xhs_unparse(node.find("rhs"))
|
||||||
|
|
||||||
|
def _return_unparse(self, node):
|
||||||
|
self.input += "return"
|
||||||
|
for child in node:
|
||||||
|
self._unparse_node(child)
|
||||||
|
self.input += ";\n"
|
||||||
|
|
||||||
|
def _routine_unparse(self, node):
|
||||||
|
return_type = ""
|
||||||
|
if node.get("return_type") != "":
|
||||||
|
return_type = "returns " + to_gazprea_type(node.get("return_type"))
|
||||||
|
|
||||||
|
self.input += "{} {}{} {} ".format(
|
||||||
|
node.tag,
|
||||||
|
node.get("name"),
|
||||||
|
node.get("args"),
|
||||||
|
return_type,
|
||||||
|
)
|
||||||
|
|
||||||
|
for child in node:
|
||||||
|
self._unparse_node(child)
|
||||||
|
|
||||||
|
# self.input += "}\n\n" #blocks are already there
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
input = """
|
||||||
|
function art() returns integer {
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
procedure main() returns integer {
|
||||||
|
integer b = art();
|
||||||
|
integer a = 1;
|
||||||
|
a * 42 -> std_output;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
|
||||||
|
parser = AstParser(input)
|
||||||
|
parser.parse()
|
||||||
|
|
13
ast_parser/ast_solver.py
Normal file
13
ast_parser/ast_solver.py
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
import json
|
||||||
|
|
||||||
|
|
||||||
|
class AstSolver:
|
||||||
|
|
||||||
|
def __init__(self, ast: str, params: str):
|
||||||
|
json.loads(params)
|
||||||
|
self.ast = ast
|
||||||
|
for key, value in json.loads(params).items():
|
||||||
|
setattr(self, key, value)
|
||||||
|
|
||||||
|
def fix_missing_locations(self, AST):
|
||||||
|
pass
|
14
ast_parser/params.json
Normal file
14
ast_parser/params.json
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
{
|
||||||
|
"num_vars": 10,
|
||||||
|
"num_globals": 10,
|
||||||
|
"num_functions": 2,
|
||||||
|
"num_procedures": 2,
|
||||||
|
|
||||||
|
"arith_ops": 60,
|
||||||
|
"compare_ops": 30,
|
||||||
|
"outstream_ops": 50,
|
||||||
|
"instream_ops": 10,
|
||||||
|
|
||||||
|
"largest_number": 900000,
|
||||||
|
"smallest_number": -900000
|
||||||
|
}
|
0
ast_parser/test/__init__.py
Normal file
0
ast_parser/test/__init__.py
Normal file
6
ast_parser/test/input.in
Normal file
6
ast_parser/test/input.in
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
procedure main() returns integer {
|
||||||
|
var integer a = 1 ;
|
||||||
|
a * 42 -> std_output;
|
||||||
|
return 0 ;
|
||||||
|
}
|
||||||
|
|
28
ast_parser/test/test.xml
Normal file
28
ast_parser/test/test.xml
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
<block>
|
||||||
|
<procedure name="main" ref_name="_cteplvqbvd" return_type="int" args="()" >
|
||||||
|
<block>
|
||||||
|
<declaration>
|
||||||
|
<variable mut="var" type="int" name="a" ref_name="_bwagkmcgpmsgosa"/>
|
||||||
|
<rhs>
|
||||||
|
<literal type="int" value="1" />
|
||||||
|
</rhs>
|
||||||
|
</declaration>
|
||||||
|
|
||||||
|
<stream type="std_output">
|
||||||
|
<operator op="*" type="unset">
|
||||||
|
<lhs>
|
||||||
|
<variable mut="var" type="int" name="a" ref_name="_bwagkmcgpmsgosa"/>
|
||||||
|
</lhs>
|
||||||
|
<rhs>
|
||||||
|
<literal type="int" value="42" />
|
||||||
|
</rhs>
|
||||||
|
</operator>
|
||||||
|
</stream>
|
||||||
|
|
||||||
|
<return>
|
||||||
|
<literal type="int" value="0" />
|
||||||
|
</return>
|
||||||
|
</block>
|
||||||
|
</procedure>
|
||||||
|
|
||||||
|
</block>
|
107
ast_parser/test/test_parse_code.py
Normal file
107
ast_parser/test/test_parse_code.py
Normal file
|
@ -0,0 +1,107 @@
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
from ast_parser.ast_parser import AstParser
|
||||||
|
|
||||||
|
|
||||||
|
class TestParseCode(unittest.TestCase):
|
||||||
|
def test_parse_code(self):
|
||||||
|
input = """
|
||||||
|
procedure main() returns integer {
|
||||||
|
integer a = 1;
|
||||||
|
a * 42 -> std_output;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
|
||||||
|
parser = AstParser(input)
|
||||||
|
parser.parse()
|
||||||
|
self.assertIsNotNone(parser.xml)
|
||||||
|
self.assertEqual(parser.xml.getroot().tag, "block")
|
||||||
|
|
||||||
|
def test_unparse_variable_regular(self):
|
||||||
|
input = '<variable mut="var" type="int" name="a" ref_name="_lsiyjvtbvnpmlml"/>'
|
||||||
|
parser = AstParser(input, True)
|
||||||
|
parser.input = ""
|
||||||
|
parser._unparse_node(parser.xml)
|
||||||
|
self.assertIsNotNone(parser.input)
|
||||||
|
self.assertEqual(" a ", parser.input)
|
||||||
|
|
||||||
|
def test_unparse_variable_declaration(self):
|
||||||
|
input = '<variable mut="var" type="int" name="a" ref_name="_lsiyjvtbvnpmlml"/>'
|
||||||
|
parser = AstParser(input, True)
|
||||||
|
parser.input = ""
|
||||||
|
parser._variable_unparse(parser.xml, True)
|
||||||
|
self.assertIsNotNone(parser.input)
|
||||||
|
self.assertEqual("var integer a ", parser.input)
|
||||||
|
|
||||||
|
|
||||||
|
def test_unparse_rhs_single(self):
|
||||||
|
input = '<rhs><literal type="int" value="1" /></rhs>'
|
||||||
|
parser = AstParser(input, True)
|
||||||
|
parser.input = ""
|
||||||
|
parser._unparse_node(parser.xml)
|
||||||
|
self.assertIsNotNone(parser.input)
|
||||||
|
self.assertEqual(" 1 ", parser.input)
|
||||||
|
|
||||||
|
def test_unparse_declaration(self):
|
||||||
|
input = '<declaration><variable mut="var" type="int" name="a" ref_name="_lsiyjvtbvnpmlml"/><rhs><literal type="int" value="1" /></rhs></declaration>'
|
||||||
|
parser = AstParser(input, True)
|
||||||
|
parser.input = ""
|
||||||
|
parser._unparse_node(parser.xml)
|
||||||
|
self.assertIsNotNone(parser.input)
|
||||||
|
self.assertEqual("var integer a = 1 ;\n", parser.input)
|
||||||
|
|
||||||
|
def test_unparse_stream(self):
|
||||||
|
input = ' <stream type="std_output"> <operator op="*" type="unset"> <lhs> <variable mut="var" type="int" name="a" ref_name="_lsiyjvtbvnpmlml"/> </lhs> <rhs> <literal type="int" value="42" /> </rhs> </operator></stream>'
|
||||||
|
parser = AstParser(input, True)
|
||||||
|
parser.input = ""
|
||||||
|
parser._unparse_node(parser.xml)
|
||||||
|
self.assertIsNotNone(parser.input)
|
||||||
|
self.assertEqual(" a * 42 -> std_output;\n", parser.input)
|
||||||
|
|
||||||
|
def test_unparse_block(self):
|
||||||
|
input = '<block> <declaration> <variable mut="var" type="int" name="a" ref_name="_lsiyjvtbvnpmlml"/> <rhs> <literal type="int" value="1" /> </rhs> </declaration> <stream type="std_output"> <operator op="*" type="unset"> <lhs> <variable mut="var" type="int" name="a" ref_name="_lsiyjvtbvnpmlml"/> </lhs> <rhs> <literal type="int" value="42" /> </rhs> </operator> </stream> <return> <literal type="int" value="0" /> </return> </block>'
|
||||||
|
parser = AstParser(input, True)
|
||||||
|
parser.input = ""
|
||||||
|
parser._unparse_node(parser.xml)
|
||||||
|
self.assertIsNotNone(parser.input)
|
||||||
|
self.assertEqual("{\n var integer a = 1 ;\n a * 42 -> std_output;\n return 0 ;\n}\n\n", parser.input)
|
||||||
|
|
||||||
|
def test_unparse_operation_single(self):
|
||||||
|
input = '<operator op="*" type="unset"> <lhs> <variable mut="var" type="int" name="a" ref_name="_lsiyjvtbvnpmlml"/> </lhs> <rhs> <literal type="int" value="42" /> </rhs> </operator>'
|
||||||
|
parser = AstParser(input, True)
|
||||||
|
parser.input = ""
|
||||||
|
parser._unparse_node(parser.xml)
|
||||||
|
self.assertIsNotNone(parser.input)
|
||||||
|
self.assertEqual(" a * 42 ", parser.input)
|
||||||
|
|
||||||
|
def test_unparse_return(self):
|
||||||
|
input = '<return> <literal type="int" value="0" /> </return>'
|
||||||
|
parser = AstParser(input, True)
|
||||||
|
parser.input = ""
|
||||||
|
parser._unparse_node(parser.xml)
|
||||||
|
self.assertIsNotNone(parser.input)
|
||||||
|
self.assertEqual("return 0 ;\n", parser.input)
|
||||||
|
|
||||||
|
def test_unparse_routine(self):
|
||||||
|
input = '<procedure name="main" ref_name="_jemrvvseyj" return_type="int" args="()" ><block><declaration><variable mut="var" type="int" name="a" ref_name="_lsiyjvtbvnpmlml"/><rhs><literal type="int" value="1" /></rhs></declaration><stream type="std_output"><operator op="*" type="unset"><lhs><variable mut="var" type="int" name="a" ref_name="_lsiyjvtbvnpmlml"/></lhs><rhs><literal type="int" value="42" /></rhs></operator></stream><return><literal type="int" value="0" /></return></block></procedure>'
|
||||||
|
parser = AstParser(input, True)
|
||||||
|
parser.input = ""
|
||||||
|
parser._unparse_node(parser.xml)
|
||||||
|
self.assertIsNotNone(parser.input)
|
||||||
|
i = ' ' * parser.indentation
|
||||||
|
self.assertEqual("procedure main() returns integer {\n var integer a = 1 ;\n a * 42 -> std_output;\n return 0 ;\n}\n\n", parser.input)
|
||||||
|
|
||||||
|
def test_unparse_code(self):
|
||||||
|
with open("test.xml", "r") as input:
|
||||||
|
parser = AstParser(input.read(), True)
|
||||||
|
parser.unparse()
|
||||||
|
self.assertIsNotNone(parser.input)
|
||||||
|
|
||||||
|
with open("input.in", "r") as input:
|
||||||
|
i = input.read()
|
||||||
|
self.assertEqual(i, parser.input)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main()
|
70
config.yaml
Normal file
70
config.yaml
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
# The default configuration for the Gazprea Fuzzer
|
||||||
|
---
|
||||||
|
generation-options:
|
||||||
|
max-nesting-depth: 5 # maximum nesting depth for statements
|
||||||
|
max-conditionals-loops: 5 # maximum number of loops/conditionals per routine
|
||||||
|
properties:
|
||||||
|
max-range-length: 5 # maximum length of ranges, vectors and tuples, (axa matrices can exist)
|
||||||
|
id-length: # length of identifiers
|
||||||
|
min: 1
|
||||||
|
max: 10
|
||||||
|
function-name-length: # length of function names
|
||||||
|
min: 1
|
||||||
|
max: 10
|
||||||
|
expression-weights: # weights for expressions
|
||||||
|
# the higher a weight, the more likely (0, +inf)
|
||||||
|
brackets: 10
|
||||||
|
|
||||||
|
# arithmetic
|
||||||
|
addition: 80
|
||||||
|
subtraction: 80
|
||||||
|
multiplication: 30
|
||||||
|
division: 10
|
||||||
|
modulo: 10
|
||||||
|
power: 5
|
||||||
|
negation: 20
|
||||||
|
|
||||||
|
# comparison
|
||||||
|
equality: 50
|
||||||
|
inequality: 50
|
||||||
|
less-than: 30
|
||||||
|
greater-than: 30
|
||||||
|
less-than-or-equal: 10
|
||||||
|
greater-than-or-equal: 10
|
||||||
|
|
||||||
|
# logical
|
||||||
|
and: 50
|
||||||
|
or: 50
|
||||||
|
not: 10
|
||||||
|
xor: 10
|
||||||
|
|
||||||
|
# vector/string
|
||||||
|
generator: 20
|
||||||
|
range: 30
|
||||||
|
filter: 10
|
||||||
|
reverse: 10
|
||||||
|
concatenation: 50
|
||||||
|
|
||||||
|
|
||||||
|
statement-weights: # set to 0 for any statements you wish to exclude
|
||||||
|
variable-declaration:
|
||||||
|
int-declaration: 50
|
||||||
|
float-declaration: 50
|
||||||
|
char-declaration: 50
|
||||||
|
string-declaration: 50
|
||||||
|
bool-declaration: 50
|
||||||
|
vector-declaration: 20
|
||||||
|
tuple-declaration: 10
|
||||||
|
matrix-declaration: 10
|
||||||
|
function-call: 20
|
||||||
|
conditional: 30
|
||||||
|
loop: 20
|
||||||
|
assignment: 40
|
||||||
|
print: 20
|
||||||
|
input: 5
|
||||||
|
|
||||||
|
return: 5 # probability for a return statement to be placed arbitrarily in the middle of a generated procedure
|
||||||
|
|
||||||
|
block-termination-probability: 0.2 # probability for a block to terminate
|
||||||
|
|
||||||
|
|
3
fuzzer.py
Normal file
3
fuzzer.py
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
class GazpreaFuzzer:
|
||||||
|
def __init__(self, config: str, ):
|
||||||
|
pass
|
83
gazprea_fuzzer.py
Normal file
83
gazprea_fuzzer.py
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
import json
|
||||||
|
from xml import etree
|
||||||
|
|
||||||
|
from fuzzingbook import Grammars
|
||||||
|
from fuzzingbook.Grammars import is_valid_grammar
|
||||||
|
from isla.solver import ISLaSolver
|
||||||
|
|
||||||
|
import ast_generator.ast_generator
|
||||||
|
from ast_parser.ast_solver import AstSolver
|
||||||
|
from ast_parser.ast_parser import AstParser
|
||||||
|
from ast_generator import gazprea_ast_grammar
|
||||||
|
import xml.etree.ElementTree as ET
|
||||||
|
import xml.dom.minidom
|
||||||
|
import ast_parser
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class GazpreaFuzzer(ISLaSolver):
|
||||||
|
"""Produce Gazprea code"""
|
||||||
|
def __init__(self,
|
||||||
|
grammar: Grammars,
|
||||||
|
start_symbol: str = "<start>",
|
||||||
|
constraint: str = "",
|
||||||
|
**kwargs) -> None:
|
||||||
|
"""
|
||||||
|
@brief initialize a Gazprea code generator
|
||||||
|
|
||||||
|
:param grammar: the grammar from which you would like to generate code
|
||||||
|
:param start_symbol: the start symbol of the grammar (default "<start>")
|
||||||
|
:param constraint: any constraints that you would like to impose on the solver
|
||||||
|
:param kwargs: any extra arguments passed to the ISLaSolver
|
||||||
|
"""
|
||||||
|
assert start_symbol in grammar
|
||||||
|
assert is_valid_grammar(grammar)
|
||||||
|
|
||||||
|
super().__init__(grammar, constraint, start_symbol=start_symbol, **kwargs)
|
||||||
|
|
||||||
|
def fuzz(self) -> str:
|
||||||
|
"""Produce the hecking code"""
|
||||||
|
AST = AstParser(eval(str(self.solve())), from_xml=True)
|
||||||
|
AstSolver.fix_missing_locations(AST)
|
||||||
|
AST.unparse()
|
||||||
|
|
||||||
|
return AST.input
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
gen = ast_generator.ast_generator.AstGenerator(gazprea_ast_grammar.GAZPREA_TOP_LEVEL, json.loads('{}'))
|
||||||
|
with open("debug/test.xml", 'w') as t:
|
||||||
|
et = gen.generate_ast()
|
||||||
|
dom = xml.dom.minidom.parseString(ET.tostring(et).decode('utf-8'))
|
||||||
|
pretty: str = dom.toprettyxml()
|
||||||
|
repretty = ""
|
||||||
|
for line in pretty.split('\n'):
|
||||||
|
if line.startswith("<?xml"):
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
repretty += (line + '\n')
|
||||||
|
|
||||||
|
t.write(repretty)
|
||||||
|
|
||||||
|
gen.populate_ast(et)
|
||||||
|
|
||||||
|
with open("debug/populated.xml", 'w') as t:
|
||||||
|
dom = xml.dom.minidom.parseString(ET.tostring(et).decode('utf-8'))
|
||||||
|
pretty: str = dom.toprettyxml()
|
||||||
|
repretty = ""
|
||||||
|
for line in pretty.split('\n'):
|
||||||
|
if line.startswith("<?xml"):
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
repretty += (line + '\n')
|
||||||
|
|
||||||
|
t.write(repretty)
|
||||||
|
|
||||||
|
|
||||||
|
source = ast_parser.ast_parser.AstParser(et, from_xml=True)
|
||||||
|
source.unparse()
|
||||||
|
|
||||||
|
with open("debug/test.gz", 'w') as t:
|
||||||
|
t.write(source.input)
|
||||||
|
|
||||||
|
|
0
test/__init__.py
Normal file
0
test/__init__.py
Normal file
Loading…
Reference in a new issue