Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add new LCGS parser with better parse errors #226

Merged
merged 18 commits into from
Oct 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions cgaal-cli/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "cgaal"
version = "2.0.0"
version = "2.0.1"
authors = [
"Asger Weirsøe <[email protected]>",
"Falke Carlsen <[email protected]>",
Expand All @@ -24,4 +24,4 @@ tracing-subscriber = "0.2.17"
serde_json = "1.0.83"
regex = { version = "1", features = ["unicode-case"] }
humantime = "2.1.0"
cgaal-engine = { path = "../cgaal-engine", version = "1.0.1" }
cgaal-engine = { path = "../cgaal-engine", version = "1.0.2" }
2 changes: 1 addition & 1 deletion cgaal-engine/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "cgaal-engine"
version = "1.0.1"
version = "1.0.2"
authors = [
"Asger Weirsøe <[email protected]>",
"Falke Carlsen <[email protected]>",
Expand Down
195 changes: 111 additions & 84 deletions cgaal-engine/src/atl/convert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,41 +3,69 @@ use crate::game_structure::lcgs::ast::DeclKind;
use crate::game_structure::lcgs::ir::intermediate::IntermediateLcgs;
use crate::game_structure::lcgs::ir::symbol_table::Owner;
use crate::game_structure::Player;
use crate::parsing::ast::{BinaryOpKind, Coalition, CoalitionKind, Expr, ExprKind, UnaryOpKind};
use crate::parsing::ast::{
BinaryOpKind, Coalition, CoalitionKind, Expr, ExprKind, Ident, UnaryOpKind,
};
use crate::parsing::errors::ErrorLog;

/// Convert an ATL expression to a Phi formula.
/// Players and labels must be defined in the game and are compiled to their respective indexes.
/// Returns None if there were errors. See the error log for details.
pub fn convert_expr_to_phi(
expr: &Expr,
game: &IntermediateLcgs,
errors: &mut ErrorLog,
) -> Option<Phi> {
pub fn convert_expr_to_phi(expr: &Expr, game: &IntermediateLcgs, errors: &ErrorLog) -> Option<Phi> {
let Expr { span, kind } = expr;
match kind {
ExprKind::True => Some(Phi::True),
ExprKind::False => Some(Phi::False),
ExprKind::Paren(e) => convert_expr_to_phi(e, game, errors),
ExprKind::Ident(ident) => {
let decl = game.get_decl(&Owner::Global.symbol_id(ident));
ExprKind::OwnedIdent(owner, ident) => {
if let Some(player) = owner {
let symbol = Owner::Global.symbol_id(&player.name);
match game.get_decl(&symbol).map(|d| &d.kind) {
Some(DeclKind::Player(_)) => {
// ok
}
Some(d) => {
errors.log(
player.span,
format!("Expected player, '{}' is a {}", player.name, d.kind_name()),
);
None?
}
None => {
errors.log(
player.span,
format!("Expected player, '{}' is not defined", player.name),
);
None?
}
}
}
let symbol = if let Some(owner) = owner {
Owner::Player(owner.name.clone()).symbol_id(&ident.name)
} else {
Owner::Global.symbol_id(&ident.name)
};
let decl = game.get_decl(&symbol);
match &decl.map(|d| &d.kind) {
Some(DeclKind::Label(l)) => Some(Phi::Proposition(l.index)),
Some(d) => {
errors.log(
*span,
ident.span,
format!(
"Expected proposition label, '{}' is a {}",
ident,
ident.name,
d.kind_name()
),
);
None
}
None => {
errors.log(
*span,
format!("Expected proposition label, '{}' is not defined", ident),
ident.span,
format!(
"Expected proposition label, '{}' is not defined",
ident.name
),
);
None
}
Expand All @@ -52,6 +80,13 @@ pub fn convert_expr_to_phi(
);
None
}
UnaryOpKind::Neg => {
errors.log(
*span,
"Arithmetic operators is currently not supported in ATL".to_string(),
);
None
}
},
ExprKind::Binary(op, lhs, rhs) => match op {
BinaryOpKind::And => Some(Phi::And(
Expand All @@ -62,71 +97,54 @@ pub fn convert_expr_to_phi(
convert_expr_to_phi(lhs, game, errors)?.into(),
convert_expr_to_phi(rhs, game, errors)?.into(),
)),
BinaryOpKind::Dot => {
let ExprKind::Ident(owner) = &lhs.kind else {
errors.log(lhs.span, "Expected player name".to_string());
return None;
};
let ExprKind::Ident(prop) = &rhs.kind else {
errors.log(rhs.span, "Expected proposition label".to_string());
return None;
};
match game
.get_decl(&Owner::Global.symbol_id(owner))
.map(|d| &d.kind)
{
Some(DeclKind::Player(_)) => {
let symb = Owner::Player(owner.clone()).symbol_id(prop);
let decl = game.get_decl(&symb);
match decl.map(|d| &d.kind) {
Some(DeclKind::Label(l)) => Some(Phi::Proposition(l.index)),
Some(d) => {
errors.log(
rhs.span,
format!(
"Expected proposition label, '{}' is a {}",
prop,
d.kind_name(),
),
);
None
}
None => {
errors.log(
rhs.span,
format!(
"Expected proposition label, '{}' is not defined",
symb,
),
);
None
}
}
}
Some(d) => {
errors.log(
lhs.span,
format!("Expected player, '{}' is a {}", owner, d.kind_name()),
);
None
}
None => {
errors.log(
lhs.span,
format!("Expected player, '{}' is not defined", owner),
);
None
}
}
}
BinaryOpKind::Until => {
errors.log(
*span,
"Temporal operators are only allowed after a coalition".to_string(),
);
None
}
BinaryOpKind::Xor => {
errors.log(
*span,
"Exclusive OR is currently not supported in ATL".to_string(),
);
None
}
BinaryOpKind::Implies => {
errors.log(
*span,
"Implication is currently not supported in ATL".to_string(),
);
None
}
BinaryOpKind::Eq
| BinaryOpKind::Neq
| BinaryOpKind::Gt
| BinaryOpKind::Geq
| BinaryOpKind::Lt
| BinaryOpKind::Leq => {
errors.log(
*span,
"Relational operators are currently not supported in ATL".to_string(),
);
None
}
BinaryOpKind::Add | BinaryOpKind::Sub | BinaryOpKind::Mul | BinaryOpKind::Div => {
errors.log(
*span,
"Arithmetic operators are currently not supported in ATL".to_string(),
);
None
}
},
ExprKind::TernaryIf(_, _, _) => {
errors.log(
*span,
"Ternary if expressions are currently not supported in ATL".to_string(),
);
None
}
ExprKind::Coalition(Coalition {
players,
kind,
Expand Down Expand Up @@ -201,43 +219,52 @@ pub fn convert_expr_to_phi(
None
}
},
ExprKind::Num(_) => {
errors.log(
*span,
"Unexpected number. Please use true, false, or label names as propositions."
.to_string(),
);
None
}
ExprKind::Max(_) | ExprKind::Min(_) => {
errors.log(
*span,
"Max and min expressions are currently not supported in ATL".to_string(),
);
None
}
ExprKind::Error => None,
}
}

/// Helper function for converting a list of player names to a list of player indexes.
/// Returns None if there were errors. See the error log for details.
fn convert_players(
players: &[Expr],
players: &[Ident],
game: &IntermediateLcgs,
errors: &mut ErrorLog,
errors: &ErrorLog,
) -> Option<Vec<Player>> {
players
.iter()
.map(|expr| match &expr.kind {
ExprKind::Ident(name) => match game
.get_decl(&Owner::Global.symbol_id(name))
.map(|d| &d.kind)
{
.map(|ident| {
let symbol = Owner::Global.symbol_id(&ident.name);
match game.get_decl(&symbol).map(|d| &d.kind) {
Some(DeclKind::Player(p)) => Some(p.index),
Some(d) => {
errors.log(
expr.span,
format!("Expected player, '{}' is a {}", name, d.kind_name()),
ident.span,
format!("Expected player, '{}' is a {}", ident.name, d.kind_name()),
);
None
}
None => {
errors.log(
expr.span,
format!("Expected player, '{}' is not defined", name),
ident.span,
format!("Expected player, '{}' is not defined", ident.name),
);
None
}
},
_ => {
errors.log(expr.span, "Expected player name".to_string());
None
}
})
.collect()
Expand Down
Loading