diff options
-rw-r--r-- | interpreter.py | 5 | ||||
-rw-r--r-- | optinterpreter.py | 115 |
2 files changed, 117 insertions, 3 deletions
diff --git a/interpreter.py b/interpreter.py index 4dd51a7..4b35234 100644 --- a/interpreter.py +++ b/interpreter.py @@ -604,7 +604,6 @@ class Interpreter(): if node is None: return if not isinstance(node, nodes.CodeBlock): - print(node) e = InvalidCode('Tried to execute a non-codeblock. Possibly a bug in the parser.') e.lineno = node.lineno() raise e @@ -980,7 +979,7 @@ class Interpreter(): fname = os.path.join(subdir, s) if not os.path.isfile(fname): raise InterpreterException('Tried to add non-existing source %s.' % s) - + def function_call(self, node): func_name = node.get_function_name() (posargs, kwargs) = self.reduce_arguments(node.arguments) @@ -1044,7 +1043,7 @@ class Interpreter(): a = args.kwargs[key] reduced_kw[key] = self.reduce_single(a) return (reduced_pos, reduced_kw) - + def string_method_call(self, obj, method_name, args): if method_name == 'strip': return self.to_native(obj).strip() diff --git a/optinterpreter.py b/optinterpreter.py new file mode 100644 index 0000000..01ae441 --- /dev/null +++ b/optinterpreter.py @@ -0,0 +1,115 @@ +# Copyright 2013 Jussi Pakkanen + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at + +# http://www.apache.org/licenses/LICENSE-2.0 + +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import mparser +import coredata +import nodes +import os + +class OptionException(coredata.MesonException): + pass + +class UserOption: + def __init__(self, kwargs): + super().__init__() + +class UserStringOption(UserOption): + def __init__(self, kwargs): + super().__init__(kwargs) + self.value = kwargs.get('value', '') + if not isinstance(self.value, str): + raise OptionException('Value of string option is not a string') + +option_types = {'string' : UserStringOption, + } + +class OptionInterpreter: + def __init__(self): + self.options = {} + + def process(self, option_file): + try: + ast = mparser.build_ast(open(option_file, 'r').read()) + except coredata.MesonException as me: + me.file = option_file + raise me + if not isinstance(ast, nodes.CodeBlock): + e = OptionException('Option file is malformed.') + e.lineno = ast.lineno() + raise e + statements = ast.get_statements() + i = 0 + while i < len(statements): + cur = statements[i] + try: + self.evaluate_statement(cur) + except Exception as e: + e.lineno = cur.lineno() + e.file = os.path.join('options.txt') + raise e + i += 1 # In THE FUTURE jump over blocks and stuff. + print(self.options) + + def reduce_single(self, arg): + if isinstance(arg, nodes.AtomExpression) or isinstance(arg, nodes.AtomStatement): + return self.get_variable(arg.value) + elif isinstance(arg, str): + return arg + elif isinstance(arg, nodes.StringExpression) or isinstance(arg, nodes.StringStatement): + return arg.get_value() + elif isinstance(arg, nodes.BoolStatement) or isinstance(arg, nodes.BoolExpression): + return arg.get_value() + elif isinstance(arg, nodes.ArrayStatement): + return [self.reduce_single(curarg) for curarg in arg.args.arguments] + elif isinstance(arg, nodes.IntStatement): + return arg.get_value() + else: + raise OptionException('Arguments may only be string, int, bool, or array of those.') + + def reduce_arguments(self, args): + assert(isinstance(args, nodes.Arguments)) + if args.incorrect_order(): + raise OptionException('All keyword arguments must be after positional arguments.') + reduced_pos = [self.reduce_single(arg) for arg in args.arguments] + reduced_kw = {} + for key in args.kwargs.keys(): + if not isinstance(key, str): + raise OptionException('Keyword argument name is not a string.') + a = args.kwargs[key] + reduced_kw[key] = self.reduce_single(a) + return (reduced_pos, reduced_kw) + + def evaluate_statement(self, node): + if not isinstance(node, nodes.FunctionCall): + raise OptionException('Option file may only contain option definitions') + func_name = node.get_function_name() + if func_name != 'option': + raise OptionException('Only calls to option() are allowed in option files.') + (posargs, kwargs) = self.reduce_arguments(node.arguments) + if 'type' not in kwargs: + raise OptionException('Option call missing mandatory "type" keyword argument') + opt_type = kwargs['type'] + if not opt_type in option_types: + raise OptionException('Unknown type %s.' % opt_type) + if len(posargs) != 1: + raise OptionException('Option all must have one (and only one) positional argument') + opt_name = posargs[0] + if not isinstance(opt_name, str): + raise OptionException('Positional argument must be a string.') + self.options[opt_name] = option_types[opt_type](kwargs) + +if __name__ == '__main__': + import sys + oi = OptionInterpreter() + oi.process(sys.argv[1]) |