aboutsummaryrefslogtreecommitdiff
path: root/qls/parser/lexer.py
blob: f7b8b98b9eea2340b59d24438d98cd76b8a810d4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
from ply.lex import lex


class QLSLexer:
    def __init__(self):
        self.__errors = []
        self.__lexer = None

    @property
    def lexer(self):
        return self.__lexer

    @property
    def errors(self):
        return self.__errors

    def build(self):
        self.__lexer = lex(module=self)

    def tokenize(self, data):
        self.__errors = []
        self.lexer.input(data)
        token = self.lexer.token()
        tokens = [token]

        while token:
            token = self.lexer.token()
            tokens.append(token)

        return tokens

    tokens = [
        'COLON', 'COMMA',
        'LEFT_BRACE', 'RIGHT_BRACE',
        'LEFT_BRACKET', 'RIGHT_BRACKET',
        'IDENTIFIER',
        'HEX_COLOR',
        'INTEGER_LITERAL', 'STRING_LITERAL',
    ]

    # List of reserved keywords
    reserved = {
        'stylesheet':   'STYLESHEET',
        'page':         'PAGE',
        'section':      'SECTION',
        'question':     'QUESTION',
        'default':      'DEFAULT',

        # Properties
        'height':       'HEIGHT',
        'width':        'WIDTH',
        'font':         'FONT',
        'fontsize':     'FONT_SIZE',
        'color':        'COLOR',
        'widget':       'WIDGET',

        # QL types
        'boolean':      'BOOLEAN',
        'date':         'DATE',
        'decimal':      'DECIMAL',
        'integer':      'INTEGER',
        'money':        'MONEY',
        'string':       'STRING',

        # Widgets
        'calendar':     'CALENDAR',
        'checkbox':     'CHECKBOX',
        'line_edit':    'LINE_EDIT',
        'spinbox':      'SPINBOX',
        'radio':        'RADIO',
    }

    tokens += list(reserved.values())

    # Regular expression rules for simple tokens
    t_ignore = ' \t'

    t_COLON = r':'
    t_COMMA = r','

    t_LEFT_BRACE = r'\{'
    t_RIGHT_BRACE = r'\}'

    t_LEFT_BRACKET = r'\('
    t_RIGHT_BRACKET = r'\)'

    t_HEX_COLOR = r'\#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})'

    @staticmethod
    def t_newline(token):
        r'\n+'
        token.lexer.lineno += len(token.value)

    @staticmethod
    def t_eof(token):
        token.lexer.lineno = 1

    @staticmethod
    def t_INTEGER_LITERAL(token):
        r'\d+'
        token.value = int(token.value)
        return token

    @staticmethod
    def t_STRING_LITERAL(token):
        r'\"(.+?)\"'
        token.value = token.value[1:-1]
        return token

    def t_IDENTIFIER(self, token):
        r'[a-zA-Z][a-zA-Z_0-9]*'
        token.type = self.reserved.get(token.value, 'IDENTIFIER')  # Check for reserved words
        return token

    def t_error(self, token):
        self.errors.append("Illegal character '%s'" % token.value[0])
        token.lexer.skip(1)