call-graph #1

Merged
dergrimm merged 4 commits from call-graph into main 2022-10-26 09:19:45 +00:00
7 changed files with 109 additions and 83 deletions
Showing only changes of commit b607b6f8ed - Show all commits

115
Cargo.lock generated
View file

@ -19,9 +19,9 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
[[package]] [[package]]
name = "anyhow" name = "anyhow"
version = "1.0.63" version = "1.0.65"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a26fa4d7e3f2eebadf743988fc8aec9fa9a9e82611acafd77c1462ed6262440a" checksum = "98161a4e3e2184da77bb14f02184cdd111e83bbbcc9979dfee3c44b9a85f5602"
dependencies = [ dependencies = [
"backtrace", "backtrace",
] ]
@ -66,9 +66,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]] [[package]]
name = "block-buffer" name = "block-buffer"
version = "0.9.0" version = "0.10.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" checksum = "69cce20737498f97b993470a6e536b8523f0af7892a4f928cceb1ac5e52ebe7e"
dependencies = [ dependencies = [
"generic-array", "generic-array",
] ]
@ -87,9 +87,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]] [[package]]
name = "clap" name = "clap"
version = "3.2.20" version = "3.2.22"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23b71c3ce99b7611011217b366d923f1d0a7e07a92bb2dbf1e84508c673ca3bd" checksum = "86447ad904c7fb335a790c9d7fe3d0d971dc523b8ccd1561a520de9a85302750"
dependencies = [ dependencies = [
"atty", "atty",
"bitflags", "bitflags",
@ -126,13 +126,13 @@ dependencies = [
[[package]] [[package]]
name = "console" name = "console"
version = "0.15.1" version = "0.15.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89eab4d20ce20cea182308bca13088fecea9c05f6776cf287205d41a0ed3c847" checksum = "c050367d967ced717c04b65d8c619d863ef9292ce0c5760028655a2fb298718c"
dependencies = [ dependencies = [
"encode_unicode", "encode_unicode",
"lazy_static",
"libc", "libc",
"once_cell",
"terminal_size", "terminal_size",
"unicode-width", "unicode-width",
"winapi", "winapi",
@ -140,13 +140,23 @@ dependencies = [
[[package]] [[package]]
name = "cpufeatures" name = "cpufeatures"
version = "0.2.4" version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc948ebb96241bb40ab73effeb80d9f93afaad49359d159a5e61be51619fe813" checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320"
dependencies = [ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "crypto-common"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
dependencies = [
"generic-array",
"typenum",
]
[[package]] [[package]]
name = "dependency-graph" name = "dependency-graph"
version = "0.1.5" version = "0.1.5"
@ -158,11 +168,12 @@ dependencies = [
[[package]] [[package]]
name = "digest" name = "digest"
version = "0.9.0" version = "0.10.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" checksum = "adfbc57365a37acbd2ebf2b64d7e69bb766e2fea813521ed536f5d0520dcf86c"
dependencies = [ dependencies = [
"generic-array", "block-buffer",
"crypto-common",
] ]
[[package]] [[package]]
@ -274,9 +285,9 @@ dependencies = [
[[package]] [[package]]
name = "itertools" name = "itertools"
version = "0.10.3" version = "0.10.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3" checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
dependencies = [ dependencies = [
"either", "either",
] ]
@ -289,9 +300,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.132" version = "0.2.135"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8371e4e5341c3a96db127eb2465ac681ced4c433e01dd0e938adbef26ba93ba5" checksum = "68783febc7782c6c5cb401fbda4de5a9898be1762314da0bb2c10ced61f18b0c"
[[package]] [[package]]
name = "memchr" name = "memchr"
@ -301,9 +312,9 @@ checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
[[package]] [[package]]
name = "miniz_oxide" name = "miniz_oxide"
version = "0.5.3" version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6f5c75688da582b8ffc1f1799e9db273f32133c49e048f614d22ec3256773ccc" checksum = "96590ba8f175222643a85693f33d26e9c8a015f599c216509b1a6894af675d34"
dependencies = [ dependencies = [
"adler", "adler",
] ]
@ -328,15 +339,9 @@ dependencies = [
[[package]] [[package]]
name = "once_cell" name = "once_cell"
version = "1.13.1" version = "1.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "074864da206b4973b84eb91683020dbefd6a8c3f0f38e054d93954e891935e4e" checksum = "e82dad04139b71a90c080c8463fe0dc7902db5192d939bd0950f074d014339e1"
[[package]]
name = "opaque-debug"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
[[package]] [[package]]
name = "os_str_bytes" name = "os_str_bytes"
@ -395,18 +400,18 @@ dependencies = [
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.36" version = "1.0.47"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029" checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725"
dependencies = [ dependencies = [
"unicode-xid", "unicode-ident",
] ]
[[package]] [[package]]
name = "quote" name = "quote"
version = "1.0.19" version = "1.0.21"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f53dc8cf16a769a6f677e09e7ff2cd4be1ea0f48754aac39520536962011de0d" checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
] ]
@ -440,9 +445,9 @@ dependencies = [
[[package]] [[package]]
name = "rand_core" name = "rand_core"
version = "0.6.3" version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
dependencies = [ dependencies = [
"getrandom", "getrandom",
] ]
@ -455,9 +460,9 @@ checksum = "c5e9af64574935e39f24d1c0313a997c8b880ca0e087c888bc6af8af31579847"
[[package]] [[package]]
name = "rust-embed" name = "rust-embed"
version = "6.4.0" version = "6.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a17e5ac65b318f397182ae94e532da0ba56b88dd1200b774715d36c4943b1c3" checksum = "e26934cd67a1da1165efe61cba4047cc1b4a526019da609fcce13a1000afb5fa"
dependencies = [ dependencies = [
"rust-embed-impl", "rust-embed-impl",
"rust-embed-utils", "rust-embed-utils",
@ -466,9 +471,9 @@ dependencies = [
[[package]] [[package]]
name = "rust-embed-impl" name = "rust-embed-impl"
version = "6.2.0" version = "6.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94e763e24ba2bf0c72bc6be883f967f794a019fafd1b86ba1daff9c91a7edd30" checksum = "e35d7b402e273544cc08e0824aa3404333fab8a90ac43589d3d5b72f4b346e12"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -479,9 +484,9 @@ dependencies = [
[[package]] [[package]]
name = "rust-embed-utils" name = "rust-embed-utils"
version = "7.2.0" version = "7.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "756feca3afcbb1487a1d01f4ecd94cf8ec98ea074c55a69e7136d29fb6166029" checksum = "c1669d81dfabd1b5f8e2856b8bbe146c6192b0ba22162edc738ac0a5de18f054"
dependencies = [ dependencies = [
"sha2", "sha2",
"walkdir", "walkdir",
@ -504,15 +509,13 @@ dependencies = [
[[package]] [[package]]
name = "sha2" name = "sha2"
version = "0.9.9" version = "0.10.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0"
dependencies = [ dependencies = [
"block-buffer",
"cfg-if", "cfg-if",
"cpufeatures", "cpufeatures",
"digest", "digest",
"opaque-debug",
] ]
[[package]] [[package]]
@ -523,13 +526,13 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]] [[package]]
name = "syn" name = "syn"
version = "1.0.94" version = "1.0.102"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a07e33e919ebcd69113d5be0e4d70c5707004ff45188910106854f38b960df4a" checksum = "3fcd952facd492f9be3ef0d0b7032a6e442ee9b361d4acc2b1d0c4aaa5f613a1"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"unicode-xid", "unicode-ident",
] ]
[[package]] [[package]]
@ -553,9 +556,9 @@ dependencies = [
[[package]] [[package]]
name = "textwrap" name = "textwrap"
version = "0.15.0" version = "0.15.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb" checksum = "949517c0cf1bf4ee812e2e07e08ab448e3ae0d23472aee8a06c985f0c8815b16"
[[package]] [[package]]
name = "typenum" name = "typenum"
@ -570,16 +573,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ccb97dac3243214f8d8507998906ca3e2e0b900bf9bf4870477f125b82e68f6e" checksum = "ccb97dac3243214f8d8507998906ca3e2e0b900bf9bf4870477f125b82e68f6e"
[[package]] [[package]]
name = "unicode-width" name = "unicode-ident"
version = "0.1.9" version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3"
[[package]] [[package]]
name = "unicode-xid" name = "unicode-width"
version = "0.2.3" version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "957e51f3646910546462e67d5f7599b9e4fb8acdd304b087a6494730f9eebf04" checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b"
[[package]] [[package]]
name = "version_check" name = "version_check"

View file

@ -93,7 +93,6 @@ impl Data {
"tlr" => 0x06, "tlr" => 0x06,
"tlrc" => 0x07, "tlrc" => 0x07,
"tls" => 0x08, "tls" => 0x08,
// "ld" => 0x09,
"dbg" => 0x09, "dbg" => 0x09,
"alu" => 0x0a, "alu" => 0x0a,
"get" => 0x0b, "get" => 0x0b,
@ -104,7 +103,6 @@ impl Data {
Some(x) => x.resolve_number(self)?, Some(x) => x.resolve_number(self)?,
None => 0, None => 0,
}; };
if a == 0 { if a == 0 {
Ok(Some(vec![opcode | 0b10000000])) Ok(Some(vec![opcode | 0b10000000]))
} else { } else {

View file

@ -235,6 +235,7 @@ pub fn emulate(data: &mut Data) -> Result<()> {
match data.reg_opc { match data.reg_opc {
0x00 => {} 0x00 => {}
0x01 => { 0x01 => {
data.tmp = data.reg_arg;
data.memory[data.reg_sp as usize] = data.reg_arg; data.memory[data.reg_sp as usize] = data.reg_arg;
data.reg_sp = data.reg_sp.wrapping_add(1); data.reg_sp = data.reg_sp.wrapping_add(1);
} }
@ -263,11 +264,6 @@ pub fn emulate(data: &mut Data) -> Result<()> {
data.memory[data.reg_sp as usize] = data.tmp; data.memory[data.reg_sp as usize] = data.tmp;
data.reg_sp = data.reg_sp.wrapping_add(1); data.reg_sp = data.reg_sp.wrapping_add(1);
} }
// 0x09 => {
// data.reg_sp = data.reg_sp.wrapping_sub(1);
// data.set_register(data.reg_arg as u8, data.stack[data.reg_sp as usize]);
// data.stack[data.reg_sp as usize] = 0;
// }
0x09 => { 0x09 => {
println!( println!(
"[DEBUG]: [{}]", "[DEBUG]: [{}]",

View file

@ -73,7 +73,7 @@ impl Data {
origin, origin,
self.words self.words
.get(&x) .get(&x)
.context(format!("Could not get referenced word: {}", x))? .context(format!("Could not get already resolved referenced word: {}", x))?
.callable_graph_node, .callable_graph_node,
(), (),
); );
@ -83,12 +83,15 @@ impl Data {
origin, origin,
self.conditions self.conditions
.get(x) .get(x)
.context(format!("Could not get referenced condition: {}", x))? .context(format!("Could not get already resolved referenced condition: {}", x))?
.callable_graph_node, .callable_graph_node,
(), (),
); );
} }
Instruction::Multiple { instruction, count: _ } => { Instruction::Multiple {
instruction,
count: _,
} => {
self.add_graph_edge(origin, *instruction)?; self.add_graph_edge(origin, *instruction)?;
} }
_ => {} _ => {}
@ -142,7 +145,7 @@ impl Data {
}); });
} }
parser::ast::Node::Number(x) => { parser::ast::Node::Number(x) => {
instructions.push(instruction::Instruction::Push(x as u16)); instructions.push(instruction::Instruction::Push(x));
} }
parser::ast::Node::WordDefinition { parser::ast::Node::WordDefinition {
name, name,

View file

@ -7,7 +7,7 @@ pub enum Instruction {
Nop, Nop,
Debug, Debug,
Quit, Quit,
Push(u16), Push(i32),
Drop, Drop,
Depth, Depth,
Pick, Pick,
@ -92,7 +92,7 @@ impl compiler::Compilable<compiler::Data, hence::parser::ast::Body> for Instruct
}]), }]),
Instruction::Push(x) => Ok(vec![hence::parser::ast::Node::Call { Instruction::Push(x) => Ok(vec![hence::parser::ast::Node::Call {
name: "push".to_string(), name: "push".to_string(),
arg: Some(hence::arg::Arg::Number(*x)), arg: Some(hence::arg::Arg::Number(*x as u16)),
}]), }]),
Instruction::Drop => Ok(vec![hence::parser::ast::Node::Call { Instruction::Drop => Ok(vec![hence::parser::ast::Node::Call {
name: "pop".to_string(), name: "pop".to_string(),
@ -1244,7 +1244,12 @@ impl compiler::Compilable<compiler::Data, hence::parser::ast::Body> for Instruct
// }, // },
Instruction::Call(x) => bail!("Unknown word: {}", x), Instruction::Call(x) => bail!("Unknown word: {}", x),
Instruction::AsmQuote(x) => Ok(hence::parser::parse(hence::lexer::lex(x)?)?.body), Instruction::AsmQuote(x) => Ok(hence::parser::parse(hence::lexer::lex(x)?)?.body),
Instruction::Condition(x) => Ok(vec![]), // Instruction::Condition(x) => Ok(vec![]),
Instruction::Condition(x) => {
dbg!(x);
Ok(vec![])
}
Instruction::Multiple { instruction, count } => { Instruction::Multiple { instruction, count } => {
if *count == 0 { if *count == 0 {
@ -1255,6 +1260,18 @@ impl compiler::Compilable<compiler::Data, hence::parser::ast::Body> for Instruct
match **instruction { match **instruction {
Instruction::Nop => Ok(Instruction::Nop.compile(data)?), Instruction::Nop => Ok(Instruction::Nop.compile(data)?),
Instruction::Quit => Ok(Instruction::Quit.compile(data)?), Instruction::Quit => Ok(Instruction::Quit.compile(data)?),
Instruction::Push(x) => Ok([
Instruction::Push(x).compile(data)?,
[hence::parser::ast::Node::Call {
name: "tls".to_string(),
arg: None,
}]
.into_iter()
.cycle()
.take(count - 1)
.collect(),
]
.concat()),
Instruction::Depth => Ok([ Instruction::Depth => Ok([
Instruction::Depth.compile(data)?, Instruction::Depth.compile(data)?,
Instruction::Multiple { Instruction::Multiple {
@ -1371,7 +1388,7 @@ impl compiler::Compilable<compiler::Data, hence::parser::ast::Body> for Instruct
arg: None, arg: None,
}, },
]), ]),
_ => bail!("Remainder of count % 3 cannot be higher than 3"), x => bail!("Remainder of count % 3 cannot be higher than 3: {}", x),
}, },
Instruction::Nip => Ok([ Instruction::Nip => Ok([
vec![hence::parser::ast::Node::MacroCall { vec![hence::parser::ast::Node::MacroCall {

View file

@ -61,4 +61,3 @@ return_call_stack_jump:
tsr CORE_REG_C tsr CORE_REG_C
get get
tlr CORE_REG_PC tlr CORE_REG_PC

View file

@ -4,8 +4,8 @@ use itertools::Itertools;
#[derive(Debug)] #[derive(Debug)]
pub enum Token { pub enum Token {
Newline(String), Newline(usize),
Whitespace(String), Whitespace(usize),
ParenComment(String), ParenComment(String),
BackslashComment(String), BackslashComment(String),
@ -19,7 +19,8 @@ pub enum Token {
impl ToCode for Token { impl ToCode for Token {
fn to_code(&self) -> String { fn to_code(&self) -> String {
match self { match self {
Token::Newline(x) | Token::Whitespace(x) => x.clone(), Token::Newline(x) => ["\n"].into_iter().cycle().take(*x).join(""),
Token::Whitespace(x) => [" "].into_iter().cycle().take(*x).join(""),
Token::ParenComment(x) => format!("( {})", x), Token::ParenComment(x) => format!("( {})", x),
Token::BackslashComment(x) => format!("\\{}", x), Token::BackslashComment(x) => format!("\\{}", x),
Token::DoubleDashComment(x) => format!("-- {}", x), Token::DoubleDashComment(x) => format!("-- {}", x),
@ -37,21 +38,19 @@ pub fn lex(source: &str) -> Result<Vec<Token>> {
let mut chars = source.chars().peekable(); let mut chars = source.chars().peekable();
let mut tokens: Vec<Token> = vec![]; let mut tokens: Vec<Token> = vec![];
while let Some(&c) = chars.peek() { while let Some(c) = chars.peek() {
tokens.push(match c { tokens.push(match c {
'\n' => Token::Newline(chars.peeking_take_while(|&c| c == '\n').collect()), '\n' => Token::Newline(chars.peeking_take_while(|&c| c == '\n').count()),
_ if c.is_whitespace() => { _ if c.is_whitespace() => {
Token::Whitespace(chars.peeking_take_while(|&c| c.is_whitespace()).collect()) Token::Whitespace(chars.peeking_take_while(|&c| c.is_whitespace()).count())
}
'\\' => {
chars.next();
Token::BackslashComment(chars.peeking_take_while(|&c| c != '\n').collect())
} }
'\\' => Token::BackslashComment(chars.peeking_take_while(|&c| c != '\n').collect()),
_ if c.is_numeric() => { _ if c.is_numeric() => {
Token::Number(chars.peeking_take_while(|&c| !is_space(c)).collect()) Token::Number(chars.peeking_take_while(|&c| !is_space(c)).collect())
} }
_ => { _ => {
let x: String = chars.peeking_take_while(|&c| !is_space(c)).collect(); let x: String = chars.peeking_take_while(|&c| !is_space(c)).collect();
let mut iter = x.chars();
match x.as_str() { match x.as_str() {
"(" => Token::ParenComment( "(" => Token::ParenComment(
@ -64,6 +63,17 @@ pub fn lex(source: &str) -> Result<Vec<Token>> {
mode: x.chars().take(x.len() - 1).collect(), mode: x.chars().take(x.len() - 1).collect(),
string: chars.by_ref().skip(1).take_while(|&c| c != '"').collect(), string: chars.by_ref().skip(1).take_while(|&c| c != '"').collect(),
}, },
_ if iter.next() == Some('-') => {
if let Some(c) = iter.next() {
if c.is_numeric() {
Token::Number(x)
} else {
Token::Word(x)
}
} else {
Token::Word(x)
}
}
_ => Token::Word(x), _ => Token::Word(x),
} }
} }