conlang: Split assignment into plain Assign and assign-with-Modify
This commit is contained in:
parent
8d8928b8a8
commit
f330a7eaa5
@ -346,8 +346,10 @@ pub enum ExprKind {
|
|||||||
/// An empty expression: `(` `)`
|
/// An empty expression: `(` `)`
|
||||||
#[default]
|
#[default]
|
||||||
Empty,
|
Empty,
|
||||||
/// An [Assign]ment expression: [`Expr`] ([`AssignKind`] [`Expr`])\+
|
/// An [Assign]ment expression: [`Expr`] (`=` [`Expr`])\+
|
||||||
Assign(Assign),
|
Assign(Assign),
|
||||||
|
/// A [Modify]-assignment expression: [`Expr`] ([`ModifyKind`] [`Expr`])\+
|
||||||
|
Modify(Modify),
|
||||||
/// A [Binary] expression: [`Expr`] ([`BinaryKind`] [`Expr`])\+
|
/// A [Binary] expression: [`Expr`] ([`BinaryKind`] [`Expr`])\+
|
||||||
Binary(Binary),
|
Binary(Binary),
|
||||||
/// A [Unary] expression: [`UnaryKind`]\* [`Expr`]
|
/// A [Unary] expression: [`UnaryKind`]\* [`Expr`]
|
||||||
@ -394,14 +396,18 @@ pub enum ExprKind {
|
|||||||
/// An [Assign]ment expression: [`Expr`] ([`AssignKind`] [`Expr`])\+
|
/// An [Assign]ment expression: [`Expr`] ([`AssignKind`] [`Expr`])\+
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
pub struct Assign {
|
pub struct Assign {
|
||||||
pub kind: AssignKind,
|
pub parts: Box<(ExprKind, ExprKind)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A [Modify]-assignment expression: [`Expr`] ([`ModifyKind`] [`Expr`])\+
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub struct Modify {
|
||||||
|
pub kind: ModifyKind,
|
||||||
pub parts: Box<(ExprKind, ExprKind)>,
|
pub parts: Box<(ExprKind, ExprKind)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||||
pub enum AssignKind {
|
pub enum ModifyKind {
|
||||||
/// Standard Assignment with no read-back
|
|
||||||
Plain,
|
|
||||||
And,
|
And,
|
||||||
Or,
|
Or,
|
||||||
Xor,
|
Xor,
|
||||||
|
@ -420,6 +420,7 @@ mod display {
|
|||||||
match self {
|
match self {
|
||||||
ExprKind::Empty => "()".fmt(f),
|
ExprKind::Empty => "()".fmt(f),
|
||||||
ExprKind::Assign(v) => v.fmt(f),
|
ExprKind::Assign(v) => v.fmt(f),
|
||||||
|
ExprKind::Modify(v) => v.fmt(f),
|
||||||
ExprKind::Binary(v) => v.fmt(f),
|
ExprKind::Binary(v) => v.fmt(f),
|
||||||
ExprKind::Unary(v) => v.fmt(f),
|
ExprKind::Unary(v) => v.fmt(f),
|
||||||
ExprKind::Member(v) => v.fmt(f),
|
ExprKind::Member(v) => v.fmt(f),
|
||||||
@ -445,26 +446,32 @@ mod display {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Display for Assign {
|
impl Display for Assign {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
let Self { parts } = self;
|
||||||
|
write!(f, "{} = {}", parts.0, parts.1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for Modify {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
let Self { kind, parts } = self;
|
let Self { kind, parts } = self;
|
||||||
write!(f, "{} {kind} {}", parts.0, parts.1)
|
write!(f, "{} {kind} {}", parts.0, parts.1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for AssignKind {
|
impl Display for ModifyKind {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
AssignKind::Plain => "=",
|
ModifyKind::Mul => "*=",
|
||||||
AssignKind::Mul => "*=",
|
ModifyKind::Div => "/=",
|
||||||
AssignKind::Div => "/=",
|
ModifyKind::Rem => "%=",
|
||||||
AssignKind::Rem => "%=",
|
ModifyKind::Add => "+=",
|
||||||
AssignKind::Add => "+=",
|
ModifyKind::Sub => "-=",
|
||||||
AssignKind::Sub => "-=",
|
ModifyKind::And => "&=",
|
||||||
AssignKind::And => "&=",
|
ModifyKind::Or => "|=",
|
||||||
AssignKind::Or => "|=",
|
ModifyKind::Xor => "^=",
|
||||||
AssignKind::Xor => "^=",
|
ModifyKind::Shl => "<<=",
|
||||||
AssignKind::Shl => "<<=",
|
ModifyKind::Shr => ">>=",
|
||||||
AssignKind::Shr => ">>=",
|
|
||||||
}
|
}
|
||||||
.fmt(f)
|
.fmt(f)
|
||||||
}
|
}
|
||||||
@ -749,6 +756,7 @@ mod convert {
|
|||||||
}
|
}
|
||||||
impl From for ExprKind {
|
impl From for ExprKind {
|
||||||
Assign => ExprKind::Assign,
|
Assign => ExprKind::Assign,
|
||||||
|
Modify => ExprKind::Modify,
|
||||||
Binary => ExprKind::Binary,
|
Binary => ExprKind::Binary,
|
||||||
Unary => ExprKind::Unary,
|
Unary => ExprKind::Unary,
|
||||||
Member => ExprKind::Member,
|
Member => ExprKind::Member,
|
||||||
|
@ -234,14 +234,19 @@ pub trait Fold {
|
|||||||
or_fold_expr_kind(self, kind)
|
or_fold_expr_kind(self, kind)
|
||||||
}
|
}
|
||||||
fn fold_assign(&mut self, a: Assign) -> Assign {
|
fn fold_assign(&mut self, a: Assign) -> Assign {
|
||||||
let Assign { kind, parts } = a;
|
let Assign { parts } = a;
|
||||||
let (head, tail) = *parts;
|
let (head, tail) = *parts;
|
||||||
Assign {
|
Assign { parts: Box::new((self.fold_expr_kind(head), self.fold_expr_kind(tail))) }
|
||||||
kind: self.fold_assign_kind(kind),
|
}
|
||||||
|
fn fold_modify(&mut self, m: Modify) -> Modify {
|
||||||
|
let Modify { kind, parts } = m;
|
||||||
|
let (head, tail) = *parts;
|
||||||
|
Modify {
|
||||||
|
kind: self.fold_modify_kind(kind),
|
||||||
parts: Box::new((self.fold_expr_kind(head), self.fold_expr_kind(tail))),
|
parts: Box::new((self.fold_expr_kind(head), self.fold_expr_kind(tail))),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn fold_assign_kind(&mut self, kind: AssignKind) -> AssignKind {
|
fn fold_modify_kind(&mut self, kind: ModifyKind) -> ModifyKind {
|
||||||
kind
|
kind
|
||||||
}
|
}
|
||||||
fn fold_binary(&mut self, b: Binary) -> Binary {
|
fn fold_binary(&mut self, b: Binary) -> Binary {
|
||||||
@ -522,6 +527,7 @@ pub fn or_fold_expr_kind<F: Fold + ?Sized>(folder: &mut F, kind: ExprKind) -> Ex
|
|||||||
match kind {
|
match kind {
|
||||||
ExprKind::Empty => ExprKind::Empty,
|
ExprKind::Empty => ExprKind::Empty,
|
||||||
ExprKind::Assign(a) => ExprKind::Assign(folder.fold_assign(a)),
|
ExprKind::Assign(a) => ExprKind::Assign(folder.fold_assign(a)),
|
||||||
|
ExprKind::Modify(m) => ExprKind::Modify(folder.fold_modify(m)),
|
||||||
ExprKind::Binary(b) => ExprKind::Binary(folder.fold_binary(b)),
|
ExprKind::Binary(b) => ExprKind::Binary(folder.fold_binary(b)),
|
||||||
ExprKind::Unary(u) => ExprKind::Unary(folder.fold_unary(u)),
|
ExprKind::Unary(u) => ExprKind::Unary(folder.fold_unary(u)),
|
||||||
ExprKind::Member(m) => ExprKind::Member(folder.fold_member(m)),
|
ExprKind::Member(m) => ExprKind::Member(folder.fold_member(m)),
|
||||||
|
@ -202,13 +202,19 @@ pub trait Visit<'a>: Sized {
|
|||||||
or_visit_expr_kind(self, e)
|
or_visit_expr_kind(self, e)
|
||||||
}
|
}
|
||||||
fn visit_assign(&mut self, a: &'a Assign) {
|
fn visit_assign(&mut self, a: &'a Assign) {
|
||||||
let Assign { kind, parts } = a;
|
let Assign { parts } = a;
|
||||||
let (head, tail) = parts.as_ref();
|
let (head, tail) = parts.as_ref();
|
||||||
self.visit_assign_kind(kind);
|
|
||||||
self.visit_expr_kind(head);
|
self.visit_expr_kind(head);
|
||||||
self.visit_expr_kind(tail);
|
self.visit_expr_kind(tail);
|
||||||
}
|
}
|
||||||
fn visit_assign_kind(&mut self, _kind: &'a AssignKind) {}
|
fn visit_modify(&mut self, m: &'a Modify) {
|
||||||
|
let Modify { kind, parts } = m;
|
||||||
|
let (head, tail) = parts.as_ref();
|
||||||
|
self.visit_modify_kind(kind);
|
||||||
|
self.visit_expr_kind(head);
|
||||||
|
self.visit_expr_kind(tail);
|
||||||
|
}
|
||||||
|
fn visit_modify_kind(&mut self, _kind: &'a ModifyKind) {}
|
||||||
fn visit_binary(&mut self, b: &'a Binary) {
|
fn visit_binary(&mut self, b: &'a Binary) {
|
||||||
let Binary { kind, parts } = b;
|
let Binary { kind, parts } = b;
|
||||||
let (head, tail) = parts.as_ref();
|
let (head, tail) = parts.as_ref();
|
||||||
@ -437,6 +443,7 @@ pub fn or_visit_expr_kind<'a, V: Visit<'a>>(visitor: &mut V, e: &'a ExprKind) {
|
|||||||
match e {
|
match e {
|
||||||
ExprKind::Empty => {}
|
ExprKind::Empty => {}
|
||||||
ExprKind::Assign(a) => visitor.visit_assign(a),
|
ExprKind::Assign(a) => visitor.visit_assign(a),
|
||||||
|
ExprKind::Modify(m) => visitor.visit_modify(m),
|
||||||
ExprKind::Binary(b) => visitor.visit_binary(b),
|
ExprKind::Binary(b) => visitor.visit_binary(b),
|
||||||
ExprKind::Unary(u) => visitor.visit_unary(u),
|
ExprKind::Unary(u) => visitor.visit_unary(u),
|
||||||
ExprKind::Member(m) => visitor.visit_member(m),
|
ExprKind::Member(m) => visitor.visit_member(m),
|
||||||
|
@ -128,6 +128,7 @@ impl Interpret for ExprKind {
|
|||||||
match self {
|
match self {
|
||||||
ExprKind::Empty => Ok(ConValue::Empty),
|
ExprKind::Empty => Ok(ConValue::Empty),
|
||||||
ExprKind::Assign(v) => v.interpret(env),
|
ExprKind::Assign(v) => v.interpret(env),
|
||||||
|
ExprKind::Modify(v) => v.interpret(env),
|
||||||
ExprKind::Binary(v) => v.interpret(env),
|
ExprKind::Binary(v) => v.interpret(env),
|
||||||
ExprKind::Unary(v) => v.interpret(env),
|
ExprKind::Unary(v) => v.interpret(env),
|
||||||
ExprKind::Member(v) => v.interpret(env),
|
ExprKind::Member(v) => v.interpret(env),
|
||||||
@ -151,59 +152,71 @@ impl Interpret for ExprKind {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn evaluate_place_expr<'e>(
|
||||||
|
env: &'e mut Environment,
|
||||||
|
expr: &ExprKind,
|
||||||
|
) -> IResult<(&'e mut Option<ConValue>, Sym)> {
|
||||||
|
match expr {
|
||||||
|
ExprKind::Path(Path { parts, .. }) if parts.len() == 1 => {
|
||||||
|
match parts.last().expect("parts should not be empty") {
|
||||||
|
PathPart::SuperKw => Err(Error::NotAssignable),
|
||||||
|
PathPart::SelfKw => todo!("Assignment to `self`"),
|
||||||
|
PathPart::Ident(Identifier(s)) => env.get_mut(*s).map(|v| (v, *s)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ExprKind::Index(_) => todo!("Assignment to an index operation"),
|
||||||
|
ExprKind::Path(_) => todo!("Path expression resolution (IMPORTANT)"),
|
||||||
|
ExprKind::Empty | ExprKind::Group(_) | ExprKind::Tuple(_) => {
|
||||||
|
todo!("Pattern Destructuring?")
|
||||||
|
}
|
||||||
|
_ => Err(Error::NotAssignable),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Interpret for Assign {
|
impl Interpret for Assign {
|
||||||
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
|
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
|
||||||
let Assign { kind: op, parts } = self;
|
let Assign { parts } = self;
|
||||||
let (head, tail) = parts.borrow();
|
let (head, tail) = parts.borrow();
|
||||||
|
let init = tail.interpret(env)?;
|
||||||
// Resolve the head pattern
|
// Resolve the head pattern
|
||||||
let head = match &head {
|
let target = evaluate_place_expr(env, head)?;
|
||||||
ExprKind::Path(Path { parts, .. }) if parts.len() == 1 => {
|
use std::mem::discriminant as variant;
|
||||||
match parts.last().expect("parts should not be empty") {
|
// runtime typecheck
|
||||||
PathPart::SuperKw => Err(Error::NotAssignable)?,
|
match target.0 {
|
||||||
PathPart::SelfKw => todo!("Assignment to `self`"),
|
Some(value) if variant(value) == variant(&init) => {
|
||||||
PathPart::Ident(Identifier(s)) => s,
|
*value = init;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
ExprKind::Index(_) => todo!("Assignment to an index operation"),
|
value @ None => *value = Some(init),
|
||||||
ExprKind::Path(_) => todo!("Path expression resolution (IMPORTANT)"),
|
_ => Err(Error::TypeError)?,
|
||||||
ExprKind::Empty | ExprKind::Group(_) | ExprKind::Tuple(_) => {
|
}
|
||||||
todo!("Pattern Destructuring?")
|
Ok(ConValue::Empty)
|
||||||
}
|
}
|
||||||
_ => Err(Error::NotAssignable)?,
|
}
|
||||||
};
|
impl Interpret for Modify {
|
||||||
|
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
|
||||||
|
let Modify { kind: op, parts } = self;
|
||||||
|
let (head, tail) = parts.borrow();
|
||||||
// Get the initializer and the tail
|
// Get the initializer and the tail
|
||||||
let init = tail.interpret(env)?;
|
let init = tail.interpret(env)?;
|
||||||
let target = env.get_mut(*head)?;
|
// Resolve the head pattern
|
||||||
|
let target = evaluate_place_expr(env, head)?;
|
||||||
if let AssignKind::Plain = op {
|
let (Some(target), _) = target else {
|
||||||
use std::mem::discriminant as variant;
|
return Err(Error::NotInitialized(target.1));
|
||||||
// runtime typecheck
|
|
||||||
match target {
|
|
||||||
Some(value) if variant(value) == variant(&init) => {
|
|
||||||
*value = init;
|
|
||||||
}
|
|
||||||
value @ None => *value = Some(init),
|
|
||||||
_ => Err(Error::TypeError)?,
|
|
||||||
}
|
|
||||||
return Ok(ConValue::Empty);
|
|
||||||
}
|
|
||||||
let Some(target) = target else {
|
|
||||||
return Err(Error::NotInitialized(*head));
|
|
||||||
};
|
};
|
||||||
|
|
||||||
match op {
|
match op {
|
||||||
AssignKind::Add => target.add_assign(init)?,
|
ModifyKind::Add => target.add_assign(init),
|
||||||
AssignKind::Sub => target.sub_assign(init)?,
|
ModifyKind::Sub => target.sub_assign(init),
|
||||||
AssignKind::Mul => target.mul_assign(init)?,
|
ModifyKind::Mul => target.mul_assign(init),
|
||||||
AssignKind::Div => target.div_assign(init)?,
|
ModifyKind::Div => target.div_assign(init),
|
||||||
AssignKind::Rem => target.rem_assign(init)?,
|
ModifyKind::Rem => target.rem_assign(init),
|
||||||
AssignKind::And => target.bitand_assign(init)?,
|
ModifyKind::And => target.bitand_assign(init),
|
||||||
AssignKind::Or => target.bitor_assign(init)?,
|
ModifyKind::Or => target.bitor_assign(init),
|
||||||
AssignKind::Xor => target.bitxor_assign(init)?,
|
ModifyKind::Xor => target.bitxor_assign(init),
|
||||||
AssignKind::Shl => target.shl_assign(init)?,
|
ModifyKind::Shl => target.shl_assign(init),
|
||||||
AssignKind::Shr => target.shr_assign(init)?,
|
ModifyKind::Shr => target.shr_assign(init),
|
||||||
_ => (),
|
}?;
|
||||||
}
|
|
||||||
Ok(ConValue::Empty)
|
Ok(ConValue::Empty)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -911,7 +911,7 @@ impl<'t> Parser<'t> {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some((kind, prec)) = from_assign(op) {
|
if let Some((kind, prec)) = from_modify(op) {
|
||||||
let (before, after) = prec.infix().expect("should have a precedence");
|
let (before, after) = prec.infix().expect("should have a precedence");
|
||||||
if before < power {
|
if before < power {
|
||||||
break;
|
break;
|
||||||
@ -919,9 +919,21 @@ impl<'t> Parser<'t> {
|
|||||||
self.consume_peeked();
|
self.consume_peeked();
|
||||||
|
|
||||||
let tail = self.exprkind(after)?;
|
let tail = self.exprkind(after)?;
|
||||||
head = Assign { kind, parts: (head, tail).into() }.into();
|
head = Modify { kind, parts: (head, tail).into() }.into();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Punct::Eq = op {
|
||||||
|
let (before, after) = Precedence::Assign
|
||||||
|
.infix()
|
||||||
|
.expect("should have a precedence");
|
||||||
|
if before < power {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
self.consume_peeked();
|
||||||
|
let tail = self.exprkind(after)?;
|
||||||
|
head = Assign { parts: (head, tail).into() }.into();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
Ok(head)
|
Ok(head)
|
||||||
@ -942,7 +954,7 @@ impl<'t> Parser<'t> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
TokenKind::Literal => {
|
TokenKind::Literal => {
|
||||||
let name = self.literal()?; // TODO: Maybe restrict this to just
|
let name = self.literal()?; // TODO: Maybe restrict this to just
|
||||||
Ok(MemberKind::Tuple(name))
|
Ok(MemberKind::Tuple(name))
|
||||||
}
|
}
|
||||||
t => Err(self.error(Unexpected(t), PARSING)),
|
t => Err(self.error(Unexpected(t), PARSING)),
|
||||||
@ -1206,8 +1218,8 @@ impl Precedence {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl From<AssignKind> for Precedence {
|
impl From<ModifyKind> for Precedence {
|
||||||
fn from(_value: AssignKind) -> Self {
|
fn from(_value: ModifyKind) -> Self {
|
||||||
Precedence::Assign
|
Precedence::Assign
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1254,8 +1266,7 @@ operator! {
|
|||||||
At => At,
|
At => At,
|
||||||
Tilde => Tilde,
|
Tilde => Tilde,
|
||||||
};
|
};
|
||||||
from_assign(Punct => AssignKind) {
|
from_modify(Punct => ModifyKind) {
|
||||||
Eq => Plain,
|
|
||||||
AmpEq => And,
|
AmpEq => And,
|
||||||
BarEq => Or,
|
BarEq => Or,
|
||||||
XorEq => Xor,
|
XorEq => Xor,
|
||||||
|
@ -389,6 +389,7 @@ pub mod yamlify {
|
|||||||
fn yaml(&self, y: &mut Yamler) {
|
fn yaml(&self, y: &mut Yamler) {
|
||||||
match self {
|
match self {
|
||||||
ExprKind::Assign(k) => k.yaml(y),
|
ExprKind::Assign(k) => k.yaml(y),
|
||||||
|
ExprKind::Modify(k) => k.yaml(y),
|
||||||
ExprKind::Binary(k) => k.yaml(y),
|
ExprKind::Binary(k) => k.yaml(y),
|
||||||
ExprKind::Unary(k) => k.yaml(y),
|
ExprKind::Unary(k) => k.yaml(y),
|
||||||
ExprKind::Member(k) => k.yaml(y),
|
ExprKind::Member(k) => k.yaml(y),
|
||||||
@ -415,14 +416,22 @@ pub mod yamlify {
|
|||||||
}
|
}
|
||||||
impl Yamlify for Assign {
|
impl Yamlify for Assign {
|
||||||
fn yaml(&self, y: &mut Yamler) {
|
fn yaml(&self, y: &mut Yamler) {
|
||||||
let Self { kind, parts } = self;
|
let Self { parts } = self;
|
||||||
y.key("Assign")
|
y.key("Assign")
|
||||||
|
.pair("head", &parts.0)
|
||||||
|
.pair("tail", &parts.1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Yamlify for Modify {
|
||||||
|
fn yaml(&self, y: &mut Yamler) {
|
||||||
|
let Self { kind, parts } = self;
|
||||||
|
y.key("Modify")
|
||||||
.pair("kind", kind)
|
.pair("kind", kind)
|
||||||
.pair("head", &parts.0)
|
.pair("head", &parts.0)
|
||||||
.pair("tail", &parts.1);
|
.pair("tail", &parts.1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl Yamlify for AssignKind {
|
impl Yamlify for ModifyKind {
|
||||||
fn yaml(&self, y: &mut Yamler) {
|
fn yaml(&self, y: &mut Yamler) {
|
||||||
y.value(self);
|
y.value(self);
|
||||||
}
|
}
|
||||||
|
@ -82,7 +82,8 @@ Bool = "true" | "false" ;
|
|||||||
|
|
||||||
Expr = Assign ;
|
Expr = Assign ;
|
||||||
|
|
||||||
Assign = Path (AssignKind Assign ) | Compare ;
|
Assign = Path (AssignKind Assign ) | Modify ;
|
||||||
|
Modify = Path (ModifyKind Assign ) | Compare ;
|
||||||
|
|
||||||
(* Binary = Compare | Range | Logic | Bitwise | Shift | Factor | Term ; *)
|
(* Binary = Compare | Range | Logic | Bitwise | Shift | Factor | Term ; *)
|
||||||
Compare = Range (CompareOp Range )* ;
|
Compare = Range (CompareOp Range )* ;
|
||||||
@ -131,7 +132,8 @@ Break = "break" Expr ;
|
|||||||
Return = "return" Expr ;
|
Return = "return" Expr ;
|
||||||
Continue = "continue" ;
|
Continue = "continue" ;
|
||||||
|
|
||||||
AssignKind = '=' | '+=' | '-=' | '*=' | '/=' | '&=' | '|=' | '^=' |'<<=' |'>>=' ;
|
AssignKind = '=' ;
|
||||||
|
ModifyKind = '+=' | '-=' | '*=' | '/=' | '&=' | '|=' | '^=' |'<<=' |'>>=' ;
|
||||||
|
|
||||||
CompareOp = '<' | '<=' | '==' | '!=' | '>=' | '>' ;
|
CompareOp = '<' | '<=' | '==' | '!=' | '>=' | '>' ;
|
||||||
RangeOp = '..' | '..=' ;
|
RangeOp = '..' | '..=' ;
|
||||||
|
Loading…
Reference in New Issue
Block a user