1# Copyright 2004-2021 Tom Rothamel <pytom@bishoujo.us> 2# 3# Permission is hereby granted, free of charge, to any person 4# obtaining a copy of this software and associated documentation files 5# (the "Software"), to deal in the Software without restriction, 6# including without limitation the rights to use, copy, modify, merge, 7# publish, distribute, sublicense, and/or sell copies of the Software, 8# and to permit persons to whom the Software is furnished to do so, 9# subject to the following conditions: 10# 11# The above copyright notice and this permission notice shall be 12# included in all copies or substantial portions of the Software. 13# 14# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 22from __future__ import division, absolute_import, with_statement, print_function, unicode_literals 23from renpy.compat import * 24 25import renpy.test.testast as testast 26import renpy 27 28 29def parse_click(l, loc, target): 30 31 rv = testast.Click(loc, target) 32 33 while True: 34 if l.keyword('button'): 35 rv.button = int(l.require(l.integer)) 36 37 elif l.keyword('pos'): 38 rv.position = l.require(l.simple_expression) 39 40 elif l.keyword('always'): 41 rv.always = True 42 43 else: 44 break 45 46 return rv 47 48 49def parse_type(l, loc, keys): 50 rv = testast.Type(loc, keys) 51 52 while True: 53 54 if l.keyword('pattern'): 55 rv.pattern = l.require(l.string) 56 57 elif l.keyword('pos'): 58 rv.position = l.require(l.simple_expression) 59 60 else: 61 break 62 63 return rv 64 65 66def parse_move(l, loc): 67 rv = testast.Move(loc) 68 69 rv.position = l.require(l.simple_expression) 70 71 while True: 72 73 if l.keyword('pattern'): 74 rv.pattern = l.require(l.string) 75 76 else: 77 break 78 79 return rv 80 81 82def parse_drag(l, loc): 83 84 points = l.require(l.simple_expression) 85 86 rv = testast.Drag(loc, points) 87 88 while True: 89 if l.keyword('button'): 90 rv.button = int(l.require(l.integer)) 91 92 elif l.keyword('pattern'): 93 rv.pattern = l.require(l.string) 94 95 elif l.keyword('steps'): 96 rv.steps = int(l.require(l.integer)) 97 98 else: 99 break 100 101 return rv 102 103 104def parse_clause(l, loc): 105 if l.keyword("run"): 106 107 expr = l.require(l.simple_expression) 108 return testast.Action(loc, expr) 109 110 elif l.keyword("pause"): 111 112 expr = l.require(l.simple_expression) 113 return testast.Pause(loc, expr) 114 115 elif l.keyword("label"): 116 117 name = l.require(l.name) 118 return testast.Label(loc, name) 119 120 elif l.keyword("type"): 121 122 name = l.name() 123 if name is not None: 124 return parse_type(l, loc, [ name ]) 125 126 string = l.require(l.string) 127 128 return parse_type(l, loc, list(string)) 129 130 elif l.keyword("drag"): 131 132 return parse_drag(l, loc) 133 134 elif l.keyword("move"): 135 return parse_move(l, loc) 136 137 elif l.keyword("click"): 138 return parse_click(l, loc, None) 139 140 elif l.keyword("scroll"): 141 pattern = l.require(l.string) 142 return testast.Scroll(loc, pattern) 143 144 else: 145 target = l.string() 146 if target: 147 return parse_click(l, loc, target) 148 149 l.error("Expected a test language statement or clause.") 150 return testast.Click(loc, target) 151 152 153def parse_statement(l, loc): 154 155 if l.keyword('python'): 156 157 l.require(':') 158 159 l.expect_block("python block") 160 161 source = l.python_block() 162 163 code = renpy.ast.PyCode(source, loc) 164 return testast.Python(loc, code) 165 166 if l.keyword("if"): 167 l.expect_block("if block") 168 169 condition = parse_clause(l, loc) 170 l.require(':') 171 block = parse_block(l.subblock_lexer(False), loc) 172 173 return testast.If(loc, condition, block) 174 175 # Single-line statements only below here. 176 177 l.expect_noblock('statement') 178 179 if l.match(r'\$'): 180 181 source = l.require(l.rest) 182 183 code = renpy.ast.PyCode(source, loc) 184 return testast.Python(loc, code) 185 186 elif l.keyword('assert'): 187 source = l.require(l.rest) 188 return testast.Assert(loc, source) 189 190 elif l.keyword('jump'): 191 target = l.require(l.name) 192 return testast.Jump(loc, target) 193 194 elif l.keyword('call'): 195 target = l.require(l.name) 196 return testast.Call(loc, target) 197 198 rv = parse_clause(l, loc) 199 200 if l.keyword("until"): 201 right = parse_clause(l, loc) 202 rv = testast.Until(loc, rv, right) 203 204 return rv 205 206 207def parse_block(l, loc): 208 """ 209 Parses a named block of testcase statements. 210 """ 211 212 block = [ ] 213 214 while l.advance(): 215 stmt = parse_statement(l, l.get_location()) 216 block.append(stmt) 217 218 l.expect_eol() 219 220 return testast.Block(loc, block) 221