diff --git a/rust/common/token.rs b/rust/common/token.rs index 1f2d83b24..5f14d9d8d 100644 --- a/rust/common/token.rs +++ b/rust/common/token.rs @@ -173,7 +173,7 @@ string_enum! { ValueType Decimal = "decimal", Double = "double", Duration = "duration", - Long = "long", + Integer = "integer", String = "string", } diff --git a/rust/parser/statement/mod.rs b/rust/parser/statement/mod.rs index c66772338..511b17485 100644 --- a/rust/parser/statement/mod.rs +++ b/rust/parser/statement/mod.rs @@ -4,15 +4,13 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ -use self::{ - single::visit_statement_single, - thing::{visit_statement_relation_anonymous, visit_statement_thing_var}, -}; +use self::single::visit_statement_single; use super::{ expression::visit_expression_value, statement::type_::visit_statement_type, IntoChildNodes, Node, Rule, RuleMatcher, }; use crate::{ common::{error::TypeQLError, token::Comparator, Spanned}, + parser::statement::thing::visit_statement_thing, statement::{comparison::Comparison, Statement}, }; @@ -26,8 +24,7 @@ pub(super) fn visit_statement(node: Node<'_>) -> Statement { match child.as_rule() { Rule::statement_single => visit_statement_single(child), Rule::statement_type => visit_statement_type(child), - Rule::statement_thing_var => visit_statement_thing_var(child), - Rule::statement_relation_anonymous => visit_statement_relation_anonymous(child), + Rule::statement_thing => visit_statement_thing(child), _ => unreachable!("{}", TypeQLError::IllegalGrammar { input: child.to_string() }), } } diff --git a/rust/parser/statement/single.rs b/rust/parser/statement/single.rs index e741cccf9..c3a4b9906 100644 --- a/rust/parser/statement/single.rs +++ b/rust/parser/statement/single.rs @@ -36,6 +36,7 @@ pub fn visit_statement_assignment(node: Node<'_>) -> Assignment { debug_assert_eq!(node.as_rule(), Rule::statement_assignment); let span = node.span(); let mut children = node.into_children(); + children.skip_expected(Rule::LET); let lhs = visit_assignment_left(children.consume_expected(Rule::assignment_left)); children.skip_expected(Rule::ASSIGN); let rhs = visit_expression(children.consume_expected(Rule::expression)); @@ -108,6 +109,7 @@ pub fn visit_statement_in(node: Node<'_>) -> InIterable { debug_assert_eq!(node.as_rule(), Rule::statement_in); let span = node.span(); let mut children = node.into_children(); + children.skip_expected(Rule::LET); let lhs = visit_vars_assignment(children.consume_expected(Rule::vars_assignment)); children.skip_expected(Rule::IN); let child = children.consume_any(); diff --git a/rust/parser/statement/thing.rs b/rust/parser/statement/thing.rs index e754303e8..76a99ba30 100644 --- a/rust/parser/statement/thing.rs +++ b/rust/parser/statement/thing.rs @@ -8,7 +8,7 @@ use crate::{ common::{error::TypeQLError, Spanned}, expression::Expression, parser::{ - expression::{visit_expression_list, visit_expression_struct, visit_expression_value}, + expression::{visit_expression, visit_expression_list, visit_expression_struct, visit_expression_value}, literal::visit_value_literal, statement::visit_comparison, type_::{visit_type_ref, visit_type_ref_list}, @@ -16,63 +16,54 @@ use crate::{ }, statement::{ thing::{ - isa::{Isa, IsaKind}, - AttributeComparisonStatement, AttributeValueStatement, Constraint, Has, HasValue, Head, Iid, Links, - Relation, RolePlayer, Thing, + isa::{Isa, IsaInstanceConstraint, IsaKind}, + Constraint, Has, HasValue, Head, Iid, Links, Relation, RolePlayer, Thing, }, Statement, }, type_::TypeRefAny, + TypeRef, }; pub(in crate::parser) fn visit_statement_thing(node: Node<'_>) -> Statement { debug_assert_eq!(node.as_rule(), Rule::statement_thing); - let child = node.into_child(); - match child.as_rule() { - Rule::statement_thing_var => visit_statement_thing_var(child), - Rule::statement_relation_anonymous => visit_statement_relation_anonymous(child), - _ => unreachable!("{}", TypeQLError::IllegalGrammar { input: child.to_string() }), - } -} - -pub(super) fn visit_statement_thing_var(node: Node<'_>) -> Statement { - debug_assert_eq!(node.as_rule(), Rule::statement_thing_var); let span = node.span(); let mut children = node.into_children(); - let var = visit_var(children.consume_expected(Rule::var)); - match children.peek_rule().unwrap() { - Rule::thing_constraint => { - Statement::Thing(Thing::new(span, Head::Variable(var), children.map(visit_thing_constraint).collect())) - } - Rule::value_literal => { - let value = visit_value_literal(children.consume_expected(Rule::value_literal)); - let isa = visit_isa_constraint(children.consume_expected(Rule::isa_constraint)); - debug_assert_eq!(children.try_consume_any(), None); - Statement::AttributeValue(AttributeValueStatement::new(span, var, value, isa)) - } - Rule::expression_struct => { - let value = visit_expression_struct(children.consume_expected(Rule::expression_struct)); - let isa = visit_isa_constraint(children.consume_expected(Rule::isa_constraint)); - debug_assert_eq!(children.try_consume_any(), None); - Statement::AttributeValue(AttributeValueStatement::new(span, var, value, isa)) + let child = children.consume_any(); + match child.as_rule() { + Rule::var => { + let var = visit_var(child); + let constraints = visit_thing_constraint_list(children.consume_expected(Rule::thing_constraint_list)); + Statement::Thing(Thing::new(span, Head::Variable(var), constraints)) } - Rule::comparison => { - let comparison = visit_comparison(children.consume_expected(Rule::comparison)); - let isa = visit_isa_constraint(children.consume_expected(Rule::isa_constraint)); - debug_assert_eq!(children.try_consume_any(), None); - Statement::AttributeComparison(AttributeComparisonStatement::new(span, var, comparison, isa)) + Rule::thing_relation_anonymous => { + let (type_ref_opt, relation) = visit_thing_relation_anonymous(child); + let constraints = if let Some(constraint_list) = children.try_consume_expected(Rule::thing_constraint_list) + { + visit_thing_constraint_list(constraint_list) + } else { + debug_assert_eq!(children.try_consume_any(), None); + vec![] + }; + Statement::Thing(Thing::new(span, Head::Relation(type_ref_opt, relation), constraints)) } - _ => unreachable!("{}", TypeQLError::IllegalGrammar { input: children.to_string() }), + _ => unreachable!("{}", TypeQLError::IllegalGrammar { input: child.to_string() }), } } -pub(super) fn visit_statement_relation_anonymous(node: Node<'_>) -> Statement { - debug_assert_eq!(node.as_rule(), Rule::statement_relation_anonymous); +pub(super) fn visit_thing_relation_anonymous(node: Node<'_>) -> (Option, Relation) { + debug_assert_eq!(node.as_rule(), Rule::thing_relation_anonymous); let span = node.span(); let mut children = node.into_children(); - let head = Head::Relation(visit_relation(children.consume_expected(Rule::relation))); - let constraints = children.map(visit_thing_constraint).collect(); - Statement::Thing(Thing::new(span, head, constraints)) + let type_ = children.try_consume_expected(Rule::type_ref).map(visit_type_ref); + let relation = visit_relation(children.consume_expected(Rule::relation)); + (type_, relation) +} + +fn visit_thing_constraint_list(node: Node<'_>) -> Vec { + debug_assert_eq!(node.as_rule(), Rule::thing_constraint_list); + let children = node.into_children(); + children.map(visit_thing_constraint).collect() } fn visit_thing_constraint(node: Node<'_>) -> Constraint { @@ -93,8 +84,15 @@ fn visit_isa_constraint(node: Node<'_>) -> Isa { let mut children = node.into_children(); let kind = visit_isa_token(children.consume_expected(Rule::ISA_)); let type_ = visit_type_ref(children.consume_expected(Rule::type_ref)); - debug_assert_eq!(children.try_consume_any(), None); - Isa::new(span, kind, type_) + let instance_constraint = children.try_consume_any().map(|child| match child.as_rule() { + Rule::relation => IsaInstanceConstraint::Relation(visit_relation(child)), + Rule::expression => IsaInstanceConstraint::Expression(visit_expression(child)), + Rule::expression_struct => IsaInstanceConstraint::Struct(visit_expression_struct(child)), + Rule::value_literal => IsaInstanceConstraint::Value(visit_value_literal(child)), + Rule::comparison => IsaInstanceConstraint::Comparison(visit_comparison(child)), + _ => unreachable!("{}", TypeQLError::IllegalGrammar { input: child.to_string() }), + }); + Isa::new(span, kind, type_, instance_constraint) } fn visit_isa_token(node: Node<'_>) -> IsaKind { diff --git a/rust/parser/test/builtin_functions.rs b/rust/parser/test/builtin_functions.rs index 57d05669d..03ae8ae4a 100644 --- a/rust/parser/test/builtin_functions.rs +++ b/rust/parser/test/builtin_functions.rs @@ -12,9 +12,9 @@ fn test_function_min() { let query = r#"match $x isa commodity, has price $p; -(commodity: $x, qty: $q) isa order; -$net = $p * $q; -$gross = min($net * 1.21, $net + 100.0);"#; +$oder isa order (commodity: $x, qty: $q); +let $net = $p * $q; +let $gross = min($net * 1.21, $net + 100.0);"#; let parsed = parse_query(query).unwrap(); // let expected = typeql_match!( // var("x").isa("commodity").has(("price", cvar("p"))), @@ -30,9 +30,9 @@ fn test_function_max() { let query = r#"match $x isa commodity, has price $p; -(commodity: $x, qty: $q) isa order; -$net = $p * $q; -$gross = max($net * 1.21, $net + 100.0);"#; +$order isa order (commodity: $x, qty: $q); +let $net = $p * $q; +let $gross = max($net * 1.21, $net + 100.0);"#; let parsed = parse_query(query).unwrap(); // let expected = typeql_match!( // var("x").isa("commodity").has(("price", cvar("p"))), @@ -48,9 +48,9 @@ fn test_function_abs() { let query = r#"match $x isa commodity, has price $p; -(commodity: $x, qty: $q) isa order; -$net = $p * $q; -$value = abs($net * 1.21);"#; +$order isa order (commodity: $x, qty: $q); +let $net = $p * $q; +let $value = abs($net * 1.21);"#; let parsed = parse_query(query).unwrap(); // let expected = typeql_match!( // var("x").isa("commodity").has(("price", cvar("p"))), @@ -67,8 +67,8 @@ fn test_function_ceil() { $x isa commodity, has price $p; (commodity: $x, qty: $q) isa order; -$net = $p * $q; -$value = ceil($net * 1.21);"#; +let $net = $p * $q; +let $value = ceil($net * 1.21);"#; let parsed = parse_query(query).unwrap(); // let expected = typeql_match!( // var("x").isa("commodity").has(("price", cvar("p"))), @@ -84,9 +84,9 @@ fn test_function_floor() { let query = r#"match $x isa commodity, has price $p; -(commodity: $x, qty: $q) isa order; -$net = $p * $q; -$value = floor($net * 1.21);"#; +$order isa order (commodity: $x, qty: $q); +let $net = $p * $q; +let $value = floor($net * 1.21);"#; let parsed = parse_query(query).unwrap(); // let expected = typeql_match!( // var("x").isa("commodity").has(("price", cvar("p"))), @@ -102,9 +102,9 @@ fn test_function_round() { let query = r#"match $x isa commodity, has price $p; -(commodity: $x, qty: $q) isa order; -$net = $p * $q; -$value = round($net * 1.21);"#; +$order isa order (commodity: $x, qty: $q); +let $net = $p * $q; +let $value = round($net * 1.21);"#; let parsed = parse_query(query).unwrap(); // let expected = typeql_match!( // var("x").isa("commodity").has(("price", cvar("p"))), diff --git a/rust/parser/test/disjunctions.rs b/rust/parser/test/disjunctions.rs index f8fefd644..4f41a4f12 100644 --- a/rust/parser/test/disjunctions.rs +++ b/rust/parser/test/disjunctions.rs @@ -12,7 +12,7 @@ fn test_or_query() { let query = r#"match $x isa movie; { - $y == "drama" isa genre; + $y isa genre == "drama"; ($x, $y); } or { $x == "The Muppets"; diff --git a/rust/parser/test/match_queries.rs b/rust/parser/test/match_queries.rs index 18b9dca92..741117e0a 100644 --- a/rust/parser/test/match_queries.rs +++ b/rust/parser/test/match_queries.rs @@ -42,7 +42,7 @@ $x isa person, #[test] fn test_relation_query() { let query = r#"match -$brando "Marl B" isa name; +$brando isa name "Marl B"; (actor: $brando, $char, production-with-cast: $prod); select $char, $prod;"#; @@ -56,6 +56,16 @@ select $char, $prod;"#; assert_valid_eq_repr!(expected, parsed, query); } +#[test] +fn test_labelled_relation() { + let query = r#"match +$brando isa name "Marl B"; +casting (actor: $brando, $char, production-with-cast: $prod); +select $char, $prod;"#; + let parsed = parse_query(query).unwrap(); + assert_valid_eq_repr!(expected, parsed, query); +} + #[test] fn test_role_type_scoped_globally() { let query = r#"match @@ -155,7 +165,7 @@ fn test_predicate_query_4() { let query = r#"match $x has age $y; $y >= $z; -$z 18 isa age;"#; +$z isa age 18;"#; let parsed = parse_query(query).unwrap(); // let expected = (); @@ -353,7 +363,7 @@ $x has release-date 1000-11-12T13:14:15.0001234567;"#; } #[test] -fn test_parsing_long_predicate_query() { +fn test_parsing_integer_predicate_query() { let query = r#"match $x isa movie, has tmdb-vote-count <= 400;"#; @@ -367,8 +377,8 @@ $x isa movie, #[test] fn test_parsing_attribute_query_by_value_variable() { let query = r#"match -$x = 5; -$a == $x isa age;"#; +let $x = 5; +$a isa age == $x;"#; let parsed = parse_query(query).unwrap(); // let expected = match_!(var("x").assign(5), var("a").equals(var("x")).isa("age")); @@ -379,7 +389,7 @@ $a == $x isa age;"#; #[test] fn test_parsing_precedence_operators() { let query = r#"match -$res = $a / $b * $c + $d ^ $e ^ $f / $g;"#; +let $res = $a / $b * $c + $d ^ $e ^ $f / $g;"#; let parsed = parse_query(query).unwrap(); // let expected = match_!(var("res").assign( @@ -391,7 +401,7 @@ $res = $a / $b * $c + $d ^ $e ^ $f / $g;"#; #[test] fn test_parsing_precedence_function_and_parentheses() { let query = r#"match -$res = $a + (round($b + $c) + $d) * $e;"#; +let $res = $a + (round($b + $c) + $d) * $e;"#; let parsed = parse_query(query).unwrap(); // let expected = diff --git a/rust/parser/test/mod.rs b/rust/parser/test/mod.rs index eb57498fe..e1b1066a6 100644 --- a/rust/parser/test/mod.rs +++ b/rust/parser/test/mod.rs @@ -22,6 +22,7 @@ mod modifiers; mod nonquery; mod regex; mod schema_queries; +mod sugar; mod write_queries; macro_rules! assert_valid_eq_repr { @@ -65,12 +66,12 @@ fn tmp() { // limit 10; // return { $name, $age, $dob }; - // fun test_single_1($x: person) -> long: + // fun test_single_1($x: person) -> integer: // match // $x isa person; // return count($x); - // fun test_single_many($x: person) -> long, long: + // fun test_single_many($x: person) -> integer, integer: // match // $x isa person, has age $a; // return count($x), sum($a); @@ -82,7 +83,7 @@ fn tmp() { // $y in get_all_dob($x); // return { $x, $age, $y }; - // fun test_single_optional($x: person) -> name?, long, double?: + // fun test_single_optional($x: person) -> name?, integer, double?: // match // $x isa person, has age $age; // try { $one_name = get_a_name($x); }; @@ -104,7 +105,7 @@ fn tmp() { // $x = 10 + 11; // person sub attribute @abstract, - // value long @values(1,2,3); + // value integer @values(1,2,3); // $person sub attribute @abstract; // $person sub $parent, value string @regex("abc"); diff --git a/rust/parser/test/modifiers.rs b/rust/parser/test/modifiers.rs index 4689dbf74..589a3bca5 100644 --- a/rust/parser/test/modifiers.rs +++ b/rust/parser/test/modifiers.rs @@ -23,7 +23,7 @@ fn test_get_sort_on_value_variable() { let query = r#"match $x isa movie, has rating $r; -$l = 100 - $r; +let $l = 100 - $r; sort $l desc;"#; let parsed = parse_query(query).unwrap(); // let expected = typeql_match!( @@ -41,7 +41,7 @@ fn test_get_sort_multiple() { $x isa movie, has title $t, has rating $r; -$rate = $r * 100; +let $rate = $r * 100; sort $rate desc, $t;"#; let parsed = parse_query(query).unwrap(); // let expected = typeql_match!( diff --git a/rust/parser/test/schema_queries.rs b/rust/parser/test/schema_queries.rs index f36d06aca..6939580ef 100644 --- a/rust/parser/test/schema_queries.rs +++ b/rust/parser/test/schema_queries.rs @@ -116,9 +116,9 @@ entity abstract-type @abstract;"#; #[test] fn test_define_value_type_query() { let query = r#"define -attribute my-type value long;"#; +attribute my-type value integer;"#; let parsed = parse_query(query).unwrap(); - // let expected = define!(type_("my-type").sub("attribute").value(ValueType::Long)); + // let expected = define!(type_("my-type").sub("attribute").value(ValueType::Integer)); assert_valid_eq_repr!(expected, parsed, query); } diff --git a/rust/parser/test/sugar.rs b/rust/parser/test/sugar.rs new file mode 100644 index 000000000..afb4f19b5 --- /dev/null +++ b/rust/parser/test/sugar.rs @@ -0,0 +1,73 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +use crate::{parse_query, parser::test::assert_valid_eq_repr}; + +#[test] +fn match_anonymous_relation() { + let query = r#"match +marriage (husband: $a, wife: $b);"#; + let parsed = parse_query(query).unwrap(); + assert_valid_eq_repr!(expected, parsed, query); +} + +#[test] +fn match_anonymous_untyped_relation() { + let query = r#"match +(husband: $a, wife: $b);"#; + let parsed = parse_query(query).unwrap(); + assert_valid_eq_repr!(expected, parsed, query); +} + +#[test] +fn match_anonymous_untyped_relation_no_roles() { + let query = r#"match +($a, $b);"#; + let parsed = parse_query(query).unwrap(); + assert_valid_eq_repr!(expected, parsed, query); +} +// +// #[test] +// fn match_anonymous_attribute() { +// let query = r#" +// match name "Alice"; +// "#; +// let parsed = parse_query(query).unwrap(); +// assert_valid_eq_repr!(expected, parsed, query); +// } +// +// // Insert +// #[test] +// fn insert_anonymous_entity() { +// let query = r#"insert +// person;"#; +// let parsed = parse_query(query).unwrap(); +// assert_valid_eq_repr!(expected, parsed, query); +// } +// +// #[test] +// fn insert_anonymous_attribute() { +// let query = r#"insert +// name "Alice";"#; +// let parsed = parse_query(query).unwrap(); +// assert_valid_eq_repr!(expected, parsed, query); +// } + +#[test] +fn insert_anonymous_relation() { + let query = r#"insert +marriage ($a, $b);"#; + let parsed = parse_query(query).unwrap(); + assert_valid_eq_repr!(expected, parsed, query); +} + +#[test] +fn insert_anonymous_untyped_relation() { + let query = r#"insert +(role1: $a, role2: $b);"#; + let parsed = parse_query(query).unwrap(); + assert_valid_eq_repr!(expected, parsed, query); +} diff --git a/rust/parser/type_.rs b/rust/parser/type_.rs index baa1c7d11..59df7f5ae 100644 --- a/rust/parser/type_.rs +++ b/rust/parser/type_.rs @@ -135,7 +135,7 @@ pub(super) fn visit_value_type_primitive(node: Node<'_>) -> BuiltinValueType { Rule::DECIMAL => token::ValueType::Decimal, Rule::DOUBLE => token::ValueType::Double, Rule::DURATION => token::ValueType::Duration, - Rule::LONG => token::ValueType::Long, + Rule::INTEGER => token::ValueType::Integer, Rule::STRING => token::ValueType::String, _ => unreachable!("{}", TypeQLError::IllegalGrammar { input: child.to_string() }), }; diff --git a/rust/parser/typeql.pest b/rust/parser/typeql.pest index 5d83cc9ef..2c0b5d9e6 100644 --- a/rust/parser/typeql.pest +++ b/rust/parser/typeql.pest @@ -69,7 +69,7 @@ pattern_try = { TRY ~ CURLY_OPEN ~ patterns ~ CURLY_CLOSE } // STATEMENTS ================================================================== -statement = { statement_type | statement_thing_var | statement_single | statement_relation_anonymous } +statement = { statement_single | statement_type | statement_thing } // TYPE STATEMENTS ============================================================= @@ -93,20 +93,14 @@ relates_constraint = { RELATES ~ type_ref_list plays_constraint = { PLAYS ~ type_ref } // THING STATEMENTS ============================================================ - -statement_thing = { statement_thing_var | statement_relation_anonymous } -statement_relation_anonymous = { relation ~ thing_constraint? ~ ( COMMA ~ thing_constraint )* ~ COMMA? } - -statement_thing_var = { var ~ COMMA? ~ thing_constraint ~ ( COMMA ~ thing_constraint )* ~ COMMA? - | var ~ ( value_literal | expression_struct ) ~ isa_constraint - // TODO: need to allow $x $name_value isa name; - // option: $x isa name($value), extend to literals as well - | var ~ comparison ~ isa_constraint - } +statement_thing = { var ~ COMMA? ~ thing_constraint_list + | thing_relation_anonymous ~ (COMMA? ~ thing_constraint_list)? + } +thing_relation_anonymous = { (!reserved ~ type_ref?) ~ relation } +thing_constraint_list = {thing_constraint ~ (COMMA ~ thing_constraint)* ~ COMMA?} thing_constraint = { isa_constraint | iid_constraint | has_constraint | links_constraint } - -isa_constraint = { ISA_ ~ type_ref } +isa_constraint = { ISA_ ~ type_ref ~ (relation | value_literal | expression | expression_struct | comparison)? } iid_constraint = { IID ~ iid_value } has_constraint = { HAS ~ type_ref_list ~ ( comparison | expression_list | var ) | HAS ~ type_ref ~ ( comparison | expression_value | var ) @@ -131,9 +125,9 @@ statement_single = { statement_is | statement_comparison | statement_assignment statement_is = { var ~ IS ~ var } statement_comparison = { expression_value ~ comparison } -statement_assignment = { assignment_left ~ ASSIGN ~ expression } +statement_assignment = { LET ~ assignment_left ~ ASSIGN ~ expression } assignment_left = { vars_assignment | struct_destructor } -statement_in = { vars_assignment ~ IN ~ ( expression_function | expression_list ) } +statement_in = { LET ~ vars_assignment ~ IN ~ ( expression_function | expression_list ) } vars_assignment = { var_assignment ~ ( COMMA ~ var_assignment )* ~ COMMA? } var_assignment = { var_optional | var } @@ -320,7 +314,7 @@ value_type = { value_type_primitive | label } value_type_optional = { value_type ~ QUESTION } value_type_list = { value_type ~ SQ_BRACKET_OPEN ~ SQ_BRACKET_CLOSE } -value_type_primitive = { BOOLEAN | LONG | DOUBLE | DECIMAL +value_type_primitive = { BOOLEAN | INTEGER | DOUBLE | DECIMAL | DATETIME_TZ | DATETIME | DATE | DURATION | STRING } @@ -381,7 +375,7 @@ unreserved = { ABS | CEIL | FLOOR | ROUND | LENGTH | CHECK | FIRST | COUNT | MAX | MIN | MEAN | MEDIAN | STD | SUM | LIST | VALUE | SELECT | SORT | LIMIT | OFFSET | GROUP | LIKE | CONTAINS - | BOOLEAN | LONG | DOUBLE | DECIMAL | DATETIME_TZ | DATETIME | DATE | DURATION | STRING + | BOOLEAN | INTEGER | DOUBLE | DECIMAL | DATETIME_TZ | DATETIME | DATE | DURATION | STRING } // QUERY COMMAND KEYWORDS @@ -502,6 +496,7 @@ CONTAINS = @{ "contains" ~ WB } // ASSIGNMENT AND EXPRESSION KEYWORDS +LET = @{ "let" } ASSIGN = @{ "=" } IN = @{ "in" ~ WB } @@ -535,7 +530,7 @@ LIST = @{ "list" ~ WB } // VALUE TYPE KEYWORDS BOOLEAN = @{ "boolean" ~ WB } -LONG = @{ "long" ~ WB } +INTEGER = @{ "integer" ~ WB } DOUBLE = @{ "double" ~ WB } DECIMAL = @{ "decimal" ~ WB } diff --git a/rust/statement/mod.rs b/rust/statement/mod.rs index 4968d7c38..9978f1dd7 100644 --- a/rust/statement/mod.rs +++ b/rust/statement/mod.rs @@ -6,10 +6,7 @@ use std::{collections::HashMap, fmt}; -use self::{ - comparison::ComparisonStatement, - thing::{AttributeComparisonStatement, AttributeValueStatement}, -}; +use self::comparison::ComparisonStatement; pub use self::{thing::Thing, type_::Type}; use crate::{ common::{identifier::Identifier, token, Span}, @@ -154,7 +151,7 @@ impl Pretty for Assignment {} impl fmt::Display for Assignment { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{} = {}", self.lhs, self.rhs) + write!(f, "let {} = {}", self.lhs, self.rhs) } } @@ -165,8 +162,6 @@ pub enum Statement { Comparison(ComparisonStatement), Assignment(Assignment), Thing(Thing), - AttributeValue(AttributeValueStatement), - AttributeComparison(AttributeComparisonStatement), Type(Type), } @@ -178,8 +173,6 @@ impl Pretty for Statement { Statement::Comparison(inner) => Pretty::fmt(inner, indent_level, f), Statement::Assignment(inner) => Pretty::fmt(inner, indent_level, f), Statement::Thing(inner) => Pretty::fmt(inner, indent_level, f), - Statement::AttributeValue(inner) => Pretty::fmt(inner, indent_level, f), - Statement::AttributeComparison(inner) => Pretty::fmt(inner, indent_level, f), Statement::Type(inner) => Pretty::fmt(inner, indent_level, f), } } @@ -193,8 +186,6 @@ impl fmt::Display for Statement { Statement::Comparison(inner) => fmt::Display::fmt(inner, f), Statement::Assignment(inner) => fmt::Display::fmt(inner, f), Statement::Thing(inner) => fmt::Display::fmt(inner, f), - Statement::AttributeValue(inner) => fmt::Display::fmt(inner, f), - Statement::AttributeComparison(inner) => fmt::Display::fmt(inner, f), Statement::Type(inner) => fmt::Display::fmt(inner, f), } } diff --git a/rust/statement/thing/isa.rs b/rust/statement/thing/isa.rs index 2fb1798cb..3dd31fca8 100644 --- a/rust/statement/thing/isa.rs +++ b/rust/statement/thing/isa.rs @@ -9,7 +9,10 @@ use std::fmt; use crate::{ common::{token, Span}, pretty::Pretty, + statement::{comparison::Comparison, thing::Relation}, type_::TypeRef, + value::ValueLiteral, + Expression, Literal, }; #[derive(Clone, Debug, Eq, PartialEq)] @@ -17,11 +20,12 @@ pub struct Isa { span: Option, pub kind: IsaKind, pub type_: TypeRef, + pub constraint: Option, } impl Isa { - pub fn new(span: Option, kind: IsaKind, type_: TypeRef) -> Self { - Self { span, kind, type_ } + pub fn new(span: Option, kind: IsaKind, type_: TypeRef, constraint: Option) -> Self { + Self { span, kind, type_, constraint } } } @@ -29,7 +33,11 @@ impl Pretty for Isa {} impl fmt::Display for Isa { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{} {}", self.kind, self.type_) + if let Some(constraint) = &self.constraint { + write!(f, "{} {} {}", self.kind, self.type_, constraint) + } else { + write!(f, "{} {}", self.kind, self.type_) + } } } @@ -50,3 +58,26 @@ impl fmt::Display for IsaKind { write!(f, "{}", token) } } + +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum IsaInstanceConstraint { + Relation(Relation), + Value(Literal), + Expression(Expression), + Comparison(Comparison), + Struct(Literal), +} + +impl Pretty for IsaInstanceConstraint {} + +impl fmt::Display for IsaInstanceConstraint { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Relation(relation) => write!(f, "{}", relation), + Self::Value(value) => write!(f, "{}", value), + Self::Expression(expr) => write!(f, "{}", expr), + Self::Comparison(cmp) => write!(f, "{}", cmp), + Self::Struct(value) => write!(f, "{}", value), + } + } +} diff --git a/rust/statement/thing/mod.rs b/rust/statement/thing/mod.rs index d4c9ed516..2f54f94e7 100644 --- a/rust/statement/thing/mod.rs +++ b/rust/statement/thing/mod.rs @@ -16,6 +16,7 @@ use crate::{ util::write_joined, value::Literal, variable::Variable, + TypeRef, }; pub mod isa; @@ -71,14 +72,15 @@ impl fmt::Display for Thing { #[derive(Debug, Clone, Eq, PartialEq)] pub enum Head { Variable(Variable), - Relation(Relation), + Relation(Option, Relation), } impl Pretty for Head { fn fmt(&self, indent_level: usize, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::Variable(inner) => Pretty::fmt(inner, indent_level, f), - Self::Relation(inner) => Pretty::fmt(inner, indent_level, f), + Self::Relation(Some(type_ref), relation) => write!(f, "{} {}", type_ref, relation), + Self::Relation(None, relation) => Pretty::fmt(relation, indent_level, f), } } } @@ -87,7 +89,8 @@ impl fmt::Display for Head { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::Variable(inner) => fmt::Display::fmt(inner, f), - Self::Relation(inner) => fmt::Display::fmt(inner, f), + Self::Relation(Some(type_ref), relation) => write!(f, "{} {}", type_ref, relation), + Self::Relation(None, inner) => fmt::Display::fmt(inner, f), } } } @@ -132,52 +135,6 @@ impl fmt::Display for RolePlayer { } } -#[derive(Debug, Clone, Eq, PartialEq)] -pub struct AttributeValueStatement { - span: Option, - pub var: Variable, - pub value: Literal, - pub isa: Isa, -} - -impl AttributeValueStatement { - pub fn new(span: Option, var: Variable, value: Literal, isa: Isa) -> Self { - Self { span, var, value, isa } - } -} - -impl Pretty for AttributeValueStatement {} - -impl fmt::Display for AttributeValueStatement { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{} ", self.var)?; - write!(f, "{} {}", self.value, self.isa)?; - Ok(()) - } -} - -#[derive(Debug, Clone, Eq, PartialEq)] -pub struct AttributeComparisonStatement { - span: Option, - pub var: Variable, - pub comparison: comparison::Comparison, - pub isa: Isa, -} - -impl AttributeComparisonStatement { - pub fn new(span: Option, var: Variable, comparison: comparison::Comparison, isa: Isa) -> Self { - Self { span, var, comparison, isa } - } -} - -impl Pretty for AttributeComparisonStatement {} - -impl fmt::Display for AttributeComparisonStatement { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{} {} {}", self.var, self.comparison, self.isa) - } -} - #[derive(Debug, Clone, Eq, PartialEq)] pub enum Constraint { Isa(Isa),