Merge pull request #44 from mist-go/statement-patches-and-errors
Statement patches and errors
This commit is contained in:
+9
-3
@@ -102,7 +102,10 @@ impl GenRust for Expression {
|
|||||||
|
|
||||||
if ensure_semicolon {
|
if ensure_semicolon {
|
||||||
ctx.expr_ensure_semicolon = true;
|
ctx.expr_ensure_semicolon = true;
|
||||||
cg.add(";");
|
|
||||||
|
if !self.is_block() {
|
||||||
|
cg.add(";");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -166,9 +169,12 @@ impl GenRust for Postfix {
|
|||||||
Postfix::Call(args) => {
|
Postfix::Call(args) => {
|
||||||
cg.add("(");
|
cg.add("(");
|
||||||
|
|
||||||
for arg in args {
|
for (i, arg) in args.iter().enumerate() {
|
||||||
|
if i > 0 {
|
||||||
|
cg.add(", ");
|
||||||
|
}
|
||||||
|
|
||||||
arg.gen_rust(ctx, cg);
|
arg.gen_rust(ctx, cg);
|
||||||
cg.add(", ");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cg.add(")");
|
cg.add(")");
|
||||||
|
|||||||
@@ -81,6 +81,19 @@ impl RustCodegen {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn ensure_brackets_expr(&mut self, ctx: &mut Context, expr: &Expression) {
|
||||||
|
match expr {
|
||||||
|
Expression::Statement(stmt) => self.ensure_brackets(ctx, stmt),
|
||||||
|
_ => {
|
||||||
|
self.add("{");
|
||||||
|
self.indent += 1;
|
||||||
|
expr.gen_rust(ctx, self);
|
||||||
|
self.indent -= 1;
|
||||||
|
self.add("}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GenRust for Attribute {
|
impl GenRust for Attribute {
|
||||||
|
|||||||
+37
-19
@@ -18,10 +18,11 @@ impl GenRust for Block {
|
|||||||
if let Some(soft_return) = &self.1 {
|
if let Some(soft_return) = &self.1 {
|
||||||
ctx.expr_ensure_semicolon = false;
|
ctx.expr_ensure_semicolon = false;
|
||||||
soft_return.gen_rust(ctx, cg);
|
soft_return.gen_rust(ctx, cg);
|
||||||
|
cg.addln("");
|
||||||
}
|
}
|
||||||
|
|
||||||
cg.indent -= 1;
|
cg.indent -= 1;
|
||||||
cg.add_indentedln("}");
|
cg.add_indented("}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -57,17 +58,14 @@ impl GenRust for Statement {
|
|||||||
p.gen_rust(ctx, cg);
|
p.gen_rust(ctx, cg);
|
||||||
}
|
}
|
||||||
|
|
||||||
cg.add(" => {");
|
cg.add(" => ");
|
||||||
cg.indent += 1;
|
|
||||||
|
|
||||||
body.gen_rust(ctx, cg);
|
cg.ensure_brackets_expr(ctx, body);
|
||||||
|
|
||||||
cg.indent -= 1;
|
|
||||||
cg.add_indentedln("}");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cg.indent -= 1;
|
cg.indent -= 1;
|
||||||
cg.add_indentedln("}");
|
cg.addln("");
|
||||||
|
cg.add_indented("}");
|
||||||
}
|
}
|
||||||
|
|
||||||
Statement::If {
|
Statement::If {
|
||||||
@@ -77,24 +75,32 @@ impl GenRust for Statement {
|
|||||||
} => {
|
} => {
|
||||||
cg.add("if ");
|
cg.add("if ");
|
||||||
initial.condition.gen_rust(ctx, cg);
|
initial.condition.gen_rust(ctx, cg);
|
||||||
cg.ensure_brackets(ctx, &initial.body);
|
cg.add(" ");
|
||||||
|
cg.ensure_brackets_expr(ctx, &initial.body);
|
||||||
|
|
||||||
for else_if_branch in else_if {
|
for else_if_branch in else_if {
|
||||||
cg.add("else if");
|
cg.add("else if");
|
||||||
else_if_branch.condition.gen_rust(ctx, cg);
|
else_if_branch.condition.gen_rust(ctx, cg);
|
||||||
cg.ensure_brackets(ctx, &else_if_branch.body);
|
cg.add(" ");
|
||||||
|
cg.ensure_brackets_expr(ctx, &else_if_branch.body);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(else_br) = else_branch {
|
if let Some(else_br) = else_branch {
|
||||||
cg.add("else");
|
cg.add(" else ");
|
||||||
cg.ensure_brackets(ctx, else_br);
|
cg.ensure_brackets_expr(ctx, else_br);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Statement::While(StatementBranch { condition, body }) => {
|
Statement::While(StatementBranch { condition, body }) => {
|
||||||
cg.add("while ");
|
cg.add("while ");
|
||||||
condition.gen_rust(ctx, cg);
|
condition.gen_rust(ctx, cg);
|
||||||
cg.ensure_brackets(ctx, body);
|
cg.add(" ");
|
||||||
|
cg.ensure_brackets_expr(ctx, body);
|
||||||
|
}
|
||||||
|
|
||||||
|
Statement::Loop(body) => {
|
||||||
|
cg.add("loop ");
|
||||||
|
cg.ensure_brackets_expr(ctx, body);
|
||||||
}
|
}
|
||||||
|
|
||||||
Statement::CStyleFor {
|
Statement::CStyleFor {
|
||||||
@@ -103,28 +109,40 @@ impl GenRust for Statement {
|
|||||||
update,
|
update,
|
||||||
body,
|
body,
|
||||||
} => {
|
} => {
|
||||||
cg.add_indentedln("{");
|
cg.addln("{");
|
||||||
cg.indent += 1;
|
cg.indent += 1;
|
||||||
|
|
||||||
|
ctx.expr_ensure_semicolon = true;
|
||||||
|
|
||||||
|
cg.add_indented("");
|
||||||
|
|
||||||
init.gen_rust(ctx, cg);
|
init.gen_rust(ctx, cg);
|
||||||
|
|
||||||
cg.add("while ");
|
cg.addln("");
|
||||||
|
|
||||||
|
cg.add_indented("while ");
|
||||||
|
|
||||||
|
ctx.expr_ensure_semicolon = false;
|
||||||
condition.gen_rust(ctx, cg);
|
condition.gen_rust(ctx, cg);
|
||||||
|
|
||||||
cg.add("{");
|
cg.add(" ");
|
||||||
|
|
||||||
|
cg.add("{");
|
||||||
cg.indent += 1;
|
cg.indent += 1;
|
||||||
|
|
||||||
cg.ensure_brackets(ctx, body);
|
ctx.expr_ensure_semicolon = true;
|
||||||
|
|
||||||
|
body.gen_rust(ctx, cg);
|
||||||
|
|
||||||
update.gen_rust(ctx, cg);
|
update.gen_rust(ctx, cg);
|
||||||
|
|
||||||
|
cg.addln("");
|
||||||
|
|
||||||
cg.indent -= 1;
|
cg.indent -= 1;
|
||||||
cg.add_indentedln("}");
|
cg.add_indentedln("}");
|
||||||
|
|
||||||
cg.indent -= 1;
|
cg.indent -= 1;
|
||||||
cg.add_indentedln("}");
|
cg.add_indented("}");
|
||||||
}
|
}
|
||||||
|
|
||||||
Statement::For {
|
Statement::For {
|
||||||
@@ -138,7 +156,7 @@ impl GenRust for Statement {
|
|||||||
pattern.gen_rust(ctx, cg);
|
pattern.gen_rust(ctx, cg);
|
||||||
cg.add(" in ");
|
cg.add(" in ");
|
||||||
iterator.gen_rust(ctx, cg);
|
iterator.gen_rust(ctx, cg);
|
||||||
cg.ensure_brackets(ctx, body);
|
cg.ensure_brackets_expr(ctx, body);
|
||||||
}
|
}
|
||||||
|
|
||||||
Statement::Return(expr) => {
|
Statement::Return(expr) => {
|
||||||
|
|||||||
@@ -92,3 +92,32 @@ pub class Application {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
i32 test_stmt() {
|
||||||
|
if (0 == 0) {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void loops_test() {
|
||||||
|
for (x : 0..10) {
|
||||||
|
println!("{x}");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var mut i = 0; i < 10; i++) {
|
||||||
|
println!("{i}");
|
||||||
|
}
|
||||||
|
|
||||||
|
var i = 0;
|
||||||
|
|
||||||
|
while (i == 1) {
|
||||||
|
println!("hi");
|
||||||
|
}
|
||||||
|
|
||||||
|
loop {
|
||||||
|
println!("loop!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ pub enum LogLevel {
|
|||||||
|
|
||||||
impl fmt::Display for LogLevel {
|
impl fmt::Display for LogLevel {
|
||||||
fmt::Result fmt(self*, Formatter<'_> mut* f) {
|
fmt::Result fmt(self*, Formatter<'_> mut* f) {
|
||||||
return match (self) {
|
match (self) {
|
||||||
LogLevel::Info => write!(f, "[INFO]");
|
LogLevel::Info => write!(f, "[INFO]");
|
||||||
|
|
||||||
LogLevel::Warning => write!(f, "[WARN]");
|
LogLevel::Warning => write!(f, "[WARN]");
|
||||||
@@ -66,7 +66,7 @@ pub class Logger {
|
|||||||
|
|
||||||
impl fmt::Display {
|
impl fmt::Display {
|
||||||
fmt::Result fmt(self*, Formatter<'_> mut* f) {
|
fmt::Result fmt(self*, Formatter<'_> mut* f) {
|
||||||
return write!(f, "logger ({})", self.prefix);
|
write!(f, "logger ({})", self.prefix)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -81,3 +81,13 @@ pub enum Generic {
|
|||||||
Lifetime(Identifier),
|
Lifetime(Identifier),
|
||||||
Type(TypeExpr),
|
Type(TypeExpr),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Expression {
|
||||||
|
pub fn is_block(&self) -> bool {
|
||||||
|
if let Expression::Statement(stmt) = self {
|
||||||
|
stmt.is_block()
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -11,27 +11,28 @@ pub struct Block(
|
|||||||
#[derive(Debug, Clone, Serialize)]
|
#[derive(Debug, Clone, Serialize)]
|
||||||
pub enum Statement {
|
pub enum Statement {
|
||||||
Block(Block),
|
Block(Block),
|
||||||
VarDecl(VarDeclStmt),
|
|
||||||
If {
|
If {
|
||||||
initial: StatementBranch,
|
initial: StatementBranch,
|
||||||
else_if: Vec<StatementBranch>,
|
else_if: Vec<StatementBranch>,
|
||||||
else_branch: Option<Box<Statement>>,
|
else_branch: Option<Box<Expression>>,
|
||||||
},
|
},
|
||||||
|
Loop(Expression),
|
||||||
While(StatementBranch),
|
While(StatementBranch),
|
||||||
CStyleFor {
|
CStyleFor {
|
||||||
init: Box<Statement>,
|
init: Expression,
|
||||||
condition: Expression,
|
condition: Expression,
|
||||||
update: Box<Statement>,
|
update: Expression,
|
||||||
body: Box<Statement>,
|
body: Expression,
|
||||||
},
|
},
|
||||||
For {
|
For {
|
||||||
mutable: bool,
|
mutable: bool,
|
||||||
pattern: Pattern,
|
pattern: Pattern,
|
||||||
iterator: Expression,
|
iterator: Expression,
|
||||||
body: Box<Statement>,
|
body: Box<Expression>,
|
||||||
},
|
},
|
||||||
Match(Expression, Vec<(Vec<Pattern>, Expression)>),
|
Match(Expression, Vec<(Vec<Pattern>, Expression)>),
|
||||||
|
|
||||||
|
VarDecl(VarDeclStmt),
|
||||||
Return(Option<Expression>),
|
Return(Option<Expression>),
|
||||||
Break,
|
Break,
|
||||||
Continue,
|
Continue,
|
||||||
@@ -53,5 +54,29 @@ pub struct VarDeclStmt {
|
|||||||
#[derive(Debug, Clone, Serialize)]
|
#[derive(Debug, Clone, Serialize)]
|
||||||
pub struct StatementBranch {
|
pub struct StatementBranch {
|
||||||
pub condition: Expression,
|
pub condition: Expression,
|
||||||
pub body: Box<Statement>,
|
pub body: Box<Expression>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Statement {
|
||||||
|
pub fn is_block(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
Self::Block(_) => true,
|
||||||
|
Self::If {
|
||||||
|
initial,
|
||||||
|
else_if,
|
||||||
|
else_branch,
|
||||||
|
} => {
|
||||||
|
else_branch
|
||||||
|
.as_ref()
|
||||||
|
.map(|v| v.is_block())
|
||||||
|
.unwrap_or_default()
|
||||||
|
|| else_if
|
||||||
|
.last()
|
||||||
|
.map(|b| b.body.is_block())
|
||||||
|
.unwrap_or_default()
|
||||||
|
|| initial.body.is_block()
|
||||||
|
}
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ keyword = {
|
|||||||
| "true"
|
| "true"
|
||||||
| "false"
|
| "false"
|
||||||
| "dyn"
|
| "dyn"
|
||||||
|
| "loop"
|
||||||
}
|
}
|
||||||
|
|
||||||
identifier = @{
|
identifier = @{
|
||||||
@@ -379,6 +380,7 @@ control_flow = {
|
|||||||
| c_for_stmt
|
| c_for_stmt
|
||||||
| for_stmt
|
| for_stmt
|
||||||
| match_stmt
|
| match_stmt
|
||||||
|
| loop_stmt
|
||||||
| block
|
| block
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -405,11 +407,15 @@ while_stmt = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
c_for_stmt = {
|
c_for_stmt = {
|
||||||
"for" ~ "(" ~ statement ~ expr ~ semicolon ~ statement ~ ")" ~ statement
|
"for" ~ "(" ~ statement ~ statement ~ expr ~ ")" ~ statement
|
||||||
}
|
}
|
||||||
|
|
||||||
for_stmt = {
|
for_stmt = {
|
||||||
"for" ~ "(" ~ mutable? ~ pattern ~ "in" ~ expr ~ ")" ~ statement
|
"for" ~ "(" ~ mutable? ~ pattern ~ ":" ~ expr ~ ")" ~ statement
|
||||||
|
}
|
||||||
|
|
||||||
|
loop_stmt = {
|
||||||
|
"loop" ~ statement
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------
|
// ------------------------------------------------------
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Statement {
|
|||||||
else_if: collect_recovered(inner.next().unwrap().into_inner()),
|
else_if: collect_recovered(inner.next().unwrap().into_inner()),
|
||||||
else_branch: inner
|
else_branch: inner
|
||||||
.next()
|
.next()
|
||||||
.map(Statement::try_from)
|
.map(Expression::try_from)
|
||||||
.transpose()
|
.transpose()
|
||||||
.map(|v| v.map(Box::new))
|
.map(|v| v.map(Box::new))
|
||||||
.get_map(|v| { Some(Box::new(v)) }),
|
.get_map(|v| { Some(Box::new(v)) }),
|
||||||
@@ -74,11 +74,13 @@ impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Statement {
|
|||||||
|
|
||||||
Rule::while_stmt => ast_expr!(Statement::While(inner.next().unwrap().try_into())),
|
Rule::while_stmt => ast_expr!(Statement::While(inner.next().unwrap().try_into())),
|
||||||
|
|
||||||
|
Rule::loop_stmt => ast_expr!(Statement::Loop(inner.next().unwrap().try_into())),
|
||||||
|
|
||||||
Rule::c_for_stmt => ast_expr!(Statement::CStyleFor {
|
Rule::c_for_stmt => ast_expr!(Statement::CStyleFor {
|
||||||
init: inner.next().unwrap().try_into().map(Box::new),
|
init: inner.next().unwrap().try_into(),
|
||||||
condition: inner.next().unwrap().try_into(),
|
condition: inner.next().unwrap().try_into(),
|
||||||
update: inner.next().unwrap().try_into().map(Box::new),
|
update: inner.next().unwrap().try_into(),
|
||||||
body: inner.next().unwrap().try_into().map(Box::new),
|
body: inner.next().unwrap().try_into(),
|
||||||
}),
|
}),
|
||||||
|
|
||||||
Rule::for_stmt => ast_expr!(Statement::For {
|
Rule::for_stmt => ast_expr!(Statement::For {
|
||||||
|
|||||||
+7
-3
@@ -1,7 +1,7 @@
|
|||||||
use std::{
|
use std::{
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
env, fs,
|
env, fs,
|
||||||
path::PathBuf,
|
path::{MAIN_SEPARATOR, PathBuf},
|
||||||
process::{Command, Stdio},
|
process::{Command, Stdio},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -44,6 +44,8 @@ pub fn build(mut args: Vec<String>, root: PathBuf) -> bool {
|
|||||||
|
|
||||||
let mut mapping = HashMap::new();
|
let mut mapping = HashMap::new();
|
||||||
|
|
||||||
|
let mist_src = format!(".mist{MAIN_SEPARATOR}src");
|
||||||
|
|
||||||
for message in cargo_metadata::Message::parse_stream(&mut reader) {
|
for message in cargo_metadata::Message::parse_stream(&mut reader) {
|
||||||
match message {
|
match message {
|
||||||
Ok(Message::CompilerMessage(msg)) => {
|
Ok(Message::CompilerMessage(msg)) => {
|
||||||
@@ -53,8 +55,10 @@ pub fn build(mut args: Vec<String>, root: PathBuf) -> bool {
|
|||||||
|
|
||||||
let mist_file = span
|
let mist_file = span
|
||||||
.file_name
|
.file_name
|
||||||
.replacen(".mist/src", "src", 1)
|
.replacen(&mist_src, "src", 1)
|
||||||
.replace(".rs", ".mist");
|
.trim_end_matches(".rs")
|
||||||
|
.to_string()
|
||||||
|
+ ".mist";
|
||||||
|
|
||||||
let mist_path = root.join(&mist_file);
|
let mist_path = root.join(&mist_file);
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -15,7 +15,7 @@ void main() {
|
|||||||
|
|
||||||
match (args[1].as_str()) {
|
match (args[1].as_str()) {
|
||||||
"run" | "build" | "check" | "r" | "b" | "c" => {
|
"run" | "build" | "check" | "r" | "b" | "c" => {
|
||||||
var root = transpiler::build();
|
var root = transpiler::build(false);
|
||||||
|
|
||||||
println!("");
|
println!("");
|
||||||
|
|
||||||
@@ -26,7 +26,7 @@ void main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
"transpile" | "t" => {
|
"transpile" | "t" => {
|
||||||
transpiler::build();
|
transpiler::build(args.get(2).is_some());
|
||||||
}
|
}
|
||||||
"init" => {
|
"init" => {
|
||||||
init_project(args);
|
init_project(args);
|
||||||
|
|||||||
+6
-6
@@ -7,7 +7,7 @@ use std::{
|
|||||||
|
|
||||||
use mist_parser::error::ParseError;
|
use mist_parser::error::ParseError;
|
||||||
|
|
||||||
pub fn build() -> PathBuf {
|
pub fn build(force: bool) -> PathBuf {
|
||||||
let start = Instant::now();
|
let start = Instant::now();
|
||||||
|
|
||||||
let root = std::env::current_dir()
|
let root = std::env::current_dir()
|
||||||
@@ -17,7 +17,7 @@ pub fn build() -> PathBuf {
|
|||||||
let src_dir = root.join("src");
|
let src_dir = root.join("src");
|
||||||
let out_dir = root.join(".mist/src");
|
let out_dir = root.join(".mist/src");
|
||||||
|
|
||||||
build_dir(&root, &src_dir, &src_dir, &out_dir);
|
build_dir(&root, &src_dir, &src_dir, &out_dir, force);
|
||||||
|
|
||||||
let elapsed = start.elapsed();
|
let elapsed = start.elapsed();
|
||||||
|
|
||||||
@@ -29,7 +29,7 @@ pub fn build() -> PathBuf {
|
|||||||
root
|
root
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_dir(root: &Path, base_src: &Path, current_dir: &Path, out_dir: &Path) {
|
fn build_dir(root: &Path, base_src: &Path, current_dir: &Path, out_dir: &Path, force: bool) {
|
||||||
let entries = match fs::read_dir(current_dir) {
|
let entries = match fs::read_dir(current_dir) {
|
||||||
Ok(entries) => entries,
|
Ok(entries) => entries,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
@@ -57,7 +57,7 @@ fn build_dir(root: &Path, base_src: &Path, current_dir: &Path, out_dir: &Path) {
|
|||||||
|
|
||||||
// recurse into nested directories
|
// recurse into nested directories
|
||||||
if path.is_dir() {
|
if path.is_dir() {
|
||||||
build_dir(root, base_src, &path, out_dir);
|
build_dir(root, base_src, &path, out_dir, force);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -72,7 +72,7 @@ fn build_dir(root: &Path, base_src: &Path, current_dir: &Path, out_dir: &Path) {
|
|||||||
let _ = fs::create_dir_all(parent);
|
let _ = fs::create_dir_all(parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
if should_skip(&path, &dest_path) {
|
if !force && should_skip(&path, &dest_path) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -83,7 +83,7 @@ fn build_dir(root: &Path, base_src: &Path, current_dir: &Path, out_dir: &Path) {
|
|||||||
let output_path = out_dir.join(relative).with_extension("rs");
|
let output_path = out_dir.join(relative).with_extension("rs");
|
||||||
|
|
||||||
// Cache layer: Skip if the generated .rs file is newer than the .mist source
|
// Cache layer: Skip if the generated .rs file is newer than the .mist source
|
||||||
if should_skip(&path, &output_path) {
|
if !force && should_skip(&path, &output_path) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user