Actually just three programming languages in a trenchcoat
at main 201 lines 13 kB view raw
1use super::*; 2use crate::{Parser, Spanned}; 3use source_span::Span; 4use trilogy_scanner::{ 5 Token, 6 TokenType::{self, *}, 7}; 8 9/// An assignment statement. An assignment may have one of many "strategies". 10/// 11/// [`FunctionAssignment`][] is parsed separately. 12/// 13/// ```trilogy 14/// lhs = rhs 15/// ``` 16#[derive(Clone, Debug)] 17pub struct AssignmentStatement { 18 pub lhs: Expression, 19 pub strategy: AssignmentStrategy, 20 pub rhs: Expression, 21 pub span: Span, 22} 23 24impl Spanned for AssignmentStatement { 25 fn span(&self) -> Span { 26 self.span 27 } 28} 29 30impl AssignmentStatement { 31 pub(crate) const ASSIGNMENT_OPERATOR: [TokenType; 24] = [ 32 OpEq, 33 OpAmpAmpEq, 34 OpPipePipeEq, 35 OpAmpEq, 36 OpPipeEq, 37 OpCaretEq, 38 OpShrEq, 39 OpShlEq, 40 OpShrExEq, 41 OpShlExEq, 42 OpShrConEq, 43 OpShlConEq, 44 OpGlueEq, 45 OpPlusEq, 46 OpMinusEq, 47 OpStarEq, 48 OpSlashEq, 49 OpSlashSlashEq, 50 OpPercentEq, 51 OpStarStarEq, 52 OpLtLtEq, 53 OpGtGtEq, 54 OpColonEq, 55 OpDotEq, 56 ]; 57 58 pub(crate) fn parse(parser: &mut Parser, lhs: Expression) -> SyntaxResult<Self> { 59 let strategy = AssignmentStrategy::parse(parser)?; 60 let rhs = Expression::parse(parser)?; 61 Ok(Self { 62 span: lhs.span().union(rhs.span()), 63 lhs, 64 strategy, 65 rhs, 66 }) 67 } 68} 69 70/// The strategy of an assignment statement. 71#[derive(Clone, Debug, Spanned)] 72pub enum AssignmentStrategy { 73 Direct(Token), 74 And(Token), 75 Or(Token), 76 Add(Token), 77 Subtract(Token), 78 Multiply(Token), 79 Divide(Token), 80 Remainder(Token), 81 Power(Token), 82 IntDivide(Token), 83 BitwiseAnd(Token), 84 BitwiseOr(Token), 85 BitwiseXor(Token), 86 LeftShift(Token), 87 RightShift(Token), 88 LeftShiftExtend(Token), 89 RightShiftExtend(Token), 90 LeftShiftContract(Token), 91 RightShiftContract(Token), 92 Glue(Token), 93 Compose(Token), 94 RCompose(Token), 95 Access(Token), 96 Cons(Token), 97} 98 99impl AssignmentStrategy { 100 fn parse(parser: &mut Parser) -> SyntaxResult<Self> { 101 let token = parser 102 .expect(AssignmentStatement::ASSIGNMENT_OPERATOR) 103 .map_err(|token| { 104 parser.expected(token, "expected assignment operator (ending with `=`)") 105 })?; 106 Ok(match token.token_type { 107 OpEq => Self::Direct(token), 108 OpAmpAmpEq => Self::And(token), 109 OpPipePipeEq => Self::Or(token), 110 OpAmpEq => Self::BitwiseAnd(token), 111 OpPipeEq => Self::BitwiseOr(token), 112 OpCaretEq => Self::BitwiseXor(token), 113 OpShlEq => Self::LeftShift(token), 114 OpShrEq => Self::RightShift(token), 115 OpShlExEq => Self::LeftShiftExtend(token), 116 OpShrExEq => Self::RightShiftExtend(token), 117 OpShlConEq => Self::LeftShiftContract(token), 118 OpShrConEq => Self::RightShiftContract(token), 119 OpGlueEq => Self::Glue(token), 120 OpPlusEq => Self::Add(token), 121 OpMinusEq => Self::Subtract(token), 122 OpStarEq => Self::Multiply(token), 123 OpSlashEq => Self::Divide(token), 124 OpSlashSlashEq => Self::IntDivide(token), 125 OpPercentEq => Self::Remainder(token), 126 OpStarStarEq => Self::Power(token), 127 OpLtLtEq => Self::RCompose(token), 128 OpGtGtEq => Self::Compose(token), 129 OpColonEq => Self::Cons(token), 130 OpDotEq => Self::Access(token), 131 _ => unreachable!(), 132 }) 133 } 134} 135 136#[cfg(test)] 137mod test { 138 use super::*; 139 140 test_parse!(assignment_direct: "x = 5" => Statement::parse => Statement::Assignment(AssignmentStatement { strategy: AssignmentStrategy::Direct(_), .. })); 141 test_parse!(assignment_and: "x &&= 5" => Statement::parse => Statement::Assignment(AssignmentStatement { strategy: AssignmentStrategy::And(_), .. })); 142 test_parse!(assignment_or: "x ||= 5" => Statement::parse => Statement::Assignment(AssignmentStatement { strategy: AssignmentStrategy::Or(_), .. })); 143 test_parse!(assignment_add: "x += 5" => Statement::parse => Statement::Assignment(AssignmentStatement { strategy: AssignmentStrategy::Add(_), .. })); 144 test_parse!(assignment_subtract: "x -= 5" => Statement::parse => Statement::Assignment(AssignmentStatement { strategy: AssignmentStrategy::Subtract(_), .. })); 145 test_parse!(assignment_multiply: "x *= 5" => Statement::parse => Statement::Assignment(AssignmentStatement { strategy: AssignmentStrategy::Multiply(_), .. })); 146 test_parse!(assignment_divide: "x /= 5" => Statement::parse => Statement::Assignment(AssignmentStatement { strategy: AssignmentStrategy::Divide(_), .. })); 147 test_parse!(assignment_remainder: "x %= 5" => Statement::parse => Statement::Assignment(AssignmentStatement { strategy: AssignmentStrategy::Remainder(_), .. })); 148 test_parse!(assignment_power: "x **= 5" => Statement::parse => Statement::Assignment(AssignmentStatement { strategy: AssignmentStrategy::Power(_), .. })); 149 test_parse!(assignment_int_divide: "x //= 5" => Statement::parse => Statement::Assignment(AssignmentStatement { strategy: AssignmentStrategy::IntDivide(_), .. })); 150 test_parse!(assignment_bitwise_and: "x &= 5" => Statement::parse => Statement::Assignment(AssignmentStatement { strategy: AssignmentStrategy::BitwiseAnd(_), .. })); 151 test_parse!(assignment_bitwise_or: "x |= 5" => Statement::parse => Statement::Assignment(AssignmentStatement { strategy: AssignmentStrategy::BitwiseOr(_), .. })); 152 test_parse!(assignment_bitwise_xor: "x ^= 5" => Statement::parse => Statement::Assignment(AssignmentStatement { strategy: AssignmentStrategy::BitwiseXor(_), .. })); 153 test_parse!(assignment_left_shift: "x <~= 5" => Statement::parse => Statement::Assignment(AssignmentStatement { strategy: AssignmentStrategy::LeftShift(_), .. })); 154 test_parse!(assignment_right_shift: "x ~>= 5" => Statement::parse => Statement::Assignment(AssignmentStatement { strategy: AssignmentStrategy::RightShift(_), .. })); 155 test_parse!(assignment_left_shift_ex: "x <~~= 5" => Statement::parse => Statement::Assignment(AssignmentStatement { strategy: AssignmentStrategy::LeftShiftExtend(_), .. })); 156 test_parse!(assignment_right_shift_ex: "x ~~>= 5" => Statement::parse => Statement::Assignment(AssignmentStatement { strategy: AssignmentStrategy::RightShiftExtend(_), .. })); 157 test_parse!(assignment_left_shift_con: "x <<~= 5" => Statement::parse => Statement::Assignment(AssignmentStatement { strategy: AssignmentStrategy::LeftShiftContract(_), .. })); 158 test_parse!(assignment_right_shift_con: "x ~>>= 5" => Statement::parse => Statement::Assignment(AssignmentStatement { strategy: AssignmentStrategy::RightShiftContract(_), .. })); 159 test_parse!(assignment_glue: "x <>= 5" => Statement::parse => Statement::Assignment(AssignmentStatement { strategy: AssignmentStrategy::Glue(_), .. })); 160 test_parse!(assignment_compose: "x >>= 5" => Statement::parse => Statement::Assignment(AssignmentStatement { strategy: AssignmentStrategy::Compose(_), .. })); 161 test_parse!(assignment_rcompose: "x <<= 5" => Statement::parse => Statement::Assignment(AssignmentStatement { strategy: AssignmentStrategy::RCompose(_), .. })); 162 test_parse!(assignment_access: "x .= 5" => Statement::parse => Statement::Assignment(AssignmentStatement { strategy: AssignmentStrategy::Access(_), .. })); 163 test_parse!(assignment_cons: "x := 5" => Statement::parse => Statement::Assignment(AssignmentStatement { strategy: AssignmentStrategy::Cons(_), .. })); 164 165 test_parse_error!(assignment_not_fn: "a x = 7" => Statement::parse => "cannot assign to an expression that is not a valid assignment target"); 166 test_parse_error!(assignment_not_proc: "a!() = 7" => Statement::parse => "cannot assign to an expression that is not a valid assignment target"); 167 test_parse_error!(assignment_contains_not: "[a, a!()] = 7" => Statement::parse => "cannot assign to an expression that is not a valid assignment target"); 168 169 test_parse!(assignment_left_access: "a.b = 7" => Statement::parse => Statement::Assignment(AssignmentStatement { strategy: AssignmentStrategy::Direct(_), .. })); 170 test_parse!(assignment_proc_but_access: "a!().x = 7" => Statement::parse => Statement::Assignment(AssignmentStatement { strategy: AssignmentStrategy::Direct(_), .. })); 171 test_parse!(assignment_left_array: "[a, b, c] = [1, 2, 3]" => Statement::parse => Statement::Assignment(AssignmentStatement { strategy: AssignmentStrategy::Direct(_), .. })); 172 test_parse!(assignment_left_array_spread_start: "[..a, b, c] = []" => Statement::parse => Statement::Assignment(AssignmentStatement { strategy: AssignmentStrategy::Direct(_), .. })); 173 test_parse!(assignment_left_array_spread_middle: "[a, ..b, c] = []" => Statement::parse => Statement::Assignment(AssignmentStatement { strategy: AssignmentStrategy::Direct(_), .. })); 174 test_parse!(assignment_left_array_spread_end: "[a, b, ..c] = []" => Statement::parse => Statement::Assignment(AssignmentStatement { strategy: AssignmentStrategy::Direct(_), .. })); 175 test_parse_error!(assignment_left_array_spread_multi: "[..a, b, ..c] = []" => Statement::parse => "cannot assign to an expression that is not a valid assignment target"); 176 test_parse!(assignment_left_record: "{| \"a\" => a |} = {||}" => Statement::parse => Statement::Assignment(AssignmentStatement { strategy: AssignmentStrategy::Direct(_), .. })); 177 test_parse!(assignment_left_record_spread: "{| \"a\" => b, ..c |} = {||}" => Statement::parse => Statement::Assignment(AssignmentStatement { strategy: AssignmentStrategy::Direct(_), .. })); 178 test_parse_error!(assignment_left_record_spread_not_last: "{| ..c, \"a\" => b |} = {||}" => Statement::parse => "cannot assign to an expression that is not a valid assignment target"); 179 test_parse_error!(assignment_left_record_spread_multi: "{| ..a, ..c |} = {||}" => Statement::parse => "cannot assign to an expression that is not a valid assignment target"); 180 test_parse!(assignment_left_set: "[| a, b |] = [||]" => Statement::parse => Statement::Assignment(AssignmentStatement { strategy: AssignmentStrategy::Direct(_), .. })); 181 test_parse!(assignment_left_set_spread: "[| \"a\", ..c |] = [||]" => Statement::parse => Statement::Assignment(AssignmentStatement { strategy: AssignmentStrategy::Direct(_), .. })); 182 test_parse_error!(assignment_left_set_spread_not_last: "[| ..c, \"a\" |] = [||]" => Statement::parse => "cannot assign to an expression that is not a valid assignment target"); 183 test_parse_error!(assignment_left_set_spread_multi: "[| ..a, ..c |] = [||]" => Statement::parse => "cannot assign to an expression that is not a valid assignment target"); 184 test_parse!(assignment_left_glue: "\"hello \" <> world = 7" => Statement::parse => Statement::Assignment(AssignmentStatement { strategy: AssignmentStrategy::Direct(_), .. })); 185 test_parse!(assignment_left_neg: "-world = 7" => Statement::parse => Statement::Assignment(AssignmentStatement { strategy: AssignmentStrategy::Direct(_), .. })); 186 test_parse!(assignment_left_cons: "hello : world = 7" => Statement::parse => Statement::Assignment(AssignmentStatement { strategy: AssignmentStrategy::Direct(_), .. })); 187 test_parse!(assignment_left_struct: "'hello(x) = 7" => Statement::parse => Statement::Assignment(AssignmentStatement { strategy: AssignmentStrategy::Direct(_), .. })); 188 test_parse!(assignment_left_paren: "(x) = 7" => Statement::parse => Statement::Assignment(AssignmentStatement { strategy: AssignmentStrategy::Direct(_), .. })); 189 test_parse!(assignment_left_lit_false: "false = 7" => Statement::parse => Statement::Assignment(AssignmentStatement { strategy: AssignmentStrategy::Direct(_), .. })); 190 test_parse!(assignment_left_lit_true: "true = 7" => Statement::parse => Statement::Assignment(AssignmentStatement { strategy: AssignmentStrategy::Direct(_), .. })); 191 test_parse!(assignment_left_lit_unit: "unit = 7" => Statement::parse => Statement::Assignment(AssignmentStatement { strategy: AssignmentStrategy::Direct(_), .. })); 192 test_parse!(assignment_left_lit_atom: "'atom = 7" => Statement::parse => Statement::Assignment(AssignmentStatement { strategy: AssignmentStrategy::Direct(_), .. })); 193 test_parse!(assignment_left_lit_num: "7 = 7" => Statement::parse => Statement::Assignment(AssignmentStatement { strategy: AssignmentStrategy::Direct(_), .. })); 194 test_parse!(assignment_left_lit_char: "'7' = 7" => Statement::parse => Statement::Assignment(AssignmentStatement { strategy: AssignmentStrategy::Direct(_), .. })); 195 test_parse!(assignment_left_lit_str: "\"7\" = 7" => Statement::parse => Statement::Assignment(AssignmentStatement { strategy: AssignmentStrategy::Direct(_), .. })); 196 test_parse!(assignment_left_lit_bits: "0bb0101 = 7" => Statement::parse => Statement::Assignment(AssignmentStatement { strategy: AssignmentStrategy::Direct(_), .. })); 197 198 test_parse_error!(assignment_left_block: "{ call!() } = 7" => Statement::parse); 199 test_parse_error!(assignment_left_block_empty: "{} = 7" => Statement::parse); 200 test_parse_error!(assignment_left_record_no_paren: "{ x => y } = 7" => Statement::parse); 201}