implemented imperative script
parent
e795a2cb9a
commit
8c8840957a
@ -0,0 +1,224 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2023, The Cozo Project Authors.
|
||||||
|
*
|
||||||
|
* 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::parse_query;
|
||||||
|
use crate::parse::{ExtractSpan, ImperativeProgram, ImperativeStmt, Pair, Pairs, Rule, SourceSpan};
|
||||||
|
use crate::{DataValue, FixedRule, ValidityTs};
|
||||||
|
use either::{Left, Right};
|
||||||
|
use itertools::Itertools;
|
||||||
|
use miette::{Diagnostic, Result};
|
||||||
|
use smartstring::SmartString;
|
||||||
|
use std::collections::BTreeMap;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
|
pub(crate) fn parse_imperative(
|
||||||
|
src: Pairs<'_>,
|
||||||
|
param_pool: &BTreeMap<String, DataValue>,
|
||||||
|
fixed_rules: &BTreeMap<String, Arc<Box<dyn FixedRule>>>,
|
||||||
|
cur_vld: ValidityTs,
|
||||||
|
) -> Result<ImperativeProgram> {
|
||||||
|
let mut collected = vec![];
|
||||||
|
|
||||||
|
for pair in src {
|
||||||
|
if pair.as_rule() != Rule::EOI {
|
||||||
|
collected.push(parse_imperative_stmt(
|
||||||
|
pair,
|
||||||
|
param_pool,
|
||||||
|
fixed_rules,
|
||||||
|
cur_vld,
|
||||||
|
)?);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(collected)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Error, Diagnostic)]
|
||||||
|
#[error("cannot manipulate permanent relation in imperative script")]
|
||||||
|
#[diagnostic(code(parser::manipulate_perm_rel_in_script))]
|
||||||
|
struct CannotManipulatePermRel(#[label] SourceSpan);
|
||||||
|
|
||||||
|
#[derive(Debug, Error, Diagnostic)]
|
||||||
|
#[error("duplicate marker found")]
|
||||||
|
#[diagnostic(code(parser::dup_marker))]
|
||||||
|
struct DuplicateMarker(#[label] SourceSpan);
|
||||||
|
|
||||||
|
fn parse_imperative_stmt(
|
||||||
|
pair: Pair<'_>,
|
||||||
|
param_pool: &BTreeMap<String, DataValue>,
|
||||||
|
fixed_rules: &BTreeMap<String, Arc<Box<dyn FixedRule>>>,
|
||||||
|
cur_vld: ValidityTs,
|
||||||
|
) -> Result<ImperativeStmt> {
|
||||||
|
Ok(match pair.as_rule() {
|
||||||
|
Rule::break_stmt => {
|
||||||
|
let span = pair.extract_span();
|
||||||
|
let target = pair
|
||||||
|
.into_inner()
|
||||||
|
.next()
|
||||||
|
.map(|p| SmartString::from(p.as_str()));
|
||||||
|
ImperativeStmt::Break { target, span }
|
||||||
|
}
|
||||||
|
Rule::continue_stmt => {
|
||||||
|
let span = pair.extract_span();
|
||||||
|
let target = pair
|
||||||
|
.into_inner()
|
||||||
|
.next()
|
||||||
|
.map(|p| SmartString::from(p.as_str()));
|
||||||
|
ImperativeStmt::Continue { target, span }
|
||||||
|
}
|
||||||
|
Rule::return_stmt => {
|
||||||
|
// let span = pair.extract_span();
|
||||||
|
match pair.into_inner().next() {
|
||||||
|
None => ImperativeStmt::ReturnNil,
|
||||||
|
Some(p) => match p.as_rule() {
|
||||||
|
Rule::ident => {
|
||||||
|
let rel = SmartString::from(p.as_str());
|
||||||
|
ImperativeStmt::ReturnTemp { rel }
|
||||||
|
}
|
||||||
|
Rule::query_script_inner => {
|
||||||
|
let prog = parse_query(p.into_inner(), param_pool, fixed_rules, cur_vld)?;
|
||||||
|
ImperativeStmt::ReturnProgram { prog }
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Rule::if_chain => {
|
||||||
|
let span = pair.extract_span();
|
||||||
|
let mut inner = pair.into_inner();
|
||||||
|
let condition = inner.next().unwrap();
|
||||||
|
let cond = match condition.as_rule() {
|
||||||
|
Rule::ident => Left(SmartString::from(condition.as_str())),
|
||||||
|
Rule::query_script_inner => Right(parse_query(
|
||||||
|
condition.into_inner(),
|
||||||
|
param_pool,
|
||||||
|
fixed_rules,
|
||||||
|
cur_vld,
|
||||||
|
)?),
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
let body = inner
|
||||||
|
.next()
|
||||||
|
.unwrap()
|
||||||
|
.into_inner()
|
||||||
|
.map(|p| parse_imperative_stmt(p, param_pool, fixed_rules, cur_vld))
|
||||||
|
.try_collect()?;
|
||||||
|
let else_body = match inner.next() {
|
||||||
|
None => vec![],
|
||||||
|
Some(rest) => rest
|
||||||
|
.into_inner()
|
||||||
|
.map(|p| parse_imperative_stmt(p, param_pool, fixed_rules, cur_vld))
|
||||||
|
.try_collect()?,
|
||||||
|
};
|
||||||
|
ImperativeStmt::If {
|
||||||
|
condition: cond,
|
||||||
|
then_branch: body,
|
||||||
|
else_branch: else_body,
|
||||||
|
span,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Rule::while_block => {
|
||||||
|
let span = pair.extract_span();
|
||||||
|
let mut inner = pair.into_inner();
|
||||||
|
let mut mark = None;
|
||||||
|
let mut nxt = inner.next().unwrap();
|
||||||
|
if nxt.as_rule() == Rule::ident {
|
||||||
|
mark = Some(SmartString::from(nxt.as_str()));
|
||||||
|
nxt = inner.next().unwrap();
|
||||||
|
}
|
||||||
|
let cond = match nxt.as_rule() {
|
||||||
|
Rule::ident => Left(SmartString::from(nxt.as_str())),
|
||||||
|
Rule::query_script_inner => Right(parse_query(
|
||||||
|
nxt.into_inner(),
|
||||||
|
param_pool,
|
||||||
|
fixed_rules,
|
||||||
|
cur_vld,
|
||||||
|
)?),
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
let body = parse_imperative(
|
||||||
|
inner.next().unwrap().into_inner(),
|
||||||
|
param_pool,
|
||||||
|
fixed_rules,
|
||||||
|
cur_vld,
|
||||||
|
)?;
|
||||||
|
ImperativeStmt::While {
|
||||||
|
label: mark,
|
||||||
|
condition: cond,
|
||||||
|
body,
|
||||||
|
span,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Rule::do_while_block => {
|
||||||
|
let span = pair.extract_span();
|
||||||
|
let mut inner = pair.into_inner();
|
||||||
|
let mut mark = None;
|
||||||
|
let mut nxt = inner.next().unwrap();
|
||||||
|
if nxt.as_rule() == Rule::ident {
|
||||||
|
mark = Some(SmartString::from(nxt.as_str()));
|
||||||
|
nxt = inner.next().unwrap();
|
||||||
|
}
|
||||||
|
let body = parse_imperative(
|
||||||
|
inner.next().unwrap().into_inner(),
|
||||||
|
param_pool,
|
||||||
|
fixed_rules,
|
||||||
|
cur_vld,
|
||||||
|
)?;
|
||||||
|
let cond = match nxt.as_rule() {
|
||||||
|
Rule::ident => Left(SmartString::from(nxt.as_str())),
|
||||||
|
Rule::query_script_inner => Right(parse_query(
|
||||||
|
nxt.into_inner(),
|
||||||
|
param_pool,
|
||||||
|
fixed_rules,
|
||||||
|
cur_vld,
|
||||||
|
)?),
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
ImperativeStmt::DoWhile {
|
||||||
|
label: mark,
|
||||||
|
body,
|
||||||
|
condition: cond,
|
||||||
|
span,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Rule::temp_swap => {
|
||||||
|
// let span = pair.extract_span();
|
||||||
|
let mut pairs = pair.into_inner();
|
||||||
|
let left = pairs.next().unwrap();
|
||||||
|
let left_name = left.as_str();
|
||||||
|
let right = pairs.next().unwrap();
|
||||||
|
let right_name = right.as_str();
|
||||||
|
|
||||||
|
ImperativeStmt::TempSwap {
|
||||||
|
left: SmartString::from(left_name),
|
||||||
|
right: SmartString::from(right_name),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Rule::remove_stmt => {
|
||||||
|
// let span = pair.extract_span();
|
||||||
|
let name_p = pair.into_inner().next().unwrap();
|
||||||
|
let name = name_p.as_str();
|
||||||
|
|
||||||
|
ImperativeStmt::TempRemove {
|
||||||
|
temp: SmartString::from(name),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Rule::query_script_inner => {
|
||||||
|
let prog = parse_query(pair.into_inner(), param_pool, fixed_rules, cur_vld)?;
|
||||||
|
ImperativeStmt::Program { prog }
|
||||||
|
}
|
||||||
|
Rule::ignore_error_script => {
|
||||||
|
let pair = pair.into_inner().next().unwrap();
|
||||||
|
let prog = parse_query(pair.into_inner(), param_pool, fixed_rules, cur_vld)?;
|
||||||
|
ImperativeStmt::IgnoreErrorProgram { prog }
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
})
|
||||||
|
}
|
Loading…
Reference in New Issue