diff options
author | Jussi Pakkanen <jpakkane@gmail.com> | 2016-01-15 21:12:23 +0200 |
---|---|---|
committer | Jussi Pakkanen <jpakkane@gmail.com> | 2016-01-15 21:22:09 +0200 |
commit | 8b1039fa30a405e2d07ac70eb0284ee4654c619a (patch) | |
tree | 6cc326bf97c235c9e67b4a34534316fdaaa2eb19 /mparser.py | |
parent | 926b55076f1fa94f887dd62443c66a886af0b78b (diff) | |
download | meson-8b1039fa30a405e2d07ac70eb0284ee4654c619a.zip meson-8b1039fa30a405e2d07ac70eb0284ee4654c619a.tar.gz meson-8b1039fa30a405e2d07ac70eb0284ee4654c619a.tar.bz2 |
Organise files into a module structure.
Diffstat (limited to 'mparser.py')
-rw-r--r-- | mparser.py | 565 |
1 files changed, 0 insertions, 565 deletions
diff --git a/mparser.py b/mparser.py deleted file mode 100644 index 455182a..0000000 --- a/mparser.py +++ /dev/null @@ -1,565 +0,0 @@ -# Copyright 2014-2015 The Meson development team - -# 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 re -from coredata import MesonException - -class ParseException(MesonException): - def __init__(self, text, lineno, colno): - super().__init__(text) - self.lineno = lineno - self.colno = colno - -class Token: - def __init__(self, tid, lineno, colno, value): - self.tid = tid - self.lineno = lineno - self.colno = colno - self.value = value - - def __eq__(self, other): - if isinstance(other, str): - return self.tid == other - return self.tid == other.tid - -class Lexer: - def __init__(self): - self.keywords = {'true', 'false', 'if', 'else', 'elif', - 'endif', 'and', 'or', 'not', 'foreach', 'endforeach'} - self.token_specification = [ - # Need to be sorted longest to shortest. - ('ignore', re.compile(r'[ \t]')), - ('id', re.compile('[_a-zA-Z][_0-9a-zA-Z]*')), - ('number', re.compile(r'\d+')), - ('eol_cont', re.compile(r'\\\n')), - ('eol', re.compile(r'\n')), - ('multiline_string', re.compile(r"'''(.|\n)*?'''", re.M)), - ('comment', re.compile(r'\#.*')), - ('lparen', re.compile(r'\(')), - ('rparen', re.compile(r'\)')), - ('lbracket', re.compile(r'\[')), - ('rbracket', re.compile(r'\]')), - ('dblquote', re.compile(r'"')), - ('string', re.compile(r"'([^'\\]|(\\.))*'")), - ('comma', re.compile(r',')), - ('plusassign', re.compile(r'\+=')), - ('dot', re.compile(r'\.')), - ('plus', re.compile(r'\+')), - ('dash', re.compile(r'-')), - ('star', re.compile(r'\*')), - ('fslash', re.compile(r'/')), - ('colon', re.compile(r':')), - ('equal', re.compile(r'==')), - ('nequal', re.compile(r'\!=')), - ('assign', re.compile(r'=')), - ] - - def lex(self, code): - lineno = 1 - line_start = 0 - loc = 0; - par_count = 0 - bracket_count = 0 - col = 0 - while(loc < len(code)): - matched = False - value = None - for (tid, reg) in self.token_specification: - mo = reg.match(code, loc) - if mo: - curline = lineno - col = mo.start()-line_start - matched = True - loc = mo.end() - match_text = mo.group() - if tid == 'ignore' or tid == 'comment': - break - elif tid == 'lparen': - par_count += 1 - elif tid == 'rparen': - par_count -= 1 - elif tid == 'lbracket': - bracket_count += 1 - elif tid == 'rbracket': - bracket_count -= 1 - elif tid == 'dblquote': - raise ParseException('Double quotes are not supported. Use single quotes.', lineno, col) - elif tid == 'string': - value = match_text[1:-1].replace(r"\'", "'").replace(r" \\ ".strip(), r" \ ".strip())\ - .replace("\\n", "\n") - elif tid == 'multiline_string': - tid = 'string' - value = match_text[3:-3] - lines = match_text.split('\n') - if len(lines) > 1: - lineno += len(lines) - 1 - line_start = mo.end() - len(lines[-1]) - elif tid == 'number': - value = int(match_text) - elif tid == 'eol' or tid == 'eol_cont': - lineno += 1 - line_start = loc - if par_count > 0 or bracket_count > 0: - break - elif tid == 'id': - if match_text in self.keywords: - tid = match_text - else: - value = match_text - yield Token(tid, curline, col, value) - break - if not matched: - raise ParseException('lexer', lineno, col) - -class BooleanNode: - def __init__(self, token, value): - self.lineno = token.lineno - self.colno = token.colno - self.value = value - assert(isinstance(self.value, bool)) - -class IdNode: - def __init__(self, token): - self.lineno = token.lineno - self.colno = token.colno - self.value = token.value - assert(isinstance(self.value, str)) - - def __str__(self): - return "Id node: '%s' (%d, %d)." % (self.value, self.lineno, self.colno) - -class NumberNode: - def __init__(self, token): - self.lineno = token.lineno - self.colno = token.colno - self.value = token.value - assert(isinstance(self.value, int)) - -class StringNode: - def __init__(self, token): - self.lineno = token.lineno - self.colno = token.colno - self.value = token.value - assert(isinstance(self.value, str)) - - def __str__(self): - return "String node: '%s' (%d, %d)." % (self.value, self.lineno, self.colno) - -class ArrayNode: - def __init__(self, args): - self.lineno = args.lineno - self.colno = args.colno - self.args = args - -class EmptyNode: - def __init__(self): - self.lineno = 0 - self.colno = 0 - self.value = None - -class OrNode: - def __init__(self, lineno, colno, left, right): - self.lineno = lineno - self.colno = colno - self.left = left - self.right = right - -class AndNode: - def __init__(self, lineno, colno, left, right): - self.lineno = lineno - self.colno = colno - self.left = left - self.right = right - -class ComparisonNode: - def __init__(self, lineno, colno, ctype, left, right): - self.lineno = lineno - self.colno = colno - self.left = left - self.right = right - self.ctype = ctype - -class ArithmeticNode: - def __init__(self, lineno, colno, operation, left, right): - self.lineno = lineno - self.colno = colno - self.left = left - self.right = right - self.operation = operation - -class NotNode: - def __init__(self, lineno, colno, value): - self.lineno = lineno - self.colno = colno - self.value = value - -class CodeBlockNode: - def __init__(self, lineno, colno): - self.lineno = lineno - self.colno = colno - self.lines = [] - -class IndexNode: - def __init__(self, iobject, index): - self.iobject = iobject - self.index = index - self.lineno = iobject.lineno - self.colno = iobject.colno - -class MethodNode: - def __init__(self, lineno, colno, source_object, name, args): - self.lineno = lineno - self.colno = colno - self.source_object = source_object - self.name = name - assert(isinstance(self.name, str)) - self.args = args - -class FunctionNode: - def __init__(self, lineno, colno, func_name, args): - self.lineno = lineno - self.colno = colno - self.func_name = func_name - assert(isinstance(func_name, str)) - self.args = args - -class AssignmentNode: - def __init__(self, lineno, colno, var_name, value): - self.lineno = lineno - self.colno = colno - self.var_name = var_name - assert(isinstance(var_name, str)) - self.value = value - -class PlusAssignmentNode: - def __init__(self, lineno, colno, var_name, value): - self.lineno = lineno - self.colno = colno - self.var_name = var_name - assert(isinstance(var_name, str)) - self.value = value - -class ForeachClauseNode(): - def __init__(self, lineno, colno, varname, items, block): - self.lineno = lineno - self.colno = colno - self.varname = varname - self.items = items - self.block = block - -class IfClauseNode(): - def __init__(self, lineno, colno): - self.lineno = lineno - self.colno = colno - self.ifs = [] - self.elseblock = EmptyNode() - -class UMinusNode(): - def __init__(self, lineno, colno, value): - self.lineno = lineno - self.colno = colno - self.value = value - -class IfNode(): - def __init__(self, lineno, colno, condition, block): - self.lineno = lineno - self.colno = colno - self.condition = condition - self.block = block - -class ArgumentNode(): - def __init__(self, token): - self.lineno = token.lineno - self.colno = token.colno - self.arguments = [] - self.kwargs = {} - self.order_error = False - - def prepend(self, statement): - if self.num_kwargs() > 0: - self.order_error = True - if not isinstance(statement, EmptyNode): - self.arguments = [statement] + self.arguments - - def append(self, statement): - if self.num_kwargs() > 0: - self.order_error = True - if not isinstance(statement, EmptyNode): - self.arguments = self.arguments + [statement] - - def set_kwarg(self, name, value): - self.kwargs[name] = value - - def num_args(self): - return len(self.arguments) - - def num_kwargs(self): - return len(self.kwargs) - - def incorrect_order(self): - return self.order_error - - def __len__(self): - return self.num_args() # Fixme - -# Recursive descent parser for Meson's definition language. -# Very basic apart from the fact that we have many precedence -# levels so there are not enough words to describe them all. -# Enter numbering: -# -# 1 assignment -# 2 or -# 3 and -# 4 comparison -# 5 arithmetic -# 6 negation -# 7 funcall, method call -# 8 parentheses -# 9 plain token - -class Parser: - def __init__(self, code): - self.stream = Lexer().lex(code) - self.getsym() - - def getsym(self): - try: - self.current = next(self.stream) - except StopIteration: - self.current = Token('eof', 0, 0, None) - - def accept(self, s): - if self.current.tid == s: - self.getsym() - return True - return False - - def expect(self, s): - if self.accept(s): - return True - raise ParseException('Expecting %s got %s.' % (s, self.current.tid), self.current.lineno, self.current.colno) - - def parse(self): - block = self.codeblock() - self.expect('eof') - return block - - def statement(self): - return self.e1() - - def e1(self): - left = self.e2() - if self.accept('plusassign'): - value = self.e1() - if not isinstance(left, IdNode): - raise ParseException('Plusassignment target must be an id.', left.lineno, left.colno) - return PlusAssignmentNode(left.lineno, left.colno, left.value, value) - elif self.accept('assign'): - value = self.e1() - if not isinstance(left, IdNode): - raise ParseException('Assignment target must be an id.', - left.lineno, left.colno) - return AssignmentNode(left.lineno, left.colno, left.value, value) - return left - - def e2(self): - left = self.e3() - while self.accept('or'): - left = OrNode(left.lineno, left.colno, left, self.e3()) - return left - - def e3(self): - left = self.e4() - while self.accept('and'): - left = AndNode(left.lineno, left.colno, left, self.e4()) - return left - - def e4(self): - left = self.e5() - if self.accept('equal'): - return ComparisonNode(left.lineno, left.colno, '==', left, self.e5()) - if self.accept('nequal'): - return ComparisonNode(left.lineno, left.colno, '!=', left, self.e5()) - return left - - def e5(self): - return self.e5add() - - def e5add(self): - left = self.e5sub() - if self.accept('plus'): - return ArithmeticNode(left.lineno, left.colno, 'add', left, self.e5add()) - return left - - def e5sub(self): - left = self.e5mul() - if self.accept('dash'): - return ArithmeticNode(left.lineno, left.colno, 'sub', left, self.e5sub()) - return left - - def e5mul(self): - left = self.e5div() - if self.accept('star'): - return ArithmeticNode(left.lineno, left.colno, 'mul', left, self.e5mul()) - return left - - def e5div(self): - left = self.e6() - if self.accept('fslash'): - return ArithmeticNode(left.lineno, left.colno, 'div', left, self.e5div()) - return left - - def e6(self): - if self.accept('not'): - return NotNode(self.current.lineno, self.current.colno, self.e7()) - if self.accept('dash'): - return UMinusNode(self.current.lineno, self.current.colno, self.e7()) - return self.e7() - - def e7(self): - left = self.e8() - if self.accept('lparen'): - args = self.args() - self.expect('rparen') - if not isinstance(left, IdNode): - raise ParseException('Function call must be applied to plain id', - left.lineno, left.colno) - left = FunctionNode(left.lineno, left.colno, left.value, args) - go_again = True - while go_again: - go_again = False - if self.accept('dot'): - go_again = True - left = self.method_call(left) - if self.accept('lbracket'): - go_again = True - left = self.index_call(left) - return left - - def e8(self): - if self.accept('lparen'): - e = self.statement() - self.expect('rparen') - return e - elif self.accept('lbracket'): - args = self.args() - self.expect('rbracket') - return ArrayNode(args) - else: - return self.e9() - - def e9(self): - t = self.current - if self.accept('true'): - return BooleanNode(t, True); - if self.accept('false'): - return BooleanNode(t, False) - if self.accept('id'): - return IdNode(t) - if self.accept('number'): - return NumberNode(t) - if self.accept('string'): - return StringNode(t) - return EmptyNode() - - def args(self): - s = self.statement() - a = ArgumentNode(s) - - while not isinstance(s, EmptyNode): - if self.accept('comma'): - a.append(s) - elif self.accept('colon'): - if not isinstance(s, IdNode): - raise ParseException('Keyword argument must be a plain identifier.', - s.lineno, s.colno) - a.set_kwarg(s.value, self.statement()) - if not self.accept('comma'): - return a - else: - a.append(s) - return a - s = self.statement() - return a - - def method_call(self, source_object): - methodname = self.e9() - if not(isinstance(methodname, IdNode)): - raise ParseException('Method name must be plain id', - self.current.lineno, self.current.colno) - self.expect('lparen') - args = self.args() - self.expect('rparen') - method = MethodNode(methodname.lineno, methodname.colno, source_object, methodname.value, args) - if self.accept('dot'): - return self.method_call(method) - return method - - def index_call(self, source_object): - index_statement = self.statement() - self.expect('rbracket') - return IndexNode(source_object, index_statement) - - def foreachblock(self): - t = self.current - self.expect('id') - varname = t - self.expect('colon') - items = self.statement() - block = self.codeblock() - return ForeachClauseNode(varname.lineno, varname.colno, varname, items, block) - - def ifblock(self): - condition = self.statement() - clause = IfClauseNode(condition.lineno, condition.colno) - block = self.codeblock() - clause.ifs.append(IfNode(clause.lineno, clause.colno, condition, block)) - self.elseifblock(clause) - clause.elseblock = self.elseblock() - return clause - - def elseifblock(self, clause): - while self.accept('elif'): - s = self.statement() - self.expect('eol') - b = self.codeblock() - clause.ifs.append(IfNode(s.lineno, s.colno, s, b)) - - def elseblock(self): - if self.accept('else'): - self.expect('eol') - return self.codeblock() - - def line(self): - if self.current == 'eol': - return EmptyNode() - if self.accept('if'): - block = self.ifblock() - self.expect('endif') - return block - if self.accept('foreach'): - block = self.foreachblock() - self.expect('endforeach') - return block - return self.statement() - - def codeblock(self): - block = CodeBlockNode(self.current.lineno, self.current.colno) - cond = True - while cond: - curline = self.line() - if not isinstance(curline, EmptyNode): - block.lines.append(curline) - cond = self.accept('eol') - return block |