statement.rs 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. use crate::{
  2. opcode::{self, ext_opcode, opcode},
  3. parser::{
  4. choice,
  5. comment_scope,
  6. extract,
  7. id,
  8. take,
  9. take_to_end_of_pkglength,
  10. take_u32,
  11. try_with_context,
  12. ParseResult,
  13. Parser,
  14. Propagate,
  15. },
  16. pkg_length::{pkg_length, PkgLength},
  17. term_object::{term_arg, term_list},
  18. AmlContext,
  19. AmlError,
  20. DebugVerbosity,
  21. };
  22. pub fn statement_opcode<'a, 'c>() -> impl Parser<'a, 'c, ()>
  23. where
  24. 'c: 'a,
  25. {
  26. /*
  27. * StatementOpcode := DefBreak | DefBreakPoint | DefContinue | DefFatal | DefIfElse | DefLoad | DefNoop |
  28. * DefNotify | DefRelease | DefReset | DefReturn | DefSignal | DefSleep | DefStall | DefWhile
  29. */
  30. comment_scope(
  31. DebugVerbosity::AllScopes,
  32. "StatementOpcode",
  33. choice!(
  34. def_break(),
  35. def_breakpoint(),
  36. def_continue(),
  37. def_fatal(),
  38. def_if_else(),
  39. def_noop(),
  40. def_return(),
  41. def_while()
  42. ),
  43. )
  44. }
  45. fn def_break<'a, 'c>() -> impl Parser<'a, 'c, ()>
  46. where
  47. 'c: 'a,
  48. {
  49. /*
  50. * DefBreak := 0xa5
  51. */
  52. opcode(opcode::DEF_BREAK_OP)
  53. .then(comment_scope(
  54. DebugVerbosity::AllScopes,
  55. "DefBreak",
  56. id().map(|()| -> Result<(), Propagate> { Err(Propagate::Break) }),
  57. ))
  58. .discard_result()
  59. }
  60. fn def_breakpoint<'a, 'c>() -> impl Parser<'a, 'c, ()>
  61. where
  62. 'c: 'a,
  63. {
  64. /*
  65. * DefBreakPoint := 0xcc
  66. * TODO: there is no debugger, so this doesn't do anything. If there was, this should stop execution and enter
  67. * the AML debugger.
  68. */
  69. opcode(opcode::DEF_BREAKPOINT_OP)
  70. .then(comment_scope(DebugVerbosity::AllScopes, "DefBreakPoint", id()))
  71. .discard_result()
  72. }
  73. fn def_continue<'a, 'c>() -> impl Parser<'a, 'c, ()>
  74. where
  75. 'c: 'a,
  76. {
  77. /*
  78. * DefContinue := 0x9f
  79. */
  80. opcode(opcode::DEF_CONTINUE_OP)
  81. .then(comment_scope(
  82. DebugVerbosity::AllScopes,
  83. "DefContinue",
  84. id().map(|()| -> Result<(), Propagate> { Err(Propagate::Continue) }),
  85. ))
  86. .discard_result()
  87. }
  88. fn def_fatal<'a, 'c>() -> impl Parser<'a, 'c, ()>
  89. where
  90. 'c: 'a,
  91. {
  92. /*
  93. * DefFatal := ExtOpPrefix 0x32 FatalType FatalCode FatalArg
  94. * FatalType := ByteData
  95. * FatalCode := DWordData
  96. * FatalArg := TermArg => Integer
  97. */
  98. ext_opcode(opcode::EXT_DEF_FATAL_OP)
  99. .then(comment_scope(
  100. DebugVerbosity::Scopes,
  101. "DefFatal",
  102. take().then(take_u32()).then(term_arg()).map_with_context(
  103. |((fatal_type, fatal_code), fatal_arg), context| -> (Result<(), Propagate>, &'c mut AmlContext) {
  104. let fatal_arg = try_with_context!(context, fatal_arg.as_integer(context));
  105. context.handler.handle_fatal_error(fatal_type, fatal_code, fatal_arg);
  106. (Err(Propagate::Err(AmlError::FatalError)), context)
  107. },
  108. ),
  109. ))
  110. .discard_result()
  111. }
  112. fn def_if_else<'a, 'c>() -> impl Parser<'a, 'c, ()>
  113. where
  114. 'c: 'a,
  115. {
  116. /*
  117. * DefIfElse := 0xa0 PkgLength Predicate TermList DefElse
  118. * Predicate := TermArg => Integer (0 = false, >0 = true)
  119. * DefElse := Nothing | <0xa1 PkgLength TermList>
  120. */
  121. let maybe_else_opcode = |input, context| match opcode(opcode::DEF_ELSE_OP).parse(input, context) {
  122. Err((x, y, Propagate::Err(AmlError::UnexpectedEndOfStream))) => {
  123. Err((x, y, Propagate::Err(AmlError::WrongParser)))
  124. }
  125. r => r,
  126. };
  127. opcode(opcode::DEF_IF_ELSE_OP)
  128. .then(comment_scope(
  129. DebugVerbosity::Scopes,
  130. "DefIfElse",
  131. pkg_length()
  132. .then(term_arg())
  133. .feed(|(length, predicate_arg)| {
  134. take_to_end_of_pkglength(length)
  135. .map(move |then_branch| Ok((predicate_arg.as_bool()?, then_branch)))
  136. })
  137. .then(choice!(
  138. maybe_else_opcode
  139. .then(comment_scope(
  140. DebugVerbosity::AllScopes,
  141. "DefElse",
  142. pkg_length().feed(|length| take_to_end_of_pkglength(length)),
  143. ))
  144. .map(|((), else_branch): ((), &[u8])| Ok(else_branch)),
  145. // TODO: can this be `id().map(&[])`?
  146. |input, context| -> ParseResult<'a, 'c, &[u8]> {
  147. /*
  148. * This path parses an DefIfElse that doesn't have an else branch. We simply
  149. * return an empty slice, so if the predicate is false, we don't execute
  150. * anything.
  151. */
  152. Ok((input, context, &[]))
  153. }
  154. ))
  155. .map_with_context(|((predicate, then_branch), else_branch), context| {
  156. let branch = if predicate { then_branch } else { else_branch };
  157. match term_list(PkgLength::from_raw_length(branch, branch.len() as u32).unwrap())
  158. .parse(branch, context)
  159. {
  160. Ok((_, context, result)) => (Ok(result), context),
  161. Err((_, context, err)) => (Err(err), context),
  162. }
  163. }),
  164. ))
  165. .discard_result()
  166. }
  167. fn def_noop<'a, 'c>() -> impl Parser<'a, 'c, ()>
  168. where
  169. 'c: 'a,
  170. {
  171. /*
  172. * DefNoop := 0xa3
  173. */
  174. opcode(opcode::DEF_NOOP_OP).then(comment_scope(DebugVerbosity::AllScopes, "DefNoop", id())).discard_result()
  175. }
  176. fn def_return<'a, 'c>() -> impl Parser<'a, 'c, ()>
  177. where
  178. 'c: 'a,
  179. {
  180. /*
  181. * DefReturn := 0xa4 ArgObject
  182. * ArgObject := TermArg => DataRefObject
  183. */
  184. opcode(opcode::DEF_RETURN_OP)
  185. .then(comment_scope(
  186. DebugVerbosity::Scopes,
  187. "DefReturn",
  188. term_arg().map(|return_arg| -> Result<(), Propagate> {
  189. /*
  190. * To return a value, we want to halt execution of the method and propagate the
  191. * return value all the way up to the start of the method invocation. To do this,
  192. * we emit a special error that is intercepted during method invocation and turned
  193. * into a valid result.
  194. */
  195. Err(Propagate::Return(return_arg))
  196. }),
  197. ))
  198. .discard_result()
  199. }
  200. fn def_while<'a, 'c>() -> impl Parser<'a, 'c, ()>
  201. where
  202. 'c: 'a,
  203. {
  204. /*
  205. * DefWhile := 0xa2 PkgLength Predicate TermList
  206. * Predicate := TermArg => Integer (0 = false, >0 = true)
  207. *
  208. * Parsing this does something a little unusual - it 'extracts' the predicate when it's first parsed, which
  209. * allows us to reevaluate it to see if we should break out of the while yet. This is required, to make sure
  210. * we're observing changes to the context between the iterations of the loop.
  211. */
  212. opcode(opcode::DEF_WHILE_OP)
  213. .then(comment_scope(
  214. DebugVerbosity::Scopes,
  215. "DefWhile",
  216. pkg_length()
  217. .then(extract(term_arg()))
  218. .feed(move |(length, (first_predicate, predicate_stream))| {
  219. take_to_end_of_pkglength(length)
  220. .map(move |body| Ok((first_predicate.clone(), predicate_stream, body)))
  221. })
  222. .map_with_context(|(first_predicate, predicate_stream, body), mut context| {
  223. if !try_with_context!(context, first_predicate.as_bool()) {
  224. return (Ok(()), context);
  225. }
  226. loop {
  227. match term_list(PkgLength::from_raw_length(body, body.len() as u32).unwrap())
  228. .parse(body, context)
  229. {
  230. Ok((_, new_context, result)) => {
  231. context = new_context;
  232. }
  233. Err((_, new_context, Propagate::Break)) => {
  234. context = new_context;
  235. break;
  236. }
  237. Err((_, new_context, Propagate::Continue)) => {
  238. // We don't need to do anything special here - the `Propagate::Continue` bubbles
  239. // up, and then we can just move on to checking the predicate for the next
  240. // iteration.
  241. context = new_context;
  242. }
  243. Err((_, context, err)) => return (Err(err), context),
  244. }
  245. // Reevaluate the predicate to see if we should break out of the loop yet
  246. let predicate =
  247. match comment_scope(DebugVerbosity::AllScopes, "WhilePredicate", term_arg())
  248. .parse(predicate_stream, context)
  249. {
  250. Ok((_, new_context, result)) => {
  251. context = new_context;
  252. try_with_context!(context, result.as_bool())
  253. }
  254. Err((_, context, err)) => return (Err(err), context),
  255. };
  256. if !predicate {
  257. break;
  258. }
  259. }
  260. (Ok(()), context)
  261. }),
  262. ))
  263. .discard_result()
  264. }